mirror of
https://github.com/microsoft/PowerToys.git
synced 2026-01-02 10:26:22 +01:00
Compare commits
32 Commits
dev/crutka
...
dev/vanzue
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
310186c44c | ||
|
|
6d303af726 | ||
|
|
84296b0d89 | ||
|
|
7417b857e8 | ||
|
|
4f3f7d649f | ||
|
|
96c5cf1897 | ||
|
|
a1cf836c6d | ||
|
|
c1e49ba915 | ||
|
|
309582795c | ||
|
|
2aad949c9e | ||
|
|
bf9217ec24 | ||
|
|
78b29c5b66 | ||
|
|
dd2e7d17f9 | ||
|
|
df8ace3ab6 | ||
|
|
88e4ba670c | ||
|
|
79958975b4 | ||
|
|
ddbb6161e3 | ||
|
|
78c7c8e88f | ||
|
|
693ab67831 | ||
|
|
c6a4ee1441 | ||
|
|
89c33fae68 | ||
|
|
c9922302e5 | ||
|
|
498ef676f4 | ||
|
|
3821e8427c | ||
|
|
964e5c9d5e | ||
|
|
48d9d19df1 | ||
|
|
d21b7fac7b | ||
|
|
02a9269435 | ||
|
|
f642720087 | ||
|
|
53b989857b | ||
|
|
718e725571 | ||
|
|
a804bf86a4 |
@@ -2,14 +2,14 @@
|
||||
# Reference: https://github.com/microsoft/PowerToys/blob/main/doc/devdocs/readme.md#compiling-powertoys
|
||||
properties:
|
||||
resources:
|
||||
- resource: Microsoft.Windows.Developer/DeveloperMode
|
||||
- resource: Microsoft.Windows.Settings/WindowsSettings
|
||||
directives:
|
||||
description: Enable Developer Mode
|
||||
allowPrerelease: true
|
||||
# Requires elevation for the set operation
|
||||
securityContext: elevated
|
||||
settings:
|
||||
Ensure: Present
|
||||
DeveloperMode: true
|
||||
- resource: Microsoft.WinGet.DSC/WinGetPackage
|
||||
id: vsPackage
|
||||
directives:
|
||||
|
||||
@@ -2,14 +2,14 @@
|
||||
# Reference: https://github.com/microsoft/PowerToys/blob/main/doc/devdocs/readme.md#compiling-powertoys
|
||||
properties:
|
||||
resources:
|
||||
- resource: Microsoft.Windows.Developer/DeveloperMode
|
||||
- resource: Microsoft.Windows.Settings/WindowsSettings
|
||||
directives:
|
||||
description: Enable Developer Mode
|
||||
allowPrerelease: true
|
||||
# Requires elevation for the set operation
|
||||
securityContext: elevated
|
||||
settings:
|
||||
Ensure: Present
|
||||
DeveloperMode: true
|
||||
- resource: Microsoft.WinGet.DSC/WinGetPackage
|
||||
id: vsPackage
|
||||
directives:
|
||||
|
||||
@@ -2,14 +2,14 @@
|
||||
# Reference: https://github.com/microsoft/PowerToys/blob/main/doc/devdocs/readme.md#compiling-powertoys
|
||||
properties:
|
||||
resources:
|
||||
- resource: Microsoft.Windows.Developer/DeveloperMode
|
||||
- resource: Microsoft.Windows.Settings/WindowsSettings
|
||||
directives:
|
||||
description: Enable Developer Mode
|
||||
allowPrerelease: true
|
||||
# Requires elevation for the set operation
|
||||
securityContext: elevated
|
||||
settings:
|
||||
Ensure: Present
|
||||
DeveloperMode: true
|
||||
- resource: Microsoft.WinGet.DSC/WinGetPackage
|
||||
id: vsPackage
|
||||
directives:
|
||||
|
||||
15
.github/actions/spell-check/allow/names.txt
vendored
15
.github/actions/spell-check/allow/names.txt
vendored
@@ -46,8 +46,8 @@ betsegaw
|
||||
bricelam
|
||||
bsky
|
||||
CCcat
|
||||
chenmy
|
||||
chemwolf
|
||||
chenmy
|
||||
Chinh
|
||||
chrdavis
|
||||
Chrzan
|
||||
@@ -65,8 +65,8 @@ Deondre
|
||||
DHowett
|
||||
ductdo
|
||||
Essey
|
||||
Feng
|
||||
ethanfangg
|
||||
Feng
|
||||
ferraridavide
|
||||
foxmsft
|
||||
frankychen
|
||||
@@ -77,6 +77,7 @@ Galaxi
|
||||
Garside
|
||||
Gershaft
|
||||
Giordani
|
||||
Gleb
|
||||
Gokce
|
||||
gordon
|
||||
Griese
|
||||
@@ -95,6 +96,7 @@ Huynh
|
||||
Ionut
|
||||
jamrobot
|
||||
Jaswal
|
||||
Jaylyn
|
||||
jefflord
|
||||
Jordi
|
||||
jyuwono
|
||||
@@ -105,6 +107,7 @@ Kantarci
|
||||
Karthick
|
||||
kaylacinnamon
|
||||
kevinguo
|
||||
Khmyznikov
|
||||
Krigun
|
||||
Lambson
|
||||
Laute
|
||||
@@ -127,6 +130,8 @@ Naro
|
||||
nathancartlidge
|
||||
Nemeth
|
||||
nielslaute
|
||||
Noraa
|
||||
noraajunker
|
||||
oldnewthing
|
||||
onegreatworld
|
||||
palenshus
|
||||
@@ -146,11 +151,13 @@ ricardosantos
|
||||
riri
|
||||
ritchielawrence
|
||||
robmikh
|
||||
ruslanlap
|
||||
Russinovich
|
||||
Rutkas
|
||||
ryanbodrug
|
||||
saahmedm
|
||||
sachaple
|
||||
Sameerjs
|
||||
Santossio
|
||||
Schoen
|
||||
Sekan
|
||||
@@ -169,6 +176,7 @@ TBM
|
||||
tilovell
|
||||
Triet
|
||||
urnotdfs
|
||||
vednig
|
||||
waaverecords
|
||||
wang
|
||||
Whuihuan
|
||||
@@ -187,9 +195,6 @@ zhaopy
|
||||
zhaoqpcn
|
||||
Zoltan
|
||||
Zykova
|
||||
Sameerjs
|
||||
ruslanlap
|
||||
vednig
|
||||
|
||||
# OTHERS
|
||||
|
||||
|
||||
16
.github/actions/spell-check/expect.txt
vendored
16
.github/actions/spell-check/expect.txt
vendored
@@ -14,6 +14,7 @@ AColumn
|
||||
acrt
|
||||
ACTIVATEAPP
|
||||
activationaction
|
||||
ACTIVATEOPTIONS
|
||||
ACVS
|
||||
adaptivecards
|
||||
ADate
|
||||
@@ -788,6 +789,7 @@ LCIDTo
|
||||
Lclean
|
||||
Ldone
|
||||
Ldr
|
||||
LEFTALIGN
|
||||
LEFTSCROLLBAR
|
||||
LEFTTEXT
|
||||
LError
|
||||
@@ -1588,6 +1590,7 @@ steamapps
|
||||
STGC
|
||||
STGM
|
||||
STGMEDIUM
|
||||
STGMREAD
|
||||
STICKYKEYS
|
||||
sticpl
|
||||
storelogo
|
||||
@@ -1692,6 +1695,7 @@ TLayout
|
||||
tlb
|
||||
tlbimp
|
||||
tlc
|
||||
TGM
|
||||
TNP
|
||||
Toolhelp
|
||||
toolkitconverters
|
||||
@@ -1995,3 +1999,15 @@ culori
|
||||
Evercoder
|
||||
LCh
|
||||
CIELCh
|
||||
CLSCTXINPROCALL
|
||||
IIDI
|
||||
irow
|
||||
lcid
|
||||
OTHERUNZOOM
|
||||
OTHERZOOM
|
||||
PARENTCLOSING
|
||||
PARENTOPENING
|
||||
ppwsz
|
||||
rguid
|
||||
SCROLLCHILDREN
|
||||
VARTYPE
|
||||
@@ -126,16 +126,15 @@ Get-ChildItem -Path $rootPath -Recurse packages.config | ForEach-Object {
|
||||
}
|
||||
|
||||
# Update Directory.Packages.props file
|
||||
$propsFile = [System.IO.Path]::Combine($rootPath,"Directory.Packages.props")
|
||||
if (Test-Path $propsFile) {
|
||||
$file = Read-FileWithEncoding -Path $propsFile
|
||||
Get-ChildItem -Path $rootPath -Recurse "Directory.Packages.props" | ForEach-Object {
|
||||
$file = Read-FileWithEncoding -Path $_.FullName
|
||||
$content = $file.Content
|
||||
if ($content -match '<PackageVersion Include="Microsoft.WindowsAppSDK"') {
|
||||
$newVersionString = '<PackageVersion Include="Microsoft.WindowsAppSDK" Version="' + $WinAppSDKVersion + '" />'
|
||||
$oldVersionString = '<PackageVersion Include="Microsoft.WindowsAppSDK" Version="[-.0-9a-zA-Z]*" />'
|
||||
$content = $content -replace $oldVersionString, $newVersionString
|
||||
Write-FileWithEncoding -Path $propsFile -Content $content -Encoding $file.encoding
|
||||
Write-Host "Modified " $propsFile
|
||||
Write-FileWithEncoding -Path $_.FullName -Content $content -Encoding $file.encoding
|
||||
Write-Host "Modified " $_.FullName
|
||||
}
|
||||
}
|
||||
|
||||
@@ -144,8 +143,8 @@ Get-ChildItem -Path $rootPath -Recurse *.vcxproj | ForEach-Object {
|
||||
$file = Read-FileWithEncoding -Path $_.FullName
|
||||
$content = $file.Content
|
||||
if ($content -match '\\Microsoft.WindowsAppSDK.') {
|
||||
$newVersionString = '\Microsoft.WindowsAppSDK.' + $WinAppSDKVersion + '\'
|
||||
$oldVersionString = '\\Microsoft.WindowsAppSDK.[-.0-9a-zA-Z]*\\'
|
||||
$newVersionString = '\Microsoft.WindowsAppSDK.' + $WinAppSDKVersion
|
||||
$oldVersionString = '\\Microsoft.WindowsAppSDK.(?=[-.0-9a-zA-Z]*\d)[-.0-9a-zA-Z]*' #positive lookahead for at least a digit
|
||||
$content = $content -replace $oldVersionString, $newVersionString
|
||||
Write-FileWithEncoding -Path $_.FullName -Content $content -Encoding $file.encoding
|
||||
Write-Host "Modified " $_.FullName
|
||||
|
||||
@@ -1,7 +1,28 @@
|
||||
$VSInstances = ([xml](& 'C:\Program Files (x86)\Microsoft Visual Studio\Installer\vswhere.exe' -latest -requires Microsoft.VisualStudio.Component.VC.Tools.x86.x64 -include packages -format xml))
|
||||
$VSPackages = $VSInstances.instances.instance.packages.package
|
||||
$LatestVCPackage = ($VSInstances.instances.instance.packages.package | ? { $_.id -eq "Microsoft.VisualCpp.Tools.Core" })
|
||||
$LatestVCPackage = ($VSPackages | ? { $_.id -eq "Microsoft.VisualCpp.Tools.Core" })
|
||||
$LatestVCToolsVersion = $LatestVCPackage.version;
|
||||
|
||||
$VSRoot = (& 'C:\Program Files (x86)\Microsoft Visual Studio\Installer\vswhere.exe' -latest -requires Microsoft.VisualStudio.Component.VC.Tools.x86.x64 -property 'resolvedInstallationPath')
|
||||
$VCToolsRoot = Join-Path $VSRoot "VC\Tools\MSVC"
|
||||
|
||||
# We have observed a few instances where the VC tools package version actually
|
||||
# differs from the version on the files themselves. We might as well check
|
||||
# whether the version we just found _actually exists_ before we use it.
|
||||
# We'll use whichever highest version exists.
|
||||
$PackageVCToolPath = Join-Path $VCToolsRoot $LatestVCToolsVersion
|
||||
If ($Null -Eq (Get-Item $PackageVCToolPath -ErrorAction:Ignore)) {
|
||||
$VCToolsVersions = Get-ChildItem $VCToolsRoot | ForEach-Object {
|
||||
[Version]$_.Name
|
||||
} | Sort -Descending
|
||||
$LatestActualVCToolsVersion = $VCToolsVersions | Select -First 1
|
||||
|
||||
If ([Version]$LatestVCToolsVersion -Ne $LatestActualVCToolsVersion) {
|
||||
Write-Output "VC Tools Mismatch: Directory = $LatestActualVCToolsVersion, Package = $LatestVCToolsVersion"
|
||||
$LatestVCToolsVersion = $LatestActualVCToolsVersion.ToString(3)
|
||||
}
|
||||
}
|
||||
|
||||
Write-Output "Latest VCToolsVersion: $LatestVCToolsVersion"
|
||||
Write-Output "Updating VCToolsVersion environment variable for job"
|
||||
Write-Output "##vso[task.setvariable variable=VCToolsVersion]$LatestVCToolsVersion"
|
||||
|
||||
16
COMMUNITY.md
16
COMMUNITY.md
@@ -6,8 +6,8 @@ Names are in alphabetical order based on first name.
|
||||
|
||||
## High impact community members
|
||||
|
||||
### [@Aaron-Junker](https://github.com/Aaron-Junker) - [Aaron Junker](https://aaron-junker.github.io)
|
||||
Aaron has helped triaging, discussing, and creating a substantial number of issues and contributed features/fixes. Aaron was the primary person for helping build the File Explorer preview pane handler for developer files.
|
||||
### [@Noraa-Junker](https://github.com/Noraa-Junker) - [Noraa Junker](https://noraajunker.ch)
|
||||
Noraa has helped triaging, discussing, and creating a substantial number of issues and contributed features/fixes. Noraa was the primary person for helping build the File Explorer preview pane handler for developer files.
|
||||
|
||||
### [@cgaarden](https://github.com/cgaarden) - [Christian Gaarden Gaardmark](https://www.onegreatworld.com)
|
||||
Christian contributed New+ utility
|
||||
@@ -117,10 +117,6 @@ PowerRename is from Chris's SmartRename and icon rendering for SVGs in File Expl
|
||||
|
||||
PowerToys Awake is a tool to keep your computer awake.
|
||||
|
||||
### [@Niels9001](https://github.com/niels9001/) - [Niels Laute](https://nielslaute.com/)
|
||||
|
||||
Niels has helped drive large sums of our update toward a new [consistent and modern UX](https://github.com/microsoft/PowerToys/issues/891). This includes the [launcher work](https://github.com/microsoft/PowerToys/issues/44), color picker UX update and [icon design](https://github.com/microsoft/PowerToys/issues/1118).
|
||||
|
||||
### [@randyrants](https://github.com/randyrants) - [Randy Santossio](https://www.randyrants.com)
|
||||
|
||||
Randy contributed Registry Preview and some very early conversations about keyboard remapping.
|
||||
@@ -184,10 +180,10 @@ ZoomIt source code was originally implemented by [Sysinternals](https://sysinter
|
||||
|
||||
## PowerToys core team
|
||||
|
||||
- [@crutkas](https://github.com/crutkas/) - Clint Rutkas - Lead
|
||||
- [@cinnamon-msft](https://github.com/cinnamon-msft) - Kayla Cinnamon - Lead
|
||||
- [@nguyen-dows](https://github.com/nguyen-dows) - Christopher Nguyen - Product Manager
|
||||
- [@craigloewen-msft](https://github.com/craigloewen-msft) - Craig Loewen - Product Manager
|
||||
- [@niels9001](https://github.com/niels9001/) - Niels Laute - Product Manager
|
||||
- [@zhiwei-ms](https://github.com/zhiwei-ms) - Zhiwei Yu - Product Manager
|
||||
- [@dhowett](https://github.com/dhowett) - Dustin Howett - Dev lead
|
||||
- [@yeelam-gordon](https://github.com/yeelam-gordon) - Gordon Lam - Dev lead
|
||||
@@ -204,6 +200,12 @@ ZoomIt source code was originally implemented by [Sysinternals](https://sysinter
|
||||
- [@zhaopy536](https://github.com/zhaopy536) - Peiyao Zhao - Dev
|
||||
- [@wang563681252](https://github.com/wang563681252) - Zhaopeng Wang - Dev
|
||||
- [@vanzue](https://github.com/vanzue) - Kai Tao - Dev
|
||||
- [@zadjii-msft](https://github.com/zadjii-msft) - Mike Griese - Dev
|
||||
- [@khmyznikov](https://github.com/khmyznikov) - Gleb Khmyznikov - Dev
|
||||
- [@chatasweetie](https://github.com/chatasweetie) - Jessica Earley-Cha - Dev
|
||||
- [@MichaelJolley](https://github.com/MichaelJolley) - Michael Jolley - Dev
|
||||
- [@Jaylyn-Barbee](https://github.com/Jaylyn-Barbee) - Jaylyn Barbee - Dev
|
||||
- [@crutkas](https://github.com/crutkas/) - Clint Rutkas - Overhead
|
||||
|
||||
## Former PowerToys core team members
|
||||
|
||||
|
||||
@@ -55,7 +55,7 @@
|
||||
-->
|
||||
<PackageVersion Include="Microsoft.Windows.CsWinRT" Version="2.2.0" />
|
||||
<PackageVersion Include="Microsoft.Windows.SDK.BuildTools" Version="10.0.22621.2428" />
|
||||
<PackageVersion Include="Microsoft.WindowsAppSDK" Version="1.7.250401001" />
|
||||
<PackageVersion Include="Microsoft.WindowsAppSDK" Version="1.7.250513003" />
|
||||
<PackageVersion Include="Microsoft.Xaml.Behaviors.WinUI.Managed" Version="2.0.9" />
|
||||
<PackageVersion Include="Microsoft.Xaml.Behaviors.Wpf" Version="1.1.39" />
|
||||
<PackageVersion Include="ModernWpfUI" Version="0.9.4" />
|
||||
|
||||
@@ -1472,7 +1472,7 @@ SOFTWARE.
|
||||
- Microsoft.Windows.CsWin32 0.2.46-beta
|
||||
- Microsoft.Windows.CsWinRT 2.2.0
|
||||
- Microsoft.Windows.SDK.BuildTools 10.0.22621.2428
|
||||
- Microsoft.WindowsAppSDK 1.7.250401001
|
||||
- Microsoft.WindowsAppSDK 1.7.250513003
|
||||
- Microsoft.WindowsPackageManager.ComInterop 1.10.340
|
||||
- Microsoft.Xaml.Behaviors.WinUI.Managed 2.0.9
|
||||
- Microsoft.Xaml.Behaviors.Wpf 1.1.39
|
||||
|
||||
@@ -706,6 +706,8 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "RegistryPreview.FuzzTests",
|
||||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Microsoft.CmdPal.Ext.System", "src\modules\cmdpal\ext\Microsoft.CmdPal.Ext.System\Microsoft.CmdPal.Ext.System.csproj", "{64B88F02-CD88-4ED8-9624-989A800230F9}"
|
||||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "FancyZones.FuzzTests", "src\modules\fancyzones\FancyZones.FuzzTests\FancyZones.FuzzTests.csproj", "{0217E86E-3476-9946-DE8E-9D200CEBD47A}"
|
||||
EndProject
|
||||
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "CmdPalKeyboardService", "src\modules\cmdpal\CmdPalKeyboardService\CmdPalKeyboardService.vcxproj", "{5F63C743-F6CE-4DBA-A200-2B3F8A14E8C2}"
|
||||
EndProject
|
||||
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "PowerRename.FuzzingTest", "src\modules\powerrename\PowerRename.FuzzingTest\PowerRename.FuzzingTest.vcxproj", "{2694E2FB-DCD5-4BFF-A418-B6C3C7CE3B8E}"
|
||||
@@ -2596,6 +2598,14 @@ Global
|
||||
{2694E2FB-DCD5-4BFF-A418-B6C3C7CE3B8E}.Release|ARM64.ActiveCfg = Release|ARM64
|
||||
{2694E2FB-DCD5-4BFF-A418-B6C3C7CE3B8E}.Release|x64.ActiveCfg = Release|x64
|
||||
{2694E2FB-DCD5-4BFF-A418-B6C3C7CE3B8E}.Release|x64.Build.0 = Release|x64
|
||||
{0217E86E-3476-9946-DE8E-9D200CEBD47A}.Debug|ARM64.ActiveCfg = Debug|ARM64
|
||||
{0217E86E-3476-9946-DE8E-9D200CEBD47A}.Debug|ARM64.Build.0 = Debug|ARM64
|
||||
{0217E86E-3476-9946-DE8E-9D200CEBD47A}.Debug|x64.ActiveCfg = Debug|x64
|
||||
{0217E86E-3476-9946-DE8E-9D200CEBD47A}.Debug|x64.Build.0 = Debug|x64
|
||||
{0217E86E-3476-9946-DE8E-9D200CEBD47A}.Release|ARM64.ActiveCfg = Release|ARM64
|
||||
{0217E86E-3476-9946-DE8E-9D200CEBD47A}.Release|ARM64.Build.0 = Release|ARM64
|
||||
{0217E86E-3476-9946-DE8E-9D200CEBD47A}.Release|x64.ActiveCfg = Release|x64
|
||||
{0217E86E-3476-9946-DE8E-9D200CEBD47A}.Release|x64.Build.0 = Release|x64
|
||||
EndGlobalSection
|
||||
GlobalSection(SolutionProperties) = preSolution
|
||||
HideSolutionNode = FALSE
|
||||
@@ -2866,6 +2876,7 @@ Global
|
||||
{4E0AE3A4-2EE0-44D7-A2D0-8769977254A0} = {F05E590D-AD46-42BE-9C25-6A63ADD2E3EA}
|
||||
{5702B3CC-8575-48D5-83D8-15BB42269CD3} = {929C1324-22E8-4412-A9A8-80E85F3985A5}
|
||||
{64B88F02-CD88-4ED8-9624-989A800230F9} = {ECB8E0D1-7603-4E5C-AB10-D1E545E6F8E2}
|
||||
{0217E86E-3476-9946-DE8E-9D200CEBD47A} = {D1D6BC88-09AE-4FB4-AD24-5DED46A791DD}
|
||||
{5F63C743-F6CE-4DBA-A200-2B3F8A14E8C2} = {3846508C-77EB-4034-A702-F8BB263C4F79}
|
||||
{2694E2FB-DCD5-4BFF-A418-B6C3C7CE3B8E} = {89E20BCE-EB9C-46C8-8B50-E01A82E6FDC3}
|
||||
EndGlobalSection
|
||||
|
||||
@@ -7,6 +7,6 @@
|
||||
<CsWinRTAotWarningLevel>2</CsWinRTAotWarningLevel>
|
||||
|
||||
<!-- Suppress DynamicallyAccessedMemberTypes.PublicParameterlessConstructor in fallback code path of Windows SDK projection -->
|
||||
<WarningsNotAsErrors>IL2081;$(WarningsNotAsErrors)</WarningsNotAsErrors>
|
||||
<WarningsNotAsErrors>IL2081;CsWinRT1028;$(WarningsNotAsErrors)</WarningsNotAsErrors>
|
||||
</PropertyGroup>
|
||||
</Project>
|
||||
|
||||
@@ -92,6 +92,9 @@ namespace Microsoft.PowerToys.FilePreviewCommon
|
||||
var run = 0;
|
||||
var chunksLen = fileSize - QOI_PADDING_LENGTH;
|
||||
|
||||
var x = 0;
|
||||
var rowAdd = bitmapData.Stride - (channels * bitmapData.Width);
|
||||
|
||||
for (var dataIndex = 0; dataIndex < dataLength; dataIndex += channels)
|
||||
{
|
||||
if (run > 0)
|
||||
@@ -153,6 +156,14 @@ namespace Microsoft.PowerToys.FilePreviewCommon
|
||||
bitmapPixel[3] = pixel.A;
|
||||
}
|
||||
}
|
||||
|
||||
x++;
|
||||
if (x == bitmapData.Width)
|
||||
{
|
||||
// We align dataIndex with the stride
|
||||
dataIndex += rowAdd;
|
||||
x = 0;
|
||||
}
|
||||
}
|
||||
|
||||
bitmap.UnlockBits(bitmapData);
|
||||
|
||||
@@ -6,9 +6,10 @@ using System;
|
||||
using System.Diagnostics;
|
||||
using System.Globalization;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Reflection;
|
||||
using System.Runtime.CompilerServices;
|
||||
|
||||
using System.Threading.Tasks;
|
||||
using PowerToys.Interop;
|
||||
|
||||
namespace ManagedCommon
|
||||
@@ -40,25 +41,72 @@ namespace ManagedCommon
|
||||
/// <param name="isLocalLow">If the process using Logger is a low-privilege process.</param>
|
||||
public static void InitializeLogger(string applicationLogPath, bool isLocalLow = false)
|
||||
{
|
||||
string basePath;
|
||||
if (isLocalLow)
|
||||
{
|
||||
applicationLogPath = Environment.GetEnvironmentVariable("userprofile") + "\\appdata\\LocalLow\\Microsoft\\PowerToys" + applicationLogPath + "\\" + Version;
|
||||
basePath = Environment.GetEnvironmentVariable("userprofile") + "\\appdata\\LocalLow\\Microsoft\\PowerToys" + applicationLogPath;
|
||||
}
|
||||
else
|
||||
{
|
||||
applicationLogPath = Constants.AppDataPath() + applicationLogPath + "\\" + Version;
|
||||
basePath = Constants.AppDataPath() + applicationLogPath;
|
||||
}
|
||||
|
||||
if (!Directory.Exists(applicationLogPath))
|
||||
string versionedPath = Path.Combine(basePath, Version);
|
||||
|
||||
if (!Directory.Exists(versionedPath))
|
||||
{
|
||||
Directory.CreateDirectory(applicationLogPath);
|
||||
Directory.CreateDirectory(versionedPath);
|
||||
}
|
||||
|
||||
var logFilePath = Path.Combine(applicationLogPath, "Log_" + DateTime.Now.ToString(@"yyyy-MM-dd", CultureInfo.InvariantCulture) + ".log");
|
||||
var logFilePath = Path.Combine(versionedPath, "Log_" + DateTime.Now.ToString(@"yyyy-MM-dd", CultureInfo.InvariantCulture) + ".log");
|
||||
|
||||
Trace.Listeners.Add(new TextWriterTraceListener(logFilePath));
|
||||
|
||||
Trace.AutoFlush = true;
|
||||
|
||||
// Clean up old version log folders
|
||||
Task.Run(() => DeleteOldVersionLogFolders(basePath, versionedPath));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Deletes old version log folders, keeping only the current version's folder.
|
||||
/// </summary>
|
||||
/// <param name="basePath">The base path to the log files folder.</param>
|
||||
/// <param name="currentVersionPath">The path to the current version's log folder.</param>
|
||||
private static void DeleteOldVersionLogFolders(string basePath, string currentVersionPath)
|
||||
{
|
||||
try
|
||||
{
|
||||
if (!Directory.Exists(basePath))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
var dirs = Directory.GetDirectories(basePath)
|
||||
.Select(d => new DirectoryInfo(d))
|
||||
.OrderBy(d => d.CreationTime)
|
||||
.Where(d => !string.Equals(d.FullName, currentVersionPath, StringComparison.OrdinalIgnoreCase))
|
||||
.Take(3)
|
||||
.ToList();
|
||||
|
||||
foreach (var directory in dirs)
|
||||
{
|
||||
try
|
||||
{
|
||||
Directory.Delete(directory.FullName, true);
|
||||
LogInfo($"Deleted old log directory: {directory.FullName}");
|
||||
Task.Delay(500).Wait();
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
LogError($"Failed to delete old log directory: {directory.FullName}", ex);
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
LogError("Error cleaning up old log folders", ex);
|
||||
}
|
||||
}
|
||||
|
||||
public static void LogError(string message, [System.Runtime.CompilerServices.CallerMemberName] string memberName = "", [System.Runtime.CompilerServices.CallerFilePath] string sourceFilePath = "", [System.Runtime.CompilerServices.CallerLineNumber] int sourceLineNumber = 0)
|
||||
|
||||
@@ -152,6 +152,7 @@
|
||||
</data>
|
||||
<data name="ClipboardHistoryImage" xml:space="preserve">
|
||||
<value>Image data</value>
|
||||
<comment>Label used to represent an image in the clipboard history</comment>
|
||||
</data>
|
||||
<data name="ClipboardHistoryItemMoreOptionsButton.[using:Microsoft.UI.Xaml.Automation]AutomationProperties.Name" xml:space="preserve">
|
||||
<value>More options</value>
|
||||
@@ -194,15 +195,19 @@
|
||||
</data>
|
||||
<data name="TranscodeToMp3" xml:space="preserve">
|
||||
<value>Transcode to .mp3</value>
|
||||
<comment>Option to transcode audio files to MP3 format</comment>
|
||||
</data>
|
||||
<data name="TranscodeToMp4" xml:space="preserve">
|
||||
<value>Transcode to .mp4 (H.264/AAC)</value>
|
||||
<comment>Option to transcode video files to MP4 format with H.264 video codec and AAC audio codec</comment>
|
||||
</data>
|
||||
<data name="TranscodeErrorGeneral" xml:space="preserve">
|
||||
<value>An error occurred while transcoding media file</value>
|
||||
<comment>Error message displayed when media conversion fails for an unknown or general reason</comment>
|
||||
</data>
|
||||
<data name="TranscodeErrorUnsupportedCodec" xml:space="preserve">
|
||||
<value>The media file contains an unsupported codec</value>
|
||||
<comment>Error message displayed when media conversion fails due to an unsupported codec in the source file</comment>
|
||||
</data>
|
||||
<data name="PasteButtonAutomation.[using:Microsoft.UI.Xaml.Automation]AutomationProperties.Name" xml:space="preserve">
|
||||
<value>Paste</value>
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project ToolsVersion="15.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<Import Project="..\..\..\..\packages\Microsoft.WindowsAppSDK.1.7.250401001\build\native\Microsoft.WindowsAppSDK.props" Condition="Exists('..\..\..\..\packages\Microsoft.WindowsAppSDK.1.7.250401001\build\native\Microsoft.WindowsAppSDK.props')" />
|
||||
<Import Project="..\..\..\..\packages\Microsoft.WindowsAppSDK.1.7.250513003\build\native\Microsoft.WindowsAppSDK.props" Condition="Exists('..\..\..\..\packages\Microsoft.WindowsAppSDK.1.7.250513003\build\native\Microsoft.WindowsAppSDK.props')" />
|
||||
<Import Project="..\..\..\..\packages\Microsoft.Windows.SDK.BuildTools.10.0.22621.2428\build\Microsoft.Windows.SDK.BuildTools.props" Condition="Exists('..\..\..\..\packages\Microsoft.Windows.SDK.BuildTools.10.0.22621.2428\build\Microsoft.Windows.SDK.BuildTools.props')" />
|
||||
<Import Project="..\..\..\..\packages\Microsoft.Windows.CppWinRT.2.0.240111.5\build\native\Microsoft.Windows.CppWinRT.props" Condition="Exists('..\..\..\..\packages\Microsoft.Windows.CppWinRT.2.0.240111.5\build\native\Microsoft.Windows.CppWinRT.props')" />
|
||||
<PropertyGroup Label="Globals">
|
||||
@@ -141,7 +141,7 @@
|
||||
<Import Project="..\..\..\..\packages\Microsoft.Windows.ImplementationLibrary.1.0.231216.1\build\native\Microsoft.Windows.ImplementationLibrary.targets" Condition="Exists('..\..\..\..\packages\Microsoft.Windows.ImplementationLibrary.1.0.231216.1\build\native\Microsoft.Windows.ImplementationLibrary.targets')" />
|
||||
<Import Project="..\..\..\..\packages\Microsoft.Windows.SDK.BuildTools.10.0.22621.2428\build\Microsoft.Windows.SDK.BuildTools.targets" Condition="Exists('..\..\..\..\packages\Microsoft.Windows.SDK.BuildTools.10.0.22621.2428\build\Microsoft.Windows.SDK.BuildTools.targets')" />
|
||||
<Import Project="..\..\..\..\packages\Microsoft.Web.WebView2.1.0.2903.40\build\native\Microsoft.Web.WebView2.targets" Condition="Exists('..\..\..\..\packages\Microsoft.Web.WebView2.1.0.2903.40\build\native\Microsoft.Web.WebView2.targets')" />
|
||||
<Import Project="..\..\..\..\packages\Microsoft.WindowsAppSDK.1.7.250401001\build\native\Microsoft.WindowsAppSDK.targets" Condition="Exists('..\..\..\..\packages\Microsoft.WindowsAppSDK.1.7.250401001\build\native\Microsoft.WindowsAppSDK.targets')" />
|
||||
<Import Project="..\..\..\..\packages\Microsoft.WindowsAppSDK.1.7.250513003\build\native\Microsoft.WindowsAppSDK.targets" Condition="Exists('..\..\..\..\packages\Microsoft.WindowsAppSDK.1.7.250513003\build\native\Microsoft.WindowsAppSDK.targets')" />
|
||||
</ImportGroup>
|
||||
<Target Name="EnsureNuGetPackageBuildImports" BeforeTargets="PrepareForBuild">
|
||||
<PropertyGroup>
|
||||
@@ -153,7 +153,7 @@
|
||||
<Error Condition="!Exists('..\..\..\..\packages\Microsoft.Windows.SDK.BuildTools.10.0.22621.2428\build\Microsoft.Windows.SDK.BuildTools.props')" Text="$([System.String]::Format('$(ErrorText)', '..\..\..\..\packages\Microsoft.Windows.SDK.BuildTools.10.0.22621.2428\build\Microsoft.Windows.SDK.BuildTools.props'))" />
|
||||
<Error Condition="!Exists('..\..\..\..\packages\Microsoft.Windows.SDK.BuildTools.10.0.22621.2428\build\Microsoft.Windows.SDK.BuildTools.targets')" Text="$([System.String]::Format('$(ErrorText)', '..\..\..\..\packages\Microsoft.Windows.SDK.BuildTools.10.0.22621.2428\build\Microsoft.Windows.SDK.BuildTools.targets'))" />
|
||||
<Error Condition="!Exists('..\..\..\..\packages\Microsoft.Web.WebView2.1.0.2903.40\build\native\Microsoft.Web.WebView2.targets')" Text="$([System.String]::Format('$(ErrorText)', '..\..\..\..\packages\Microsoft.Web.WebView2.1.0.2903.40\build\native\Microsoft.Web.WebView2.targets'))" />
|
||||
<Error Condition="!Exists('..\..\..\..\packages\Microsoft.WindowsAppSDK.1.7.250401001\build\native\Microsoft.WindowsAppSDK.props')" Text="$([System.String]::Format('$(ErrorText)', '..\..\..\..\packages\Microsoft.WindowsAppSDK.1.7.250401001\build\native\Microsoft.WindowsAppSDK.props'))" />
|
||||
<Error Condition="!Exists('..\..\..\..\packages\Microsoft.WindowsAppSDK.1.7.250401001\build\native\Microsoft.WindowsAppSDK.targets')" Text="$([System.String]::Format('$(ErrorText)', '..\..\..\..\packages\Microsoft.WindowsAppSDK.1.7.250401001\build\native\Microsoft.WindowsAppSDK.targets'))" />
|
||||
<Error Condition="!Exists('..\..\..\..\packages\Microsoft.WindowsAppSDK.1.7.250513003\build\native\Microsoft.WindowsAppSDK.props')" Text="$([System.String]::Format('$(ErrorText)', '..\..\..\..\packages\Microsoft.WindowsAppSDK.1.7.250513003\build\native\Microsoft.WindowsAppSDK.props'))" />
|
||||
<Error Condition="!Exists('..\..\..\..\packages\Microsoft.WindowsAppSDK.1.7.250513003\build\native\Microsoft.WindowsAppSDK.targets')" Text="$([System.String]::Format('$(ErrorText)', '..\..\..\..\packages\Microsoft.WindowsAppSDK.1.7.250513003\build\native\Microsoft.WindowsAppSDK.targets'))" />
|
||||
</Target>
|
||||
</Project>
|
||||
@@ -4,5 +4,5 @@
|
||||
<package id="Microsoft.Windows.CppWinRT" version="2.0.240111.5" targetFramework="native" />
|
||||
<package id="Microsoft.Windows.ImplementationLibrary" version="1.0.231216.1" targetFramework="native" />
|
||||
<package id="Microsoft.Windows.SDK.BuildTools" version="10.0.22621.2428" targetFramework="native" />
|
||||
<package id="Microsoft.WindowsAppSDK" version="1.7.250401001" targetFramework="native" />
|
||||
<package id="Microsoft.WindowsAppSDK" version="1.7.250513003" targetFramework="native" />
|
||||
</packages>
|
||||
@@ -13,6 +13,7 @@
|
||||
#include <common/utils/winapi_error.h>
|
||||
#include <common/utils/processApi.h>
|
||||
#include <common/utils/elevation.h>
|
||||
#include <common/utils/logger_helper.h>
|
||||
|
||||
HINSTANCE g_hInst_MouseWithoutBorders = 0;
|
||||
|
||||
@@ -409,9 +410,12 @@ public:
|
||||
{
|
||||
app_name = L"MouseWithoutBorders";
|
||||
app_key = app_name;
|
||||
std::filesystem::path logFilePath(PTSettingsHelper::get_module_save_folder_location(app_key));
|
||||
logFilePath.append(LogSettings::mouseWithoutBordersLogPath);
|
||||
Logger::init(LogSettings::mouseWithoutBordersLoggerName, logFilePath.wstring(), PTSettingsHelper::get_log_settings_file_location());
|
||||
|
||||
LoggerHelpers::init_logger(app_key, L"ModuleInterface", LogSettings::mouseWithoutBordersLoggerName);
|
||||
|
||||
std::filesystem::path oldLogPath(PTSettingsHelper::get_module_save_folder_location(app_key));
|
||||
oldLogPath.append("LogsModuleInterface");
|
||||
LoggerHelpers::delete_old_log_folder(oldLogPath);
|
||||
|
||||
try
|
||||
{
|
||||
|
||||
@@ -193,27 +193,29 @@ namespace WorkspacesEditor.ViewModels
|
||||
ApplyShortcut(editedProject);
|
||||
}
|
||||
|
||||
private string GetDesktopShortcutAddress(Project project) => Path.Combine(FolderUtils.Desktop(), project.Name + ".lnk");
|
||||
|
||||
private string GetShortcutStoreAddress(Project project)
|
||||
{
|
||||
var dataFolder = FolderUtils.DataFolder();
|
||||
Directory.CreateDirectory(dataFolder);
|
||||
var shortcutStoreFolder = Path.Combine(dataFolder, "WorkspacesIcons");
|
||||
Directory.CreateDirectory(shortcutStoreFolder);
|
||||
return Path.Combine(shortcutStoreFolder, project.Id + ".ico");
|
||||
}
|
||||
|
||||
private void ApplyShortcut(Project project)
|
||||
{
|
||||
string basePath = AppDomain.CurrentDomain.BaseDirectory;
|
||||
string shortcutAddress = Path.Combine(FolderUtils.Desktop(), project.Name + ".lnk");
|
||||
string shortcutIconFilename = Path.Combine(FolderUtils.Temp(), project.Id + ".ico");
|
||||
|
||||
if (!project.IsShortcutNeeded)
|
||||
{
|
||||
if (File.Exists(shortcutIconFilename))
|
||||
{
|
||||
File.Delete(shortcutIconFilename);
|
||||
}
|
||||
|
||||
if (File.Exists(shortcutAddress))
|
||||
{
|
||||
File.Delete(shortcutAddress);
|
||||
}
|
||||
|
||||
RemoveShortcut(project);
|
||||
return;
|
||||
}
|
||||
|
||||
var basePath = AppDomain.CurrentDomain.BaseDirectory;
|
||||
var shortcutAddress = GetDesktopShortcutAddress(project);
|
||||
var shortcutIconFilename = GetShortcutStoreAddress(project);
|
||||
|
||||
Bitmap icon = WorkspacesIcon.DrawIcon(WorkspacesIcon.IconTextFromProjectName(project.Name), App.ThemeManager.GetCurrentTheme());
|
||||
WorkspacesIcon.SaveIcon(icon, shortcutIconFilename);
|
||||
|
||||
@@ -360,8 +362,8 @@ namespace WorkspacesEditor.ViewModels
|
||||
|
||||
private void RemoveShortcut(Project selectedProject)
|
||||
{
|
||||
string shortcutAddress = Path.Combine(FolderUtils.Desktop(), selectedProject.Name + ".lnk");
|
||||
string shortcutIconFilename = Path.Combine(FolderUtils.Temp(), selectedProject.Id + ".ico");
|
||||
string shortcutAddress = GetDesktopShortcutAddress(selectedProject);
|
||||
string shortcutIconFilename = GetShortcutStoreAddress(selectedProject);
|
||||
|
||||
if (File.Exists(shortcutIconFilename))
|
||||
{
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
<Project>
|
||||
<Project>
|
||||
<PropertyGroup>
|
||||
<ManagePackageVersionsCentrally>true</ManagePackageVersionsCentrally>
|
||||
</PropertyGroup>
|
||||
@@ -9,7 +9,7 @@
|
||||
<PackageVersion Include="Microsoft.Windows.CsWin32" Version="0.2.46-beta" />
|
||||
<PackageVersion Include="Microsoft.Windows.CsWinRT" Version="2.2.0" />
|
||||
<PackageVersion Include="Microsoft.Windows.SDK.BuildTools" Version="10.0.22621.2428" />
|
||||
<PackageVersion Include="Microsoft.WindowsAppSDK" Version="1.7.250401001" />
|
||||
<PackageVersion Include="Microsoft.WindowsAppSDK" Version="1.7.250513003" />
|
||||
<PackageVersion Include="Shmuelie.WinRTServer" Version="2.1.1" />
|
||||
<PackageVersion Include="StyleCop.Analyzers" Version="1.2.0-beta.556" />
|
||||
<PackageVersion Include="System.Text.Json" Version="9.0.5" />
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
<PropertyGroup>
|
||||
<OutputType>WinExe</OutputType>
|
||||
<RootNamespace>TemplateCmdPalExtension</RootNamespace>
|
||||
@@ -56,13 +56,35 @@
|
||||
</PropertyGroup>
|
||||
|
||||
<PropertyGroup>
|
||||
<PublishSingleFile>true</PublishSingleFile>
|
||||
<IsAotCompatible>true</IsAotCompatible>
|
||||
|
||||
<CsWinRTAotOptimizerEnabled>true</CsWinRTAotOptimizerEnabled>
|
||||
<CsWinRTAotWarningLevel>2</CsWinRTAotWarningLevel>
|
||||
<!-- Suppress DynamicallyAccessedMemberTypes.PublicParameterlessConstructor in fallback code path of Windows SDK projection -->
|
||||
<WarningsNotAsErrors>IL2081</WarningsNotAsErrors>
|
||||
<WarningsNotAsErrors>IL2081;$(WarningsNotAsErrors)</WarningsNotAsErrors>
|
||||
|
||||
<!-- When publishing trimmed, make sure to treat trimming warnings as build errors -->
|
||||
<ILLinkTreatWarningsAsErrors>true</ILLinkTreatWarningsAsErrors>
|
||||
|
||||
<PublishTrimmed>true</PublishTrimmed>
|
||||
<PublishSingleFile>true</PublishSingleFile>
|
||||
</PropertyGroup>
|
||||
|
||||
<PropertyGroup Condition="'$(Configuration)'=='Debug'">
|
||||
<!-- In Debug builds, trimming is disabled by default, but all the trim &
|
||||
AOT warnings are enabled. This gives debug builds a tighter inner loop,
|
||||
while at least warning about future trim violations -->
|
||||
<PublishTrimmed>false</PublishTrimmed>
|
||||
|
||||
<EnableTrimAnalyzer>true</EnableTrimAnalyzer>
|
||||
<EnableSingleFileAnalyzer>true</EnableSingleFileAnalyzer>
|
||||
<EnableAotAnalyzer>true</EnableAotAnalyzer>
|
||||
</PropertyGroup>
|
||||
|
||||
<PropertyGroup Condition="'$(Configuration)'!='Debug'">
|
||||
<!-- In Release builds, trimming is enabled by default.
|
||||
feel free to disable this if needed -->
|
||||
<PublishTrimmed>true</PublishTrimmed>
|
||||
</PropertyGroup>
|
||||
|
||||
|
||||
</Project>
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
<Import Project="..\..\..\Common.Dotnet.CsWinRT.props" />
|
||||
<Import Project="..\..\..\Common.Dotnet.AotCompatibility.props" />
|
||||
<PropertyGroup>
|
||||
|
||||
Binary file not shown.
@@ -79,6 +79,9 @@ public partial class ContentPageViewModel : PageViewModel, ICommandBarContext
|
||||
throw;
|
||||
}
|
||||
|
||||
var oneContent = newContent.Count == 1;
|
||||
newContent.ForEach(c => c.OnlyControlOnPage = oneContent);
|
||||
|
||||
// Now, back to a UI thread to update the observable collection
|
||||
DoOnUiThread(
|
||||
() =>
|
||||
|
||||
@@ -7,4 +7,5 @@ namespace Microsoft.CmdPal.UI.ViewModels;
|
||||
public abstract partial class ContentViewModel(WeakReference<IPageContext> context) :
|
||||
ExtensionObjectViewModel(context)
|
||||
{
|
||||
public bool OnlyControlOnPage { get; internal set; }
|
||||
}
|
||||
|
||||
@@ -0,0 +1,42 @@
|
||||
// Copyright (c) Microsoft Corporation
|
||||
// The Microsoft Corporation licenses this file to you under the MIT license.
|
||||
// See the LICENSE file in the project root for more information.
|
||||
|
||||
using Microsoft.CmdPal.UI.ViewModels.Models;
|
||||
using Microsoft.CommandPalette.Extensions;
|
||||
|
||||
namespace Microsoft.CmdPal.UI.ViewModels;
|
||||
|
||||
public partial class DetailsCommandsViewModel(
|
||||
IDetailsElement _detailsElement,
|
||||
WeakReference<IPageContext> context) : DetailsElementViewModel(_detailsElement, context)
|
||||
{
|
||||
public List<CommandViewModel> Commands { get; private set; } = [];
|
||||
|
||||
public bool HasCommands => Commands.Count > 0;
|
||||
|
||||
private readonly ExtensionObject<IDetailsCommands> _dataModel =
|
||||
new(_detailsElement.Data as IDetailsCommands);
|
||||
|
||||
public override void InitializeProperties()
|
||||
{
|
||||
base.InitializeProperties();
|
||||
var model = _dataModel.Unsafe;
|
||||
if (model == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
Commands = model
|
||||
.Commands?
|
||||
.Select(c =>
|
||||
{
|
||||
var vm = new CommandViewModel(c, PageContext);
|
||||
vm.InitializeProperties();
|
||||
return vm;
|
||||
})
|
||||
.ToList() ?? [];
|
||||
UpdateProperty(nameof(HasCommands));
|
||||
UpdateProperty(nameof(Commands));
|
||||
}
|
||||
}
|
||||
@@ -49,6 +49,7 @@ public partial class DetailsViewModel(IDetails _details, WeakReference<IPageCont
|
||||
{
|
||||
IDetailsSeparator => new DetailsSeparatorViewModel(element, this.PageContext),
|
||||
IDetailsLink => new DetailsLinkViewModel(element, this.PageContext),
|
||||
IDetailsCommands => new DetailsCommandsViewModel(element, this.PageContext),
|
||||
IDetailsTags => new DetailsTagsViewModel(element, this.PageContext),
|
||||
_ => null,
|
||||
};
|
||||
|
||||
@@ -11,6 +11,7 @@
|
||||
<!-- Other merged dictionaries here -->
|
||||
<ResourceDictionary Source="Styles/Button.xaml" />
|
||||
<ResourceDictionary Source="Styles/Colors.xaml" />
|
||||
<ResourceDictionary Source="Styles/TextBlock.xaml" />
|
||||
<ResourceDictionary Source="Styles/TextBox.xaml" />
|
||||
<ResourceDictionary Source="Styles/Settings.xaml" />
|
||||
<ResourceDictionary Source="Controls/Tag.xaml" />
|
||||
|
||||
@@ -8,6 +8,7 @@ using Microsoft.CmdPal.Common.Services;
|
||||
using Microsoft.CmdPal.Ext.Apps;
|
||||
using Microsoft.CmdPal.Ext.Bookmarks;
|
||||
using Microsoft.CmdPal.Ext.Calc;
|
||||
using Microsoft.CmdPal.Ext.ClipboardHistory;
|
||||
using Microsoft.CmdPal.Ext.Indexer;
|
||||
using Microsoft.CmdPal.Ext.Registry;
|
||||
using Microsoft.CmdPal.Ext.Shell;
|
||||
@@ -19,6 +20,7 @@ using Microsoft.CmdPal.Ext.WindowsSettings;
|
||||
using Microsoft.CmdPal.Ext.WindowsTerminal;
|
||||
using Microsoft.CmdPal.Ext.WindowWalker;
|
||||
using Microsoft.CmdPal.Ext.WinGet;
|
||||
using Microsoft.CmdPal.UI.Helpers;
|
||||
using Microsoft.CmdPal.UI.ViewModels;
|
||||
using Microsoft.CmdPal.UI.ViewModels.BuiltinCommands;
|
||||
using Microsoft.CmdPal.UI.ViewModels.Models;
|
||||
@@ -100,8 +102,7 @@ public partial class App : Application
|
||||
services.AddSingleton<ICommandProvider, IndexerCommandsProvider>();
|
||||
services.AddSingleton<ICommandProvider, BookmarksCommandProvider>();
|
||||
|
||||
// TODO GH #527 re-enable the clipboard commands
|
||||
// services.AddSingleton<ICommandProvider, ClipboardHistoryCommandsProvider>();
|
||||
services.AddSingleton<ICommandProvider, ClipboardHistoryCommandsProvider>();
|
||||
services.AddSingleton<ICommandProvider, WindowWalkerCommandsProvider>();
|
||||
services.AddSingleton<ICommandProvider, WebSearchCommandsProvider>();
|
||||
|
||||
@@ -140,6 +141,7 @@ public partial class App : Application
|
||||
var state = AppStateModel.LoadState();
|
||||
services.AddSingleton(state);
|
||||
services.AddSingleton<IExtensionService, ExtensionService>();
|
||||
services.AddSingleton<TrayIconService>();
|
||||
|
||||
// ViewModels
|
||||
services.AddSingleton<ShellViewModel>();
|
||||
|
||||
@@ -34,8 +34,13 @@
|
||||
Orientation="Vertical"
|
||||
Spacing="4" />
|
||||
|
||||
<!-- Template for actions in the mode actions dropdown button -->
|
||||
<DataTemplate x:Key="ContextMenuViewModelTemplate" x:DataType="viewmodels:CommandContextItemViewModel">
|
||||
<cmdpalUI:ContextItemTemplateSelector
|
||||
x:Key="ContextItemTemplateSelector"
|
||||
Critical="{StaticResource CriticalContextMenuViewModelTemplate}"
|
||||
Default="{StaticResource DefaultContextMenuViewModelTemplate}" />
|
||||
|
||||
<!-- Template for context items in the context item menu -->
|
||||
<DataTemplate x:Key="DefaultContextMenuViewModelTemplate" x:DataType="viewmodels:CommandContextItemViewModel">
|
||||
<Grid AutomationProperties.Name="{x:Bind Title, Mode=OneWay}">
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="32" />
|
||||
@@ -63,6 +68,38 @@
|
||||
Text="{x:Bind RequestedShortcut, Mode=OneWay, Converter={StaticResource KeyChordToStringConverter}}" />
|
||||
</Grid>
|
||||
</DataTemplate>
|
||||
|
||||
<!-- Template for context items flagged as critical -->
|
||||
<DataTemplate x:Key="CriticalContextMenuViewModelTemplate" x:DataType="viewmodels:CommandContextItemViewModel">
|
||||
<Grid AutomationProperties.Name="{x:Bind Title, Mode=OneWay}">
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="32" />
|
||||
<ColumnDefinition Width="*" />
|
||||
<ColumnDefinition Width="Auto" />
|
||||
</Grid.ColumnDefinitions>
|
||||
<cpcontrols:IconBox
|
||||
Width="16"
|
||||
Height="16"
|
||||
Margin="4,0,0,0"
|
||||
HorizontalAlignment="Left"
|
||||
Foreground="{ThemeResource SystemFillColorCriticalBrush}"
|
||||
SourceKey="{x:Bind Icon, Mode=OneWay}"
|
||||
SourceRequested="{x:Bind help:IconCacheProvider.SourceRequested}" />
|
||||
<TextBlock
|
||||
Grid.Column="1"
|
||||
VerticalAlignment="Center"
|
||||
Style="{StaticResource ContextItemTitleTextBlockCriticalStyle}"
|
||||
Text="{x:Bind Title, Mode=OneWay}" />
|
||||
<TextBlock
|
||||
Grid.Column="2"
|
||||
Margin="16,0,0,0"
|
||||
HorizontalAlignment="Right"
|
||||
VerticalAlignment="Center"
|
||||
Style="{StaticResource ContextItemCaptionTextBlockCriticalStyle}"
|
||||
Text="{x:Bind RequestedShortcut, Mode=OneWay, Converter={StaticResource KeyChordToStringConverter}}" />
|
||||
</Grid>
|
||||
</DataTemplate>
|
||||
|
||||
</ResourceDictionary>
|
||||
</UserControl.Resources>
|
||||
|
||||
@@ -237,7 +274,7 @@
|
||||
Margin="-16,-12,-16,-12"
|
||||
IsItemClickEnabled="True"
|
||||
ItemClick="CommandsDropdown_ItemClick"
|
||||
ItemTemplate="{StaticResource ContextMenuViewModelTemplate}"
|
||||
ItemTemplateSelector="{StaticResource ContextItemTemplateSelector}"
|
||||
ItemsSource="{x:Bind ViewModel.ContextMenu.FilteredItems, Mode=OneWay}"
|
||||
KeyDown="CommandsDropdown_KeyDown"
|
||||
SelectionMode="Single">
|
||||
|
||||
@@ -5,7 +5,9 @@
|
||||
using AdaptiveCards.ObjectModel.WinUI3;
|
||||
using AdaptiveCards.Rendering.WinUI3;
|
||||
using Microsoft.CmdPal.UI.ViewModels;
|
||||
using Microsoft.UI.Xaml;
|
||||
using Microsoft.UI.Xaml.Controls;
|
||||
using Microsoft.UI.Xaml.Media;
|
||||
|
||||
namespace Microsoft.CmdPal.UI.Controls;
|
||||
|
||||
@@ -96,11 +98,65 @@ public sealed partial class ContentFormControl : UserControl
|
||||
if (_renderedCard.FrameworkElement != null)
|
||||
{
|
||||
ContentGrid.Children.Add(_renderedCard.FrameworkElement);
|
||||
|
||||
// Use the Loaded event to ensure we focus after the card is in the visual tree
|
||||
_renderedCard.FrameworkElement.Loaded += OnFrameworkElementLoaded;
|
||||
}
|
||||
|
||||
_renderedCard.Action += Rendered_Action;
|
||||
}
|
||||
|
||||
private void OnFrameworkElementLoaded(object sender, RoutedEventArgs e)
|
||||
{
|
||||
// Unhook the event handler to avoid multiple registrations
|
||||
if (sender is FrameworkElement element)
|
||||
{
|
||||
element.Loaded -= OnFrameworkElementLoaded;
|
||||
|
||||
if (!ViewModel?.OnlyControlOnPage ?? true)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
// Focus on the first focusable element asynchronously to ensure the visual tree is fully built
|
||||
element.DispatcherQueue.TryEnqueue(Microsoft.UI.Dispatching.DispatcherQueuePriority.Normal, () =>
|
||||
{
|
||||
var focusableElement = FindFirstFocusableElement(element);
|
||||
focusableElement?.Focus(FocusState.Programmatic);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
private Control? FindFirstFocusableElement(DependencyObject parent)
|
||||
{
|
||||
var childCount = VisualTreeHelper.GetChildrenCount(parent);
|
||||
|
||||
// Process children first (depth-first search)
|
||||
for (var i = 0; i < childCount; i++)
|
||||
{
|
||||
var child = VisualTreeHelper.GetChild(parent, i);
|
||||
|
||||
// If the child is a focusable control like TextBox, ComboBox, etc.
|
||||
if (child is Control control &&
|
||||
control.IsEnabled &&
|
||||
control.IsTabStop &&
|
||||
control.Visibility == Visibility.Visible &&
|
||||
control.AllowFocusOnInteraction)
|
||||
{
|
||||
return control;
|
||||
}
|
||||
|
||||
// Recursively check children
|
||||
var result = FindFirstFocusableElement(child);
|
||||
if (result != null)
|
||||
{
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
private void Rendered_Action(RenderedAdaptiveCard sender, AdaptiveActionEventArgs args) =>
|
||||
ViewModel?.HandleSubmit(args.Action, args.Inputs.AsJson());
|
||||
}
|
||||
|
||||
@@ -0,0 +1,21 @@
|
||||
// Copyright (c) Microsoft Corporation
|
||||
// The Microsoft Corporation licenses this file to you under the MIT license.
|
||||
// See the LICENSE file in the project root for more information.
|
||||
|
||||
using Microsoft.CmdPal.UI.ViewModels;
|
||||
using Microsoft.UI.Xaml;
|
||||
using Microsoft.UI.Xaml.Controls;
|
||||
|
||||
namespace Microsoft.CmdPal.UI;
|
||||
|
||||
internal sealed partial class ContextItemTemplateSelector : DataTemplateSelector
|
||||
{
|
||||
public DataTemplate? Default { get; set; }
|
||||
|
||||
public DataTemplate? Critical { get; set; }
|
||||
|
||||
protected override DataTemplate? SelectTemplateCore(object item)
|
||||
{
|
||||
return ((CommandContextItemViewModel)item).IsCritical ? Critical : Default;
|
||||
}
|
||||
}
|
||||
@@ -18,6 +18,8 @@ public partial class DetailsDataTemplateSelector : DataTemplateSelector
|
||||
|
||||
public DataTemplate? TagTemplate { get; set; }
|
||||
|
||||
public DataTemplate? CommandTemplate { get; set; }
|
||||
|
||||
protected override DataTemplate? SelectTemplateCore(object item)
|
||||
{
|
||||
if (item is DetailsElementViewModel element)
|
||||
@@ -27,6 +29,7 @@ public partial class DetailsDataTemplateSelector : DataTemplateSelector
|
||||
{
|
||||
DetailsSeparatorViewModel => SeparatorTemplate,
|
||||
DetailsLinkViewModel => LinkTemplate,
|
||||
DetailsCommandsViewModel => CommandTemplate,
|
||||
DetailsTagsViewModel => TagTemplate,
|
||||
_ => null,
|
||||
};
|
||||
|
||||
@@ -0,0 +1,212 @@
|
||||
// Copyright (c) Microsoft Corporation
|
||||
// The Microsoft Corporation licenses this file to you under the MIT license.
|
||||
// See the LICENSE file in the project root for more information.
|
||||
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
using System.Runtime.InteropServices;
|
||||
using CommunityToolkit.Mvvm.Messaging;
|
||||
using Microsoft.CmdPal.UI.ViewModels;
|
||||
using Microsoft.CmdPal.UI.ViewModels.Messages;
|
||||
using Microsoft.UI.Xaml;
|
||||
using Windows.Win32;
|
||||
using Windows.Win32.Foundation;
|
||||
using Windows.Win32.UI.Shell;
|
||||
using Windows.Win32.UI.WindowsAndMessaging;
|
||||
using WinRT.Interop;
|
||||
using RS_ = Microsoft.CmdPal.UI.Helpers.ResourceLoaderInstance;
|
||||
|
||||
namespace Microsoft.CmdPal.UI.Helpers;
|
||||
|
||||
[SuppressMessage("StyleCop.CSharp.NamingRules", "SA1310:Field names should not contain underscore", Justification = "Stylistically, window messages are WM_*")]
|
||||
[SuppressMessage("StyleCop.CSharp.NamingRules", "SA1306:Field names should begin with lower-case letter", Justification = "Stylistically, window messages are WM_*")]
|
||||
internal sealed partial class TrayIconService
|
||||
{
|
||||
private const uint MY_NOTIFY_ID = 1000;
|
||||
private const uint WM_TRAY_ICON = PInvoke.WM_USER + 1;
|
||||
|
||||
private readonly SettingsModel _settingsModel;
|
||||
private readonly uint WM_TASKBAR_RESTART;
|
||||
|
||||
private Window? _window;
|
||||
private HWND _hwnd;
|
||||
private WNDPROC? _originalWndProc;
|
||||
private WNDPROC? _trayWndProc;
|
||||
private NOTIFYICONDATAW? _trayIconData;
|
||||
private DestroyIconSafeHandle? _largeIcon;
|
||||
private DestroyMenuSafeHandle? _popupMenu;
|
||||
|
||||
public TrayIconService(SettingsModel settingsModel)
|
||||
{
|
||||
_settingsModel = settingsModel;
|
||||
|
||||
// TaskbarCreated is the message that's broadcast when explorer.exe
|
||||
// restarts. We need to know when that happens to be able to bring our
|
||||
// notification area icon back
|
||||
WM_TASKBAR_RESTART = PInvoke.RegisterWindowMessage("TaskbarCreated");
|
||||
}
|
||||
|
||||
public void SetupTrayIcon(bool? showSystemTrayIcon = null)
|
||||
{
|
||||
if (showSystemTrayIcon ?? _settingsModel.ShowSystemTrayIcon)
|
||||
{
|
||||
if (_window == null)
|
||||
{
|
||||
_window = new Window();
|
||||
_hwnd = new HWND(WindowNative.GetWindowHandle(_window));
|
||||
|
||||
// LOAD BEARING: If you don't stick the pointer to HotKeyPrc into a
|
||||
// member (and instead like, use a local), then the pointer we marshal
|
||||
// into the WindowLongPtr will be useless after we leave this function,
|
||||
// and our **WindProc will explode**.
|
||||
_trayWndProc = WindowProc;
|
||||
var hotKeyPrcPointer = Marshal.GetFunctionPointerForDelegate(_trayWndProc);
|
||||
_originalWndProc = Marshal.GetDelegateForFunctionPointer<WNDPROC>(PInvoke.SetWindowLongPtr(_hwnd, WINDOW_LONG_PTR_INDEX.GWL_WNDPROC, hotKeyPrcPointer));
|
||||
}
|
||||
|
||||
if (_trayIconData == null)
|
||||
{
|
||||
// We need to stash this handle, so it doesn't clean itself up. If
|
||||
// explorer restarts, we'll come back through here, and we don't
|
||||
// really need to re-load the icon in that case. We can just use
|
||||
// the handle from the first time.
|
||||
_largeIcon = GetAppIconHandle();
|
||||
_trayIconData = new NOTIFYICONDATAW()
|
||||
{
|
||||
cbSize = (uint)Marshal.SizeOf(typeof(NOTIFYICONDATAW)),
|
||||
hWnd = _hwnd,
|
||||
uID = MY_NOTIFY_ID,
|
||||
uFlags = NOTIFY_ICON_DATA_FLAGS.NIF_MESSAGE | NOTIFY_ICON_DATA_FLAGS.NIF_ICON | NOTIFY_ICON_DATA_FLAGS.NIF_TIP,
|
||||
uCallbackMessage = WM_TRAY_ICON,
|
||||
hIcon = (HICON)_largeIcon.DangerousGetHandle(),
|
||||
szTip = RS_.GetString("AppStoreName"),
|
||||
};
|
||||
}
|
||||
|
||||
var d = (NOTIFYICONDATAW)_trayIconData;
|
||||
|
||||
// Add the notification icon
|
||||
PInvoke.Shell_NotifyIcon(NOTIFY_ICON_MESSAGE.NIM_ADD, in d);
|
||||
|
||||
if (_popupMenu == null)
|
||||
{
|
||||
_popupMenu = PInvoke.CreatePopupMenu_SafeHandle();
|
||||
PInvoke.InsertMenu(_popupMenu, 0, MENU_ITEM_FLAGS.MF_BYPOSITION | MENU_ITEM_FLAGS.MF_STRING, PInvoke.WM_USER + 1, RS_.GetString("TrayMenu_Settings"));
|
||||
PInvoke.InsertMenu(_popupMenu, 1, MENU_ITEM_FLAGS.MF_BYPOSITION | MENU_ITEM_FLAGS.MF_STRING, PInvoke.WM_USER + 2, RS_.GetString("TrayMenu_Exit"));
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
Destroy();
|
||||
}
|
||||
}
|
||||
|
||||
public void Destroy()
|
||||
{
|
||||
if (_trayIconData != null)
|
||||
{
|
||||
var d = (NOTIFYICONDATAW)_trayIconData;
|
||||
if (PInvoke.Shell_NotifyIcon(NOTIFY_ICON_MESSAGE.NIM_DELETE, in d))
|
||||
{
|
||||
_trayIconData = null;
|
||||
}
|
||||
}
|
||||
|
||||
if (_popupMenu != null)
|
||||
{
|
||||
_popupMenu.Close();
|
||||
_popupMenu = null;
|
||||
}
|
||||
|
||||
if (_largeIcon != null)
|
||||
{
|
||||
_largeIcon.Close();
|
||||
_largeIcon = null;
|
||||
}
|
||||
|
||||
if (_window != null)
|
||||
{
|
||||
_window.Close();
|
||||
_window = null;
|
||||
_hwnd = HWND.Null;
|
||||
}
|
||||
}
|
||||
|
||||
private DestroyIconSafeHandle GetAppIconHandle()
|
||||
{
|
||||
var exePath = System.Reflection.Assembly.GetExecutingAssembly().Location;
|
||||
DestroyIconSafeHandle largeIcon;
|
||||
PInvoke.ExtractIconEx(exePath, 0, out largeIcon, out _, 1);
|
||||
return largeIcon;
|
||||
}
|
||||
|
||||
private LRESULT WindowProc(
|
||||
HWND hwnd,
|
||||
uint uMsg,
|
||||
WPARAM wParam,
|
||||
LPARAM lParam)
|
||||
{
|
||||
switch (uMsg)
|
||||
{
|
||||
case PInvoke.WM_COMMAND:
|
||||
{
|
||||
if (wParam == PInvoke.WM_USER + 1)
|
||||
{
|
||||
WeakReferenceMessenger.Default.Send<OpenSettingsMessage>();
|
||||
}
|
||||
else if (wParam == PInvoke.WM_USER + 2)
|
||||
{
|
||||
WeakReferenceMessenger.Default.Send<QuitMessage>();
|
||||
}
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
// Shell_NotifyIcon can fail when we invoke it during the time explorer.exe isn't present/ready to handle it.
|
||||
// We'll also never receive WM_TASKBAR_RESTART message if the first call to Shell_NotifyIcon failed, so we use
|
||||
// WM_WINDOWPOSCHANGING which is always received on explorer startup sequence.
|
||||
case PInvoke.WM_WINDOWPOSCHANGING:
|
||||
{
|
||||
if (_trayIconData == null)
|
||||
{
|
||||
SetupTrayIcon();
|
||||
}
|
||||
}
|
||||
|
||||
break;
|
||||
default:
|
||||
// WM_TASKBAR_RESTART isn't a compile-time constant, so we can't
|
||||
// use it in a case label
|
||||
if (uMsg == WM_TASKBAR_RESTART)
|
||||
{
|
||||
// Handle the case where explorer.exe restarts.
|
||||
// Even if we created it before, do it again
|
||||
SetupTrayIcon();
|
||||
}
|
||||
else if (uMsg == WM_TRAY_ICON)
|
||||
{
|
||||
switch ((uint)lParam.Value)
|
||||
{
|
||||
case PInvoke.WM_RBUTTONUP:
|
||||
{
|
||||
if (_popupMenu != null)
|
||||
{
|
||||
PInvoke.GetCursorPos(out var cursorPos);
|
||||
PInvoke.SetForegroundWindow(_hwnd);
|
||||
PInvoke.TrackPopupMenuEx(_popupMenu, (uint)TRACK_POPUP_MENU_FLAGS.TPM_LEFTALIGN | (uint)TRACK_POPUP_MENU_FLAGS.TPM_BOTTOMALIGN, cursorPos.X, cursorPos.Y, _hwnd, null);
|
||||
}
|
||||
}
|
||||
|
||||
break;
|
||||
case PInvoke.WM_LBUTTONUP:
|
||||
case PInvoke.WM_LBUTTONDBLCLK:
|
||||
WeakReferenceMessenger.Default.Send<HotkeySummonMessage>(new(string.Empty, HWND.Null));
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
return PInvoke.CallWindowProc(_originalWndProc, hwnd, uMsg, wParam, lParam);
|
||||
}
|
||||
}
|
||||
@@ -29,7 +29,6 @@ using Windows.Win32;
|
||||
using Windows.Win32.Foundation;
|
||||
using Windows.Win32.Graphics.Dwm;
|
||||
using Windows.Win32.UI.Input.KeyboardAndMouse;
|
||||
using Windows.Win32.UI.Shell;
|
||||
using Windows.Win32.UI.WindowsAndMessaging;
|
||||
using WinRT;
|
||||
using WinUIEx;
|
||||
@@ -47,22 +46,8 @@ public sealed partial class MainWindow : WindowEx,
|
||||
private readonly WNDPROC? _hotkeyWndProc;
|
||||
private readonly WNDPROC? _originalWndProc;
|
||||
private readonly List<TopLevelHotkey> _hotkeys = [];
|
||||
private bool _ignoreHotKeyWhenFullScreen = true;
|
||||
|
||||
// Stylistically, window messages are WM_*
|
||||
#pragma warning disable SA1310 // Field names should not contain underscore
|
||||
#pragma warning disable SA1306 // Field names should begin with lower-case letter
|
||||
private const uint MY_NOTIFY_ID = 1000;
|
||||
private const uint WM_TRAY_ICON = PInvoke.WM_USER + 1;
|
||||
private readonly uint WM_TASKBAR_RESTART;
|
||||
#pragma warning restore SA1306 // Field names should begin with lower-case letter
|
||||
#pragma warning restore SA1310 // Field names should not contain underscore
|
||||
|
||||
private readonly KeyboardListener _keyboardListener;
|
||||
|
||||
// Notification Area ("Tray") icon data
|
||||
private NOTIFYICONDATAW? _trayIconData;
|
||||
private DestroyIconSafeHandle? _largeIcon;
|
||||
private bool _ignoreHotKeyWhenFullScreen = true;
|
||||
|
||||
private DesktopAcrylicController? _acrylicController;
|
||||
private SystemBackdropConfiguration? _configurationSource;
|
||||
@@ -79,11 +64,6 @@ public sealed partial class MainWindow : WindowEx,
|
||||
|
||||
_keyboardListener.SetProcessCommand(new CmdPalKeyboardService.ProcessCommand(HandleSummon));
|
||||
|
||||
// TaskbarCreated is the message that's broadcast when explorer.exe
|
||||
// restarts. We need to know when that happens to be able to bring our
|
||||
// notification area icon back
|
||||
WM_TASKBAR_RESTART = PInvoke.RegisterWindowMessage("TaskbarCreated");
|
||||
|
||||
this.SetIcon();
|
||||
AppWindow.Title = RS_.GetString("AppName");
|
||||
PositionCentered();
|
||||
@@ -159,7 +139,7 @@ public sealed partial class MainWindow : WindowEx,
|
||||
var settings = App.Current.Services.GetService<SettingsModel>()!;
|
||||
|
||||
SetupHotkey(settings);
|
||||
SetupTrayIcon(settings.ShowSystemTrayIcon);
|
||||
App.Current.Services.GetService<TrayIconService>()!.SetupTrayIcon(settings.ShowSystemTrayIcon);
|
||||
|
||||
_ignoreHotKeyWhenFullScreen = settings.IgnoreShortcutWhenFullscreen;
|
||||
|
||||
@@ -219,7 +199,7 @@ public sealed partial class MainWindow : WindowEx,
|
||||
|
||||
private void ShowHwnd(IntPtr hwndValue, MonitorBehavior target)
|
||||
{
|
||||
var hwnd = new HWND(hwndValue);
|
||||
var hwnd = new HWND(hwndValue != 0 ? hwndValue : _hwnd);
|
||||
|
||||
// Remember, IsIconic == "minimized", which is entirely different state
|
||||
// from "show/hide"
|
||||
@@ -332,7 +312,7 @@ public sealed partial class MainWindow : WindowEx,
|
||||
var extensionService = serviceProvider.GetService<IExtensionService>()!;
|
||||
extensionService.SignalStopExtensionsAsync();
|
||||
|
||||
RemoveTrayIcon();
|
||||
App.Current.Services.GetService<TrayIconService>()!.Destroy();
|
||||
|
||||
// WinUI bug is causing a crash on shutdown when FailFastOnErrors is set to true (#51773592).
|
||||
// Workaround by turning it off before shutdown.
|
||||
@@ -340,6 +320,7 @@ public sealed partial class MainWindow : WindowEx,
|
||||
DisposeAcrylic();
|
||||
|
||||
_keyboardListener.Stop();
|
||||
Environment.Exit(0);
|
||||
}
|
||||
|
||||
private void DisposeAcrylic()
|
||||
@@ -515,18 +496,27 @@ public sealed partial class MainWindow : WindowEx,
|
||||
|
||||
if (key != null)
|
||||
{
|
||||
var vk = key.Code;
|
||||
var modifiers =
|
||||
(key.Alt ? HOT_KEY_MODIFIERS.MOD_ALT : 0) |
|
||||
(key.Ctrl ? HOT_KEY_MODIFIERS.MOD_CONTROL : 0) |
|
||||
(key.Shift ? HOT_KEY_MODIFIERS.MOD_SHIFT : 0) |
|
||||
(key.Win ? HOT_KEY_MODIFIERS.MOD_WIN : 0)
|
||||
;
|
||||
|
||||
var success = PInvoke.RegisterHotKey(_hwnd, _hotkeys.Count, modifiers, (uint)vk);
|
||||
if (success)
|
||||
if (settings.UseLowLevelGlobalHotkey)
|
||||
{
|
||||
_hotkeys.Add(commandHotkey);
|
||||
_keyboardListener.SetHotkeyAction(key.Win, key.Ctrl, key.Shift, key.Alt, (byte)key.Code, commandHotkey.CommandId);
|
||||
|
||||
_hotkeys.Add(new(globalHotkey, string.Empty));
|
||||
}
|
||||
else
|
||||
{
|
||||
var vk = key.Code;
|
||||
var modifiers =
|
||||
(key.Alt ? HOT_KEY_MODIFIERS.MOD_ALT : 0) |
|
||||
(key.Ctrl ? HOT_KEY_MODIFIERS.MOD_CONTROL : 0) |
|
||||
(key.Shift ? HOT_KEY_MODIFIERS.MOD_SHIFT : 0) |
|
||||
(key.Win ? HOT_KEY_MODIFIERS.MOD_WIN : 0)
|
||||
;
|
||||
|
||||
var success = PInvoke.RegisterHotKey(_hwnd, _hotkeys.Count, modifiers, (uint)vk);
|
||||
if (success)
|
||||
{
|
||||
_hotkeys.Add(commandHotkey);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -606,100 +596,8 @@ public sealed partial class MainWindow : WindowEx,
|
||||
|
||||
return (LRESULT)IntPtr.Zero;
|
||||
}
|
||||
|
||||
// Shell_NotifyIcon can fail when we invoke it during the time explorer.exe isn't present/ready to handle it.
|
||||
// We'll also never receive WM_TASKBAR_RESTART message if the first call to Shell_NotifyIcon failed, so we use
|
||||
// WM_WINDOWPOSCHANGING which is always received on explorer startup sequence.
|
||||
case PInvoke.WM_WINDOWPOSCHANGING:
|
||||
{
|
||||
if (_trayIconData == null)
|
||||
{
|
||||
SetupTrayIcon();
|
||||
}
|
||||
}
|
||||
|
||||
break;
|
||||
default:
|
||||
// WM_TASKBAR_RESTART isn't a compile-time constant, so we can't
|
||||
// use it in a case label
|
||||
if (uMsg == WM_TASKBAR_RESTART)
|
||||
{
|
||||
// Handle the case where explorer.exe restarts.
|
||||
// Even if we created it before, do it again
|
||||
SetupTrayIcon();
|
||||
}
|
||||
else if (uMsg == WM_TRAY_ICON)
|
||||
{
|
||||
switch ((uint)lParam.Value)
|
||||
{
|
||||
case PInvoke.WM_RBUTTONUP:
|
||||
case PInvoke.WM_LBUTTONUP:
|
||||
case PInvoke.WM_LBUTTONDBLCLK:
|
||||
Summon(string.Empty);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
return PInvoke.CallWindowProc(_originalWndProc, hwnd, uMsg, wParam, lParam);
|
||||
}
|
||||
|
||||
private void SetupTrayIcon(bool? showSystemTrayIcon = null)
|
||||
{
|
||||
if (showSystemTrayIcon ?? App.Current.Services.GetService<SettingsModel>()!.ShowSystemTrayIcon)
|
||||
{
|
||||
// We only need to build the tray data once.
|
||||
if (_trayIconData == null)
|
||||
{
|
||||
// We need to stash this handle, so it doesn't clean itself up. If
|
||||
// explorer restarts, we'll come back through here, and we don't
|
||||
// really need to re-load the icon in that case. We can just use
|
||||
// the handle from the first time.
|
||||
_largeIcon = GetAppIconHandle();
|
||||
_trayIconData = new NOTIFYICONDATAW()
|
||||
{
|
||||
cbSize = (uint)Marshal.SizeOf(typeof(NOTIFYICONDATAW)),
|
||||
hWnd = _hwnd,
|
||||
uID = MY_NOTIFY_ID,
|
||||
uFlags = NOTIFY_ICON_DATA_FLAGS.NIF_MESSAGE | NOTIFY_ICON_DATA_FLAGS.NIF_ICON | NOTIFY_ICON_DATA_FLAGS.NIF_TIP,
|
||||
uCallbackMessage = WM_TRAY_ICON,
|
||||
hIcon = (HICON)_largeIcon.DangerousGetHandle(),
|
||||
szTip = RS_.GetString("AppStoreName"),
|
||||
};
|
||||
}
|
||||
|
||||
var d = (NOTIFYICONDATAW)_trayIconData;
|
||||
|
||||
// Add the notification icon
|
||||
PInvoke.Shell_NotifyIcon(NOTIFY_ICON_MESSAGE.NIM_ADD, in d);
|
||||
}
|
||||
else
|
||||
{
|
||||
RemoveTrayIcon();
|
||||
}
|
||||
}
|
||||
|
||||
private void RemoveTrayIcon()
|
||||
{
|
||||
if (_trayIconData != null)
|
||||
{
|
||||
var d = (NOTIFYICONDATAW)_trayIconData;
|
||||
if (PInvoke.Shell_NotifyIcon(NOTIFY_ICON_MESSAGE.NIM_DELETE, in d))
|
||||
{
|
||||
_trayIconData = null;
|
||||
}
|
||||
}
|
||||
|
||||
_largeIcon?.Close();
|
||||
}
|
||||
|
||||
private DestroyIconSafeHandle GetAppIconHandle()
|
||||
{
|
||||
var exePath = System.Reflection.Assembly.GetExecutingAssembly().Location;
|
||||
DestroyIconSafeHandle largeIcon;
|
||||
PInvoke.ExtractIconEx(exePath, 0, out largeIcon, out _, 1);
|
||||
return largeIcon;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -39,9 +39,7 @@
|
||||
</PropertyGroup>
|
||||
|
||||
<!-- BODGY: XES Versioning and WinAppSDK get into a fight about the app manifest, which breaks WinAppSDK. -->
|
||||
<Target Name="RearrangeXefVersioningAndWinAppSDKResourceGeneration"
|
||||
DependsOnTargets="GetNewAppManifestValues;CreateWinRTRegistration"
|
||||
BeforeTargets="XesWriteVersionInfoResourceFile">
|
||||
<Target Name="RearrangeXefVersioningAndWinAppSDKResourceGeneration" DependsOnTargets="GetNewAppManifestValues;CreateWinRTRegistration" BeforeTargets="XesWriteVersionInfoResourceFile">
|
||||
<PropertyGroup>
|
||||
<!-- XES uses this property to store the "final" location of the app manifest, before it erases it.
|
||||
We have to update it to the value WinAppSDK set it to. -->
|
||||
|
||||
@@ -35,9 +35,14 @@ WM_WINDOWPOSCHANGING
|
||||
RegisterWindowMessageW
|
||||
GetModuleHandleW
|
||||
ExtractIconEx
|
||||
TRACK_POPUP_MENU_FLAGS
|
||||
WM_COMMAND
|
||||
WM_RBUTTONUP
|
||||
WM_LBUTTONUP
|
||||
WM_LBUTTONDBLCLK
|
||||
CreatePopupMenu
|
||||
TrackPopupMenuEx
|
||||
InsertMenu
|
||||
|
||||
MessageBox
|
||||
DwmGetWindowAttribute
|
||||
|
||||
@@ -29,6 +29,7 @@
|
||||
|
||||
<cmdpalUI:DetailsDataTemplateSelector
|
||||
x:Key="DetailsDataTemplateSelector"
|
||||
CommandTemplate="{StaticResource DetailsCommandsTemplate}"
|
||||
LinkTemplate="{StaticResource DetailsLinkTemplate}"
|
||||
SeparatorTemplate="{StaticResource DetailsSeparatorTemplate}"
|
||||
TagTemplate="{StaticResource DetailsTagsTemplate}" />
|
||||
@@ -50,6 +51,27 @@
|
||||
ToolTipService.ToolTip="{x:Bind ToolTip, Mode=OneWay}" />
|
||||
</DataTemplate>
|
||||
|
||||
<DataTemplate x:Key="CommandTemplate" x:DataType="viewModels:CommandViewModel">
|
||||
<StackPanel Orientation="Vertical">
|
||||
<Button
|
||||
Name="Command"
|
||||
HorizontalAlignment="Stretch"
|
||||
HorizontalContentAlignment="Left"
|
||||
Click="Command_Click"
|
||||
Style="{StaticResource SubtleButtonStyle}">
|
||||
<StackPanel VerticalAlignment="Center" Orientation="Horizontal">
|
||||
<cpcontrols:IconBox
|
||||
Width="16"
|
||||
Height="16"
|
||||
Margin="0,3,8,0"
|
||||
SourceKey="{x:Bind Icon, Mode=OneWay}"
|
||||
SourceRequested="{x:Bind help:IconCacheProvider.SourceRequested}" />
|
||||
<TextBlock Text="{x:Bind Name}" />
|
||||
</StackPanel>
|
||||
</Button>
|
||||
</StackPanel>
|
||||
</DataTemplate>
|
||||
|
||||
<DataTemplate x:Key="DetailsLinkTemplate" x:DataType="viewModels:DetailsLinkViewModel">
|
||||
<StackPanel Orientation="Vertical">
|
||||
<TextBlock
|
||||
@@ -71,6 +93,18 @@
|
||||
Visibility="{x:Bind IsLink, Mode=OneWay}" />
|
||||
</StackPanel>
|
||||
</DataTemplate>
|
||||
<DataTemplate x:Key="DetailsCommandsTemplate" x:DataType="viewModels:DetailsCommandsViewModel">
|
||||
<StackPanel Orientation="Vertical" Spacing="4">
|
||||
<TextBlock
|
||||
IsTextSelectionEnabled="True"
|
||||
Text="{x:Bind Key, Mode=OneWay}"
|
||||
TextWrapping="WrapWholeWords" />
|
||||
<ItemsControl
|
||||
ItemTemplate="{StaticResource CommandTemplate}"
|
||||
ItemsSource="{x:Bind Commands, Mode=OneWay}"
|
||||
Visibility="{x:Bind HasCommands, Mode=OneWay}" />
|
||||
</StackPanel>
|
||||
</DataTemplate>
|
||||
<DataTemplate x:Key="DetailsSeparatorTemplate" x:DataType="viewModels:DetailsSeparatorViewModel">
|
||||
<StackPanel Margin="0,8,8,0" Orientation="Vertical">
|
||||
<Border
|
||||
|
||||
@@ -629,4 +629,12 @@ public sealed partial class ShellPage : Microsoft.UI.Xaml.Controls.Page,
|
||||
return iconInfoVM?.HasIcon(requestedTheme == Microsoft.UI.Xaml.ElementTheme.Light) ?? false;
|
||||
}
|
||||
}
|
||||
|
||||
private void Command_Click(object sender, Microsoft.UI.Xaml.RoutedEventArgs e)
|
||||
{
|
||||
if (sender is Button button && button.DataContext is CommandViewModel commandViewModel)
|
||||
{
|
||||
WeakReferenceMessenger.Default.Send<PerformCommandMessage>(new(commandViewModel.Model));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -412,4 +412,10 @@ Right-click to remove the key combination, thereby deactivating the shortcut.</v
|
||||
<data name="MoreCommandsButton.[using:Microsoft.UI.Xaml.Automation]AutomationProperties.Name" xml:space="preserve">
|
||||
<value>More</value>
|
||||
</data>
|
||||
<data name="TrayMenu_Settings" xml:space="preserve">
|
||||
<value>Settings</value>
|
||||
</data>
|
||||
<data name="TrayMenu_Exit" xml:space="preserve">
|
||||
<value>Exit</value>
|
||||
</data>
|
||||
</root>
|
||||
27
src/modules/cmdpal/Microsoft.CmdPal.UI/Styles/TextBlock.xaml
Normal file
27
src/modules/cmdpal/Microsoft.CmdPal.UI/Styles/TextBlock.xaml
Normal file
@@ -0,0 +1,27 @@
|
||||
<?xml version="1.0" encoding="utf-8" ?>
|
||||
<ResourceDictionary
|
||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:converters="using:CommunityToolkit.WinUI.Converters">
|
||||
|
||||
<ResourceDictionary.MergedDictionaries>
|
||||
<XamlControlsResources xmlns="using:Microsoft.UI.Xaml.Controls" />
|
||||
<!-- Other merged dictionaries here -->
|
||||
</ResourceDictionary.MergedDictionaries>
|
||||
|
||||
<Style
|
||||
x:Key="ContextItemTitleTextBlockCriticalStyle"
|
||||
BasedOn="{StaticResource BaseTextBlockStyle}"
|
||||
TargetType="TextBlock">
|
||||
<Setter Property="Foreground" Value="{ThemeResource SystemFillColorCriticalBrush}" />
|
||||
<Setter Property="FontWeight" Value="Normal" />
|
||||
</Style>
|
||||
|
||||
<Style
|
||||
x:Key="ContextItemCaptionTextBlockCriticalStyle"
|
||||
BasedOn="{StaticResource CaptionTextBlockStyle}"
|
||||
TargetType="TextBlock">
|
||||
<Setter Property="Foreground" Value="{ThemeResource SystemFillColorCriticalBrush}" />
|
||||
</Style>
|
||||
|
||||
</ResourceDictionary>
|
||||
@@ -1,9 +1,9 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project DefaultTargets="Build" ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<Import Project="..\..\..\..\packages\Microsoft.Windows.CppWinRT.2.0.240111.5\build\native\Microsoft.Windows.CppWinRT.props" Condition="Exists('..\..\..\..\packages\Microsoft.Windows.CppWinRT.2.0.240111.5\build\native\Microsoft.Windows.CppWinRT.props')" />
|
||||
<PropertyGroup>
|
||||
<PathToRoot>..\..\..\..\</PathToRoot>
|
||||
<WasdkNuget>$(PathToRoot)packages\Microsoft.WindowsAppSDK.1.7.250401001</WasdkNuget>
|
||||
<WasdkNuget>$(PathToRoot)packages\Microsoft.WindowsAppSDK.1.7.250513003</WasdkNuget>
|
||||
</PropertyGroup>
|
||||
<Import Project="$(WasdkNuget)\build\native\Microsoft.WindowsAppSDK.props" Condition="Exists('$(WasdkNuget)\build\native\Microsoft.WindowsAppSDK.props')" />
|
||||
<PropertyGroup Label="Globals">
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
#  Command Palette
|
||||
|
||||
Windows Command Palette ("CmdPal") is the next iteration of PowerToys Run. With extensibility at it's core, the Command Palette is your one-stop launcher to start _anything_.
|
||||
Windows Command Palette ("CmdPal") is the next iteration of PowerToys Run. With extensibility at its core, the Command Palette is your one-stop launcher to start _anything_.
|
||||
|
||||
By default, CmdPal is bound to <kbd>Win+Alt+Space</kbd>.
|
||||
|
||||
|
||||
@@ -71,7 +71,7 @@ public class AllAppsSettings : JsonSettingsManager
|
||||
|
||||
internal static string SettingsJsonPath()
|
||||
{
|
||||
string directory = Utilities.BaseSettingsPath("Microsoft.CmdPal");
|
||||
var directory = Utilities.BaseSettingsPath("Microsoft.CmdPal");
|
||||
Directory.CreateDirectory(directory);
|
||||
|
||||
// now, the state is just next to the exe
|
||||
|
||||
@@ -8,7 +8,12 @@ using System.Threading.Tasks;
|
||||
using ManagedCommon;
|
||||
using Microsoft.CmdPal.Ext.Apps.Programs;
|
||||
using Microsoft.CmdPal.Ext.Apps.Properties;
|
||||
using Microsoft.CmdPal.Ext.Apps.Utils;
|
||||
using Microsoft.CommandPalette.Extensions.Toolkit;
|
||||
using Windows.Services.Maps;
|
||||
using Windows.Win32;
|
||||
using Windows.Win32.System.Com;
|
||||
using Windows.Win32.UI.Shell;
|
||||
using WyHash;
|
||||
|
||||
namespace Microsoft.CmdPal.Ext.Apps;
|
||||
@@ -27,26 +32,31 @@ internal sealed partial class AppCommand : InvokableCommand
|
||||
|
||||
internal static async Task StartApp(string aumid)
|
||||
{
|
||||
var appManager = new ApplicationActivationManager();
|
||||
const ActivateOptions noFlags = ActivateOptions.None;
|
||||
await Task.Run(() =>
|
||||
{
|
||||
try
|
||||
unsafe
|
||||
{
|
||||
appManager.ActivateApplication(aumid, /*queryArguments*/ string.Empty, noFlags, out var unusedPid);
|
||||
}
|
||||
catch (System.Exception ex)
|
||||
{
|
||||
Logger.LogError(ex.Message);
|
||||
IApplicationActivationManager* appManager = null;
|
||||
try
|
||||
{
|
||||
PInvoke.CoCreateInstance(typeof(ApplicationActivationManager).GUID, null, CLSCTX.CLSCTX_INPROC_SERVER, out appManager).ThrowOnFailure();
|
||||
using var handle = new SafeComHandle((IntPtr)appManager);
|
||||
appManager->ActivateApplication(
|
||||
aumid,
|
||||
string.Empty,
|
||||
ACTIVATEOPTIONS.AO_NONE,
|
||||
out var unusedPid);
|
||||
}
|
||||
catch (System.Exception ex)
|
||||
{
|
||||
Logger.LogError(ex.Message);
|
||||
}
|
||||
}
|
||||
}).ConfigureAwait(false);
|
||||
}
|
||||
|
||||
internal static async Task StartExe(string path)
|
||||
{
|
||||
var appManager = new ApplicationActivationManager();
|
||||
|
||||
// const ActivateOptions noFlags = ActivateOptions.None;
|
||||
await Task.Run(() =>
|
||||
{
|
||||
try
|
||||
|
||||
@@ -1,11 +1,13 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
<Import Project="..\..\..\..\Common.Dotnet.CsWinRT.props" />
|
||||
<Import Project="..\..\..\..\Common.Dotnet.AotCompatibility.props" />
|
||||
<PropertyGroup>
|
||||
<RootNamespace>Microsoft.CmdPal.Ext.Apps</RootNamespace>
|
||||
<Nullable>enable</Nullable>
|
||||
<OutputPath>$(SolutionDir)$(Platform)\$(Configuration)\WinUI3Apps\CmdPal</OutputPath>
|
||||
<AppendTargetFrameworkToOutputPath>false</AppendTargetFrameworkToOutputPath>
|
||||
<AppendRuntimeIdentifierToOutputPath>false</AppendRuntimeIdentifierToOutputPath>
|
||||
<DisableRuntimeMarshalling>true</DisableRuntimeMarshalling>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
@@ -49,4 +51,9 @@
|
||||
<LastGenOutput>Resources.Designer.cs</LastGenOutput>
|
||||
</EmbeddedResource>
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<AdditionalFiles Include="NativeMethods.txt" />
|
||||
<AdditionalFiles Include="NativeMethods.json" />
|
||||
</ItemGroup>
|
||||
</Project>
|
||||
|
||||
@@ -0,0 +1,7 @@
|
||||
{
|
||||
"$schema": "https://aka.ms/CsWin32.schema.json",
|
||||
"allowMarshaling": false,
|
||||
"comInterop": {
|
||||
"preserveSigMethods": [ "*" ]
|
||||
}
|
||||
}
|
||||
@@ -1,19 +1,20 @@
|
||||
GetPhysicallyInstalledSystemMemory
|
||||
GlobalMemoryStatusEx
|
||||
GetSystemInfo
|
||||
IStream
|
||||
CoCreateInstance
|
||||
SetForegroundWindow
|
||||
IsIconic
|
||||
RegisterHotKey
|
||||
SetWindowLongPtr
|
||||
CallWindowProc
|
||||
ShowWindow
|
||||
SetForegroundWindow
|
||||
SetFocus
|
||||
SetActiveWindow
|
||||
MonitorFromWindow
|
||||
GetMonitorInfo
|
||||
IApplicationActivationManager
|
||||
ApplicationActivationManager
|
||||
SHCreateStreamOnFileEx
|
||||
CoAllowSetForegroundWindow
|
||||
SHCreateStreamOnFileEx
|
||||
SHLoadIndirectString
|
||||
SHCreateItemFromParsingName
|
||||
IShellItem
|
||||
ISequentialStream
|
||||
SHLoadIndirectString
|
||||
IAppxFactory
|
||||
AppxFactory
|
||||
IAppxManifestReader
|
||||
IAppxManifestApplicationsEnumerator
|
||||
IAppxManifestApplication
|
||||
IAppxManifestProperties
|
||||
IShellLinkW
|
||||
ShellLink
|
||||
IPersistFile
|
||||
CoTaskMemFree
|
||||
IUnknown
|
||||
|
||||
@@ -1,14 +0,0 @@
|
||||
// Copyright (c) Microsoft Corporation
|
||||
// The Microsoft Corporation licenses this file to you under the MIT license.
|
||||
// See the LICENSE file in the project root for more information.
|
||||
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
namespace Microsoft.CmdPal.Ext.Apps.Programs;
|
||||
|
||||
// Reference : https://stackoverflow.com/questions/32122679/getting-icon-of-modern-windows-app-from-a-desktop-application
|
||||
[Guid("5842a140-ff9f-4166-8f5c-62f5b7b0c781")]
|
||||
[ComImport]
|
||||
public class AppxFactory
|
||||
{
|
||||
}
|
||||
@@ -2,42 +2,75 @@
|
||||
// The Microsoft Corporation licenses this file to you under the MIT license.
|
||||
// See the LICENSE file in the project root for more information.
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Runtime.InteropServices;
|
||||
using ManagedCommon;
|
||||
using Microsoft.CmdPal.Ext.Apps.Utils;
|
||||
using Microsoft.UI.Xaml.Controls;
|
||||
using Windows.Win32;
|
||||
using Windows.Win32.Foundation;
|
||||
using Windows.Win32.Storage.Packaging.Appx;
|
||||
using Windows.Win32.System.Com;
|
||||
using static Microsoft.CmdPal.Ext.Apps.Utils.Native;
|
||||
|
||||
namespace Microsoft.CmdPal.Ext.Apps.Programs;
|
||||
|
||||
public static class AppxPackageHelper
|
||||
{
|
||||
private static readonly IAppxFactory AppxFactory = (IAppxFactory)new AppxFactory();
|
||||
|
||||
// This function returns a list of attributes of applications
|
||||
internal static IEnumerable<IAppxManifestApplication> GetAppsFromManifest(IStream stream)
|
||||
internal static unsafe List<IntPtr> GetAppsFromManifest(IStream* stream)
|
||||
{
|
||||
var reader = AppxFactory.CreateManifestReader(stream);
|
||||
var manifestApps = reader.GetApplications();
|
||||
PInvoke.CoCreateInstance(typeof(AppxFactory).GUID, null, CLSCTX.CLSCTX_INPROC_SERVER, out IAppxFactory* appxFactory).ThrowOnFailure();
|
||||
using var handle = new SafeComHandle((IntPtr)appxFactory);
|
||||
|
||||
while (manifestApps.GetHasCurrent())
|
||||
IAppxManifestReader* reader = null;
|
||||
IAppxManifestApplicationsEnumerator* manifestApps = null;
|
||||
var result = new List<IntPtr>();
|
||||
|
||||
appxFactory->CreateManifestReader(stream, &reader);
|
||||
using var readerHandle = new SafeComHandle((IntPtr)reader);
|
||||
reader->GetApplications(&manifestApps);
|
||||
using var manifestAppsHandle = new SafeComHandle((IntPtr)manifestApps);
|
||||
|
||||
while (true)
|
||||
{
|
||||
var manifestApp = manifestApps.GetCurrent();
|
||||
var hr = manifestApp.GetStringValue("AppListEntry", out var appListEntry);
|
||||
_ = CheckHRAndReturnOrThrow(hr, appListEntry);
|
||||
if (appListEntry != "none")
|
||||
manifestApps->GetHasCurrent(out var hasCurrent);
|
||||
if (hasCurrent == false)
|
||||
{
|
||||
yield return manifestApp;
|
||||
break;
|
||||
}
|
||||
|
||||
manifestApps.MoveNext();
|
||||
}
|
||||
}
|
||||
IAppxManifestApplication* manifestApp = null;
|
||||
|
||||
internal static T CheckHRAndReturnOrThrow<T>(HRESULT hr, T result)
|
||||
{
|
||||
if (hr != HRESULT.S_OK)
|
||||
{
|
||||
Marshal.ThrowExceptionForHR((int)hr);
|
||||
try
|
||||
{
|
||||
manifestApps->GetCurrent(&manifestApp).ThrowOnFailure();
|
||||
|
||||
var hr = manifestApp->GetStringValue("AppListEntry", out var appListEntryPtr);
|
||||
var appListEntry = ComFreeHelper.GetStringAndFree(hr, appListEntryPtr);
|
||||
|
||||
if (appListEntry != "none")
|
||||
{
|
||||
result.Add((IntPtr)manifestApp);
|
||||
}
|
||||
else if (manifestApp != null)
|
||||
{
|
||||
manifestApp->Release();
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
if (manifestApp != null)
|
||||
{
|
||||
manifestApp->Release();
|
||||
}
|
||||
|
||||
Logger.LogError($"Failed to get current application from manifest: {ex.Message}");
|
||||
}
|
||||
|
||||
manifestApps->MoveNext(out var hasNext);
|
||||
if (hasNext == false)
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
|
||||
@@ -1,47 +0,0 @@
|
||||
// Copyright (c) Microsoft Corporation
|
||||
// The Microsoft Corporation licenses this file to you under the MIT license.
|
||||
// See the LICENSE file in the project root for more information.
|
||||
|
||||
using System;
|
||||
using System.Runtime.CompilerServices;
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
namespace Microsoft.CmdPal.Ext.Apps.Programs;
|
||||
|
||||
// Reference : https://github.com/MicrosoftEdge/edge-launcher/blob/108e63df0b4cb5cd9d5e45aa7a264690851ec51d/MIcrosoftEdgeLauncherCsharp/Program.cs
|
||||
[Flags]
|
||||
public enum ActivateOptions
|
||||
{
|
||||
None = 0x00000000,
|
||||
DesignMode = 0x00000001,
|
||||
NoErrorUI = 0x00000002,
|
||||
NoSplashScreen = 0x00000004,
|
||||
}
|
||||
|
||||
// ApplicationActivationManager
|
||||
[ComImport]
|
||||
[Guid("2e941141-7f97-4756-ba1d-9decde894a3d")]
|
||||
[InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
|
||||
public interface IApplicationActivationManager
|
||||
{
|
||||
IntPtr ActivateApplication([In] string appUserModelId, [In] string arguments, [In] ActivateOptions options, [Out] out uint processId);
|
||||
|
||||
IntPtr ActivateForFile([In] string appUserModelId, [In] IntPtr /*IShellItemArray* */ itemArray, [In] string verb, [Out] out uint processId);
|
||||
|
||||
IntPtr ActivateForProtocol([In] string appUserModelId, [In] IntPtr /* IShellItemArray* */itemArray, [Out] out uint processId);
|
||||
}
|
||||
|
||||
// Application Activation Manager Class
|
||||
[ComImport]
|
||||
[Guid("45BA127D-10A8-46EA-8AB7-56EA9078943C")]
|
||||
public class ApplicationActivationManager : IApplicationActivationManager
|
||||
{
|
||||
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)/*, PreserveSig*/]
|
||||
public extern IntPtr ActivateApplication([In] string appUserModelId, [In] string arguments, [In] ActivateOptions options, [Out] out uint processId);
|
||||
|
||||
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
|
||||
public extern IntPtr ActivateForFile([In] string appUserModelId, [In] IntPtr /*IShellItemArray* */ itemArray, [In] string verb, [Out] out uint processId);
|
||||
|
||||
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
|
||||
public extern IntPtr ActivateForProtocol([In] string appUserModelId, [In] IntPtr /* IShellItemArray* */itemArray, [Out] out uint processId);
|
||||
}
|
||||
@@ -1,20 +0,0 @@
|
||||
// Copyright (c) Microsoft Corporation
|
||||
// The Microsoft Corporation licenses this file to you under the MIT license.
|
||||
// See the LICENSE file in the project root for more information.
|
||||
|
||||
using System.Runtime.InteropServices;
|
||||
using Windows.Win32.System.Com;
|
||||
|
||||
namespace Microsoft.CmdPal.Ext.Apps.Programs;
|
||||
|
||||
[Guid("BEB94909-E451-438B-B5A7-D79E767B75D8")]
|
||||
[InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
|
||||
public interface IAppxFactory
|
||||
{
|
||||
[System.Diagnostics.CodeAnalysis.SuppressMessage("StyleCop.CSharp.NamingRules", "SA1300:Element should begin with upper-case letter", Justification = "Implements COM Interface")]
|
||||
[System.Diagnostics.CodeAnalysis.SuppressMessage("Style", "IDE1006:Naming Styles", Justification = "Implements COM Interface")]
|
||||
[System.Diagnostics.CodeAnalysis.SuppressMessage("Naming", "CA1707:Identifiers should not contain underscores", Justification = "Implements COM Interface")]
|
||||
void _VtblGap0_2(); // skip 2 methods
|
||||
|
||||
internal IAppxManifestReader CreateManifestReader(IStream inputStream);
|
||||
}
|
||||
@@ -1,19 +0,0 @@
|
||||
// Copyright (c) Microsoft Corporation
|
||||
// The Microsoft Corporation licenses this file to you under the MIT license.
|
||||
// See the LICENSE file in the project root for more information.
|
||||
|
||||
using System.Runtime.InteropServices;
|
||||
using static Microsoft.CmdPal.Ext.Apps.Utils.Native;
|
||||
|
||||
namespace Microsoft.CmdPal.Ext.Apps.Programs;
|
||||
|
||||
[Guid("5DA89BF4-3773-46BE-B650-7E744863B7E8")]
|
||||
[InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
|
||||
public interface IAppxManifestApplication
|
||||
{
|
||||
[PreserveSig]
|
||||
HRESULT GetStringValue([MarshalAs(UnmanagedType.LPWStr)] string name, [MarshalAs(UnmanagedType.LPWStr)] out string value);
|
||||
|
||||
[PreserveSig]
|
||||
HRESULT GetAppUserModelId([MarshalAs(UnmanagedType.LPWStr)] out string value);
|
||||
}
|
||||
@@ -1,19 +0,0 @@
|
||||
// Copyright (c) Microsoft Corporation
|
||||
// The Microsoft Corporation licenses this file to you under the MIT license.
|
||||
// See the LICENSE file in the project root for more information.
|
||||
|
||||
using System;
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
namespace Microsoft.CmdPal.Ext.Apps.Programs;
|
||||
|
||||
[Guid("9EB8A55A-F04B-4D0D-808D-686185D4847A")]
|
||||
[InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
|
||||
public interface IAppxManifestApplicationsEnumerator
|
||||
{
|
||||
IAppxManifestApplication GetCurrent();
|
||||
|
||||
bool GetHasCurrent();
|
||||
|
||||
bool MoveNext();
|
||||
}
|
||||
@@ -1,19 +0,0 @@
|
||||
// Copyright (c) Microsoft Corporation
|
||||
// The Microsoft Corporation licenses this file to you under the MIT license.
|
||||
// See the LICENSE file in the project root for more information.
|
||||
|
||||
using System.Runtime.InteropServices;
|
||||
using static Microsoft.CmdPal.Ext.Apps.Utils.Native;
|
||||
|
||||
namespace Microsoft.CmdPal.Ext.Apps.Programs;
|
||||
|
||||
[Guid("03FAF64D-F26F-4B2C-AAF7-8FE7789B8BCA")]
|
||||
[InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
|
||||
public interface IAppxManifestProperties
|
||||
{
|
||||
[PreserveSig]
|
||||
HRESULT GetBoolValue([MarshalAs(UnmanagedType.LPWStr)] string name, out bool value);
|
||||
|
||||
[PreserveSig]
|
||||
HRESULT GetStringValue([MarshalAs(UnmanagedType.LPWStr)] string name, [MarshalAs(UnmanagedType.LPWStr)] out string value);
|
||||
}
|
||||
@@ -1,27 +0,0 @@
|
||||
// Copyright (c) Microsoft Corporation
|
||||
// The Microsoft Corporation licenses this file to you under the MIT license.
|
||||
// See the LICENSE file in the project root for more information.
|
||||
|
||||
using System;
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
namespace Microsoft.CmdPal.Ext.Apps.Programs;
|
||||
|
||||
[Guid("4E1BD148-55A0-4480-A3D1-15544710637C")]
|
||||
[InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
|
||||
public interface IAppxManifestReader
|
||||
{
|
||||
[System.Diagnostics.CodeAnalysis.SuppressMessage("StyleCop.CSharp.NamingRules", "SA1300:Element should begin with upper-case letter", Justification = "Implements COM Interface")]
|
||||
[System.Diagnostics.CodeAnalysis.SuppressMessage("Style", "IDE1006:Naming Styles", Justification = "Implements COM Interface")]
|
||||
[System.Diagnostics.CodeAnalysis.SuppressMessage("Naming", "CA1707:Identifiers should not contain underscores", Justification = "Implements COM Interface")]
|
||||
void _VtblGap0_1(); // skip 1 method
|
||||
|
||||
IAppxManifestProperties GetProperties();
|
||||
|
||||
[System.Diagnostics.CodeAnalysis.SuppressMessage("StyleCop.CSharp.NamingRules", "SA1300:Element should begin with upper-case letter", Justification = "Implements COM Interface")]
|
||||
[System.Diagnostics.CodeAnalysis.SuppressMessage("Style", "IDE1006:Naming Styles", Justification = "Implements COM Interface")]
|
||||
[System.Diagnostics.CodeAnalysis.SuppressMessage("Naming", "CA1707:Identifiers should not contain underscores", Justification = "Implements COM Interface")]
|
||||
void _VtblGap1_5(); // skip 5 methods
|
||||
|
||||
IAppxManifestApplicationsEnumerator GetApplications();
|
||||
}
|
||||
@@ -5,6 +5,7 @@
|
||||
using System;
|
||||
using System.ComponentModel;
|
||||
using System.IO;
|
||||
using System.Runtime.CompilerServices;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Text;
|
||||
|
||||
@@ -16,7 +17,7 @@ namespace Microsoft.CmdPal.Ext.Apps.Programs;
|
||||
/// <summary>
|
||||
/// Provides access to NTFS reparse points in .Net.
|
||||
/// </summary>
|
||||
public static class ReparsePoint
|
||||
public static partial class ReparsePoint
|
||||
{
|
||||
#pragma warning disable SA1310 // Field names should not contain underscore
|
||||
|
||||
@@ -36,7 +37,7 @@ public static class ReparsePoint
|
||||
#pragma warning restore SA1310 // Field names should not contain underscore
|
||||
|
||||
[Flags]
|
||||
private enum FileAccessType : uint
|
||||
internal enum FileAccessType : uint
|
||||
{
|
||||
DELETE = 0x00010000,
|
||||
READ_CONTROL = 0x00020000,
|
||||
@@ -100,7 +101,7 @@ public static class ReparsePoint
|
||||
}
|
||||
|
||||
[Flags]
|
||||
private enum FileShareType : uint
|
||||
internal enum FileShareType : uint
|
||||
{
|
||||
None = 0x00000000,
|
||||
Read = 0x00000001,
|
||||
@@ -108,7 +109,7 @@ public static class ReparsePoint
|
||||
Delete = 0x00000004,
|
||||
}
|
||||
|
||||
private enum CreationDisposition : uint
|
||||
internal enum CreationDisposition : uint
|
||||
{
|
||||
New = 1,
|
||||
CreateAlways = 2,
|
||||
@@ -118,7 +119,7 @@ public static class ReparsePoint
|
||||
}
|
||||
|
||||
[Flags]
|
||||
private enum FileAttributes : uint
|
||||
internal enum FileAttributes : uint
|
||||
{
|
||||
Readonly = 0x00000001,
|
||||
Hidden = 0x00000002,
|
||||
@@ -195,8 +196,9 @@ public static class ReparsePoint
|
||||
public AppExecutionAliasReparseTagBufferLayoutVersion Version;
|
||||
}
|
||||
|
||||
[DllImport("kernel32.dll", CharSet = CharSet.Auto, SetLastError = true)]
|
||||
private static extern bool DeviceIoControl(
|
||||
[LibraryImport("kernel32.dll", SetLastError = true)]
|
||||
[return: MarshalAs(UnmanagedType.Bool)]
|
||||
internal static partial bool DeviceIoControl(
|
||||
IntPtr hDevice,
|
||||
uint dwIoControlCode,
|
||||
IntPtr inBuffer,
|
||||
@@ -206,8 +208,8 @@ public static class ReparsePoint
|
||||
out int pBytesReturned,
|
||||
IntPtr lpOverlapped);
|
||||
|
||||
[DllImport("kernel32.dll", SetLastError = true, CharSet = CharSet.Unicode)]
|
||||
private static extern IntPtr CreateFile(
|
||||
[LibraryImport("kernel32.dll", SetLastError = true, StringMarshalling = StringMarshalling.Utf16)]
|
||||
internal static partial int CreateFile(
|
||||
string lpFileName,
|
||||
FileAccessType dwDesiredAccess,
|
||||
FileShareType dwShareMode,
|
||||
@@ -284,15 +286,18 @@ public static class ReparsePoint
|
||||
ThrowLastWin32Error("Unable to get information about reparse point.");
|
||||
}
|
||||
|
||||
AppExecutionAliasReparseTagHeader aliasReparseHeader = Marshal.PtrToStructure<AppExecutionAliasReparseTagHeader>(outBuffer);
|
||||
|
||||
if (aliasReparseHeader.ReparseTag == IO_REPARSE_TAG_APPEXECLINK)
|
||||
unsafe
|
||||
{
|
||||
var metadata = AppExecutionAliasMetadata.FromPersistedRepresentationIntPtr(
|
||||
outBuffer,
|
||||
aliasReparseHeader.Version);
|
||||
var aliasReparseHeader = Unsafe.Read<AppExecutionAliasReparseTagHeader>((void*)outBuffer);
|
||||
|
||||
return metadata.ExePath;
|
||||
if (aliasReparseHeader.ReparseTag == IO_REPARSE_TAG_APPEXECLINK)
|
||||
{
|
||||
var metadata = AppExecutionAliasMetadata.FromPersistedRepresentationIntPtr(
|
||||
outBuffer,
|
||||
aliasReparseHeader.Version);
|
||||
|
||||
return metadata.ExePath;
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
@@ -319,61 +324,65 @@ public static class ReparsePoint
|
||||
|
||||
public static AppExecutionAliasMetadata FromPersistedRepresentationIntPtr(IntPtr reparseDataBufferPtr, AppExecutionAliasReparseTagBufferLayoutVersion version)
|
||||
{
|
||||
var dataOffset = Marshal.SizeOf<AppExecutionAliasReparseTagHeader>();
|
||||
var dataBufferPtr = reparseDataBufferPtr + dataOffset;
|
||||
|
||||
string? packageFullName = null;
|
||||
string? packageFamilyName = null;
|
||||
string? aumid = null;
|
||||
string? exePath = null;
|
||||
|
||||
VerifyVersion(version);
|
||||
|
||||
switch (version)
|
||||
unsafe
|
||||
{
|
||||
case AppExecutionAliasReparseTagBufferLayoutVersion.Initial:
|
||||
packageFullName = Marshal.PtrToStringUni(dataBufferPtr);
|
||||
if (packageFullName is not null)
|
||||
{
|
||||
dataBufferPtr += Encoding.Unicode.GetByteCount(packageFullName) + Encoding.Unicode.GetByteCount("\0");
|
||||
aumid = Marshal.PtrToStringUni(dataBufferPtr);
|
||||
var dataOffset = Unsafe.SizeOf<AppExecutionAliasReparseTagHeader>();
|
||||
|
||||
if (aumid is not null)
|
||||
var dataBufferPtr = reparseDataBufferPtr + dataOffset;
|
||||
|
||||
string? packageFullName = null;
|
||||
string? packageFamilyName = null;
|
||||
string? aumid = null;
|
||||
string? exePath = null;
|
||||
|
||||
VerifyVersion(version);
|
||||
|
||||
switch (version)
|
||||
{
|
||||
case AppExecutionAliasReparseTagBufferLayoutVersion.Initial:
|
||||
packageFullName = Marshal.PtrToStringUni(dataBufferPtr);
|
||||
if (packageFullName is not null)
|
||||
{
|
||||
dataBufferPtr += Encoding.Unicode.GetByteCount(aumid) + Encoding.Unicode.GetByteCount("\0");
|
||||
exePath = Marshal.PtrToStringUni(dataBufferPtr);
|
||||
dataBufferPtr += Encoding.Unicode.GetByteCount(packageFullName) + Encoding.Unicode.GetByteCount("\0");
|
||||
aumid = Marshal.PtrToStringUni(dataBufferPtr);
|
||||
|
||||
if (aumid is not null)
|
||||
{
|
||||
dataBufferPtr += Encoding.Unicode.GetByteCount(aumid) + Encoding.Unicode.GetByteCount("\0");
|
||||
exePath = Marshal.PtrToStringUni(dataBufferPtr);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
break;
|
||||
break;
|
||||
|
||||
case AppExecutionAliasReparseTagBufferLayoutVersion.PackageFamilyName:
|
||||
case AppExecutionAliasReparseTagBufferLayoutVersion.MultiAppTypeSupport:
|
||||
packageFamilyName = Marshal.PtrToStringUni(dataBufferPtr);
|
||||
case AppExecutionAliasReparseTagBufferLayoutVersion.PackageFamilyName:
|
||||
case AppExecutionAliasReparseTagBufferLayoutVersion.MultiAppTypeSupport:
|
||||
packageFamilyName = Marshal.PtrToStringUni(dataBufferPtr);
|
||||
|
||||
if (packageFamilyName is not null)
|
||||
{
|
||||
dataBufferPtr += Encoding.Unicode.GetByteCount(packageFamilyName) + Encoding.Unicode.GetByteCount("\0");
|
||||
aumid = Marshal.PtrToStringUni(dataBufferPtr);
|
||||
|
||||
if (aumid is not null)
|
||||
if (packageFamilyName is not null)
|
||||
{
|
||||
dataBufferPtr += Encoding.Unicode.GetByteCount(aumid) + Encoding.Unicode.GetByteCount("\0");
|
||||
dataBufferPtr += Encoding.Unicode.GetByteCount(packageFamilyName) + Encoding.Unicode.GetByteCount("\0");
|
||||
aumid = Marshal.PtrToStringUni(dataBufferPtr);
|
||||
|
||||
exePath = Marshal.PtrToStringUni(dataBufferPtr);
|
||||
if (aumid is not null)
|
||||
{
|
||||
dataBufferPtr += Encoding.Unicode.GetByteCount(aumid) + Encoding.Unicode.GetByteCount("\0");
|
||||
|
||||
exePath = Marshal.PtrToStringUni(dataBufferPtr);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
break;
|
||||
break;
|
||||
}
|
||||
|
||||
return new AppExecutionAliasMetadata
|
||||
{
|
||||
PackageFullName = packageFullName ?? string.Empty,
|
||||
PackageFamilyName = packageFamilyName ?? string.Empty,
|
||||
Aumid = aumid ?? string.Empty,
|
||||
ExePath = exePath ?? string.Empty,
|
||||
};
|
||||
}
|
||||
|
||||
return new AppExecutionAliasMetadata
|
||||
{
|
||||
PackageFullName = packageFullName ?? string.Empty,
|
||||
PackageFamilyName = packageFamilyName ?? string.Empty,
|
||||
Aumid = aumid ?? string.Empty,
|
||||
ExePath = exePath ?? string.Empty,
|
||||
};
|
||||
}
|
||||
|
||||
private static void VerifyVersion(AppExecutionAliasReparseTagBufferLayoutVersion version)
|
||||
|
||||
@@ -3,17 +3,19 @@
|
||||
// See the LICENSE file in the project root for more information.
|
||||
|
||||
using System;
|
||||
using System.Collections.Concurrent;
|
||||
using System.Collections.Generic;
|
||||
using System.IO.Abstractions;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
using System.Xml.Linq;
|
||||
using ManagedCommon;
|
||||
using Microsoft.CmdPal.Ext.Apps.Utils;
|
||||
using Microsoft.CommandPalette.Extensions.Toolkit;
|
||||
using Windows.Win32;
|
||||
using Windows.Win32.Foundation;
|
||||
using Windows.Win32.Storage.Packaging.Appx;
|
||||
using Windows.Win32.System.Com;
|
||||
using static Microsoft.CmdPal.Ext.Apps.Utils.Native;
|
||||
|
||||
namespace Microsoft.CmdPal.Ext.Apps.Programs;
|
||||
|
||||
@@ -55,7 +57,7 @@ public partial class UWP
|
||||
FamilyName = package.FamilyName;
|
||||
}
|
||||
|
||||
public void InitializeAppInfo(string installedLocation)
|
||||
public unsafe void InitializeAppInfo(string installedLocation)
|
||||
{
|
||||
Location = installedLocation;
|
||||
LocationLocalized = ShellLocalization.Instance.GetLocalizedPath(installedLocation);
|
||||
@@ -65,26 +67,31 @@ public partial class UWP
|
||||
InitPackageVersion(namespaces);
|
||||
|
||||
const uint noAttribute = 0x80;
|
||||
|
||||
var access = (uint)STGM.READ;
|
||||
var hResult = PInvoke.SHCreateStreamOnFileEx(path, access, noAttribute, false, null, out IStream stream);
|
||||
|
||||
// S_OK
|
||||
if (hResult == 0)
|
||||
const uint STGMREAD = 0x00000000;
|
||||
try
|
||||
{
|
||||
Apps = AppxPackageHelper.GetAppsFromManifest(stream).Select(appInManifest => new UWPApplication(appInManifest, this)).Where(a =>
|
||||
IStream* stream = null;
|
||||
PInvoke.SHCreateStreamOnFileEx(path, STGMREAD, noAttribute, false, null, &stream).ThrowOnFailure();
|
||||
using var streamHandle = new SafeComHandle((IntPtr)stream);
|
||||
|
||||
Apps = AppxPackageHelper.GetAppsFromManifest(stream).Select(appInManifest =>
|
||||
{
|
||||
using var appHandle = new SafeComHandle(appInManifest);
|
||||
return new UWPApplication((IAppxManifestApplication*)appInManifest, this);
|
||||
}).Where(a =>
|
||||
{
|
||||
var valid =
|
||||
!string.IsNullOrEmpty(a.UserModelId) &&
|
||||
!string.IsNullOrEmpty(a.DisplayName) &&
|
||||
a.AppListEntry != "none";
|
||||
|
||||
!string.IsNullOrEmpty(a.UserModelId) &&
|
||||
!string.IsNullOrEmpty(a.DisplayName) &&
|
||||
a.AppListEntry != "none";
|
||||
return valid;
|
||||
}).ToList();
|
||||
}
|
||||
else
|
||||
catch (Exception ex)
|
||||
{
|
||||
Apps = Array.Empty<UWPApplication>();
|
||||
Logger.LogError($"Failed to initialize UWP app info for {Name} ({FullName}): {ex.Message}");
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -123,35 +130,36 @@ public partial class UWP
|
||||
{
|
||||
var windows10 = new Version(10, 0);
|
||||
var support = Environment.OSVersion.Version.Major >= windows10.Major;
|
||||
if (support)
|
||||
{
|
||||
var applications = CurrentUserPackages().AsParallel().SelectMany(p =>
|
||||
{
|
||||
UWP u;
|
||||
try
|
||||
{
|
||||
u = new UWP(p);
|
||||
u.InitializeAppInfo(p.InstalledLocation);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Logger.LogError(ex.Message);
|
||||
return Array.Empty<UWPApplication>();
|
||||
}
|
||||
|
||||
return u.Apps;
|
||||
});
|
||||
|
||||
var updatedListWithoutDisabledApps = applications
|
||||
.Where(t1 => AllAppsSettings.Instance.DisabledProgramSources.All(x => x.UniqueIdentifier != t1.UniqueIdentifier))
|
||||
.Select(x => x);
|
||||
|
||||
return updatedListWithoutDisabledApps.ToArray();
|
||||
}
|
||||
else
|
||||
if (!support)
|
||||
{
|
||||
return Array.Empty<UWPApplication>();
|
||||
}
|
||||
|
||||
var appsBag = new ConcurrentBag<UWPApplication>();
|
||||
|
||||
Parallel.ForEach(CurrentUserPackages(), p =>
|
||||
{
|
||||
try
|
||||
{
|
||||
var u = new UWP(p);
|
||||
u.InitializeAppInfo(p.InstalledLocation);
|
||||
|
||||
foreach (var app in u.Apps)
|
||||
{
|
||||
if (AllAppsSettings.Instance.DisabledProgramSources.All(x => x.UniqueIdentifier != app.UniqueIdentifier))
|
||||
{
|
||||
appsBag.Add(app);
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Logger.LogError(ex.Message);
|
||||
}
|
||||
});
|
||||
|
||||
return appsBag.ToArray();
|
||||
}
|
||||
|
||||
private static IEnumerable<IPackage> CurrentUserPackages()
|
||||
|
||||
@@ -6,6 +6,7 @@ using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO.Abstractions;
|
||||
using System.Linq;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Text;
|
||||
using System.Xml;
|
||||
using ManagedCommon;
|
||||
@@ -13,7 +14,9 @@ using Microsoft.CmdPal.Ext.Apps.Commands;
|
||||
using Microsoft.CmdPal.Ext.Apps.Properties;
|
||||
using Microsoft.CmdPal.Ext.Apps.Utils;
|
||||
using Microsoft.CommandPalette.Extensions.Toolkit;
|
||||
using static Microsoft.CmdPal.Ext.Apps.Utils.Native;
|
||||
using Windows.Win32;
|
||||
using Windows.Win32.Foundation;
|
||||
using Windows.Win32.Storage.Packaging.Appx;
|
||||
using PackageVersion = Microsoft.CmdPal.Ext.Apps.Programs.UWP.PackageVersion;
|
||||
using Theme = Microsoft.CmdPal.Ext.Apps.Utils.Theme;
|
||||
|
||||
@@ -97,27 +100,27 @@ public class UWPApplication : IProgram
|
||||
return commands;
|
||||
}
|
||||
|
||||
public UWPApplication(IAppxManifestApplication manifestApp, UWP package)
|
||||
internal unsafe UWPApplication(IAppxManifestApplication* manifestApp, UWP package)
|
||||
{
|
||||
ArgumentNullException.ThrowIfNull(manifestApp);
|
||||
|
||||
var hr = manifestApp.GetAppUserModelId(out var tmpUserModelId);
|
||||
UserModelId = AppxPackageHelper.CheckHRAndReturnOrThrow(hr, tmpUserModelId);
|
||||
var hr = manifestApp->GetAppUserModelId(out var tmpUserModelIdPtr);
|
||||
UserModelId = ComFreeHelper.GetStringAndFree(hr, tmpUserModelIdPtr);
|
||||
|
||||
hr = manifestApp.GetAppUserModelId(out var tmpUniqueIdentifier);
|
||||
UniqueIdentifier = AppxPackageHelper.CheckHRAndReturnOrThrow(hr, tmpUniqueIdentifier);
|
||||
manifestApp->GetAppUserModelId(out var tmpUniqueIdentifierPtr);
|
||||
UniqueIdentifier = ComFreeHelper.GetStringAndFree(hr, tmpUniqueIdentifierPtr);
|
||||
|
||||
hr = manifestApp.GetStringValue("DisplayName", out var tmpDisplayName);
|
||||
DisplayName = AppxPackageHelper.CheckHRAndReturnOrThrow(hr, tmpDisplayName);
|
||||
manifestApp->GetStringValue("DisplayName", out var tmpDisplayNamePtr);
|
||||
DisplayName = ComFreeHelper.GetStringAndFree(hr, tmpDisplayNamePtr);
|
||||
|
||||
hr = manifestApp.GetStringValue("Description", out var tmpDescription);
|
||||
Description = AppxPackageHelper.CheckHRAndReturnOrThrow(hr, tmpDescription);
|
||||
manifestApp->GetStringValue("Description", out var tmpDescriptionPtr);
|
||||
Description = ComFreeHelper.GetStringAndFree(hr, tmpDescriptionPtr);
|
||||
|
||||
hr = manifestApp.GetStringValue("BackgroundColor", out var tmpBackgroundColor);
|
||||
BackgroundColor = AppxPackageHelper.CheckHRAndReturnOrThrow(hr, tmpBackgroundColor);
|
||||
manifestApp->GetStringValue("BackgroundColor", out var tmpBackgroundColorPtr);
|
||||
BackgroundColor = ComFreeHelper.GetStringAndFree(hr, tmpBackgroundColorPtr);
|
||||
|
||||
hr = manifestApp.GetStringValue("EntryPoint", out var tmpEntryPoint);
|
||||
EntryPoint = AppxPackageHelper.CheckHRAndReturnOrThrow(hr, tmpEntryPoint);
|
||||
manifestApp->GetStringValue("EntryPoint", out var tmpEntryPointPtr);
|
||||
EntryPoint = ComFreeHelper.GetStringAndFree(hr, tmpEntryPointPtr);
|
||||
|
||||
Package = package ?? throw new ArgumentNullException(nameof(package));
|
||||
|
||||
@@ -166,7 +169,7 @@ public class UWPApplication : IProgram
|
||||
return false;
|
||||
}
|
||||
|
||||
internal string ResourceFromPri(string packageFullName, string resourceReference)
|
||||
internal unsafe string ResourceFromPri(string packageFullName, string resourceReference)
|
||||
{
|
||||
const string prefix = "ms-resource:";
|
||||
|
||||
@@ -200,30 +203,8 @@ public class UWPApplication : IProgram
|
||||
parsedFallback = prefix + "///" + key;
|
||||
}
|
||||
|
||||
var outBuffer = new StringBuilder(128);
|
||||
var source = $"@{{{packageFullName}? {parsed}}}";
|
||||
var capacity = (uint)outBuffer.Capacity;
|
||||
var hResult = SHLoadIndirectString(source, outBuffer, capacity, IntPtr.Zero);
|
||||
if (hResult != HRESULT.S_OK)
|
||||
if (string.IsNullOrEmpty(parsedFallback))
|
||||
{
|
||||
if (!string.IsNullOrEmpty(parsedFallback))
|
||||
{
|
||||
var sourceFallback = $"@{{{packageFullName}? {parsedFallback}}}";
|
||||
hResult = SHLoadIndirectString(sourceFallback, outBuffer, capacity, IntPtr.Zero);
|
||||
if (hResult == HRESULT.S_OK)
|
||||
{
|
||||
var loaded = outBuffer.ToString();
|
||||
if (!string.IsNullOrEmpty(loaded))
|
||||
{
|
||||
return loaded;
|
||||
}
|
||||
else
|
||||
{
|
||||
return string.Empty;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// https://github.com/Wox-launcher/Wox/issues/964
|
||||
// known hresult 2147942522:
|
||||
// 'Microsoft Corporation' violates pattern constraint of '\bms-resource:.{1,256}'.
|
||||
@@ -232,17 +213,40 @@ public class UWPApplication : IProgram
|
||||
// Microsoft.BingFoodAndDrink_3.0.4.336_x64__8wekyb3d8bbwe: ms-resource:AppDescription
|
||||
return string.Empty;
|
||||
}
|
||||
else
|
||||
|
||||
var capacity = 1024U;
|
||||
PWSTR outBuffer = new PWSTR((char*)(void*)Marshal.AllocHGlobal((int)capacity * sizeof(char)));
|
||||
var source = $"@{{{packageFullName}? {parsed}}}";
|
||||
void* reserved = null;
|
||||
|
||||
try
|
||||
{
|
||||
PInvoke.SHLoadIndirectString(source, outBuffer, capacity, ref reserved).ThrowOnFailure();
|
||||
|
||||
var loaded = outBuffer.ToString();
|
||||
if (!string.IsNullOrEmpty(loaded))
|
||||
return string.IsNullOrEmpty(loaded) ? string.Empty : loaded;
|
||||
}
|
||||
catch (Exception)
|
||||
{
|
||||
try
|
||||
{
|
||||
return loaded;
|
||||
var sourceFallback = $"@{{{packageFullName}?{parsedFallback}}}";
|
||||
PInvoke.SHLoadIndirectString(sourceFallback, outBuffer, capacity, ref reserved).ThrowOnFailure();
|
||||
var loaded = outBuffer.ToString();
|
||||
return string.IsNullOrEmpty(loaded) ? string.Empty : loaded;
|
||||
}
|
||||
else
|
||||
catch (Exception)
|
||||
{
|
||||
// ProgramLogger.Exception($"Unable to load resource {resourceReference} from {packageFullName}", new InvalidOperationException(), GetType(), packageFullName);
|
||||
return string.Empty;
|
||||
}
|
||||
finally
|
||||
{
|
||||
}
|
||||
}
|
||||
finally
|
||||
{
|
||||
Marshal.FreeHGlobal((IntPtr)outBuffer.Value);
|
||||
}
|
||||
}
|
||||
else
|
||||
@@ -258,13 +262,12 @@ public class UWPApplication : IProgram
|
||||
{ PackageVersion.Windows8, "SmallLogo" },
|
||||
};
|
||||
|
||||
internal string LogoUriFromManifest(IAppxManifestApplication app)
|
||||
internal unsafe string LogoUriFromManifest(IAppxManifestApplication* app)
|
||||
{
|
||||
if (_logoKeyFromVersion.TryGetValue(Package.Version, out var key))
|
||||
{
|
||||
var hr = app.GetStringValue(key, out var logoUriFromApp);
|
||||
_ = AppxPackageHelper.CheckHRAndReturnOrThrow(hr, logoUriFromApp);
|
||||
return logoUriFromApp;
|
||||
var hr = app->GetStringValue(key, out var logoUriFromAppPtr);
|
||||
return ComFreeHelper.GetStringAndFree(hr, logoUriFromAppPtr);
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -349,7 +352,7 @@ public class UWPApplication : IProgram
|
||||
var prefix = path.Substring(0, end);
|
||||
var paths = new List<string> { };
|
||||
const int appIconSize = 36;
|
||||
var targetSizes = new List<int> { 16, 24, 30, 36, 44, 60, 72, 96, 128, 180, 256 }.AsParallel();
|
||||
var targetSizes = new List<int> { 16, 24, 30, 36, 44, 60, 72, 96, 128, 180, 256 };
|
||||
var pathFactorPairs = new Dictionary<string, int>();
|
||||
|
||||
foreach (var factor in targetSizes)
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
// See the LICENSE file in the project root for more information.
|
||||
|
||||
using System;
|
||||
using System.Collections.Concurrent;
|
||||
using System.Collections.Generic;
|
||||
using System.ComponentModel.Design;
|
||||
using System.Diagnostics;
|
||||
@@ -841,18 +842,69 @@ public class Win32Program : IProgram
|
||||
var disabledProgramsList = settings.DisabledProgramSources;
|
||||
|
||||
// Get all paths but exclude all normal .Executables
|
||||
paths.UnionWith(sources
|
||||
.AsParallel()
|
||||
.SelectMany(source => source.IsEnabled ? source.GetPaths() : Enumerable.Empty<string>())
|
||||
.Where(programPath => disabledProgramsList.All(x => x.UniqueIdentifier != programPath))
|
||||
.Where(path => !ExecutableApplicationExtensions.Contains(Extension(path))));
|
||||
runCommandPaths.UnionWith(runCommandSources
|
||||
.AsParallel()
|
||||
.SelectMany(source => source.IsEnabled ? source.GetPaths() : Enumerable.Empty<string>())
|
||||
.Where(programPath => disabledProgramsList.All(x => x.UniqueIdentifier != programPath)));
|
||||
var pathBag = new ConcurrentBag<string>();
|
||||
|
||||
var programs = paths.AsParallel().Select(source => GetProgramFromPath(source));
|
||||
var runCommandPrograms = runCommandPaths.AsParallel().Select(source => GetRunCommandProgramFromPath(source));
|
||||
Parallel.ForEach(sources, source =>
|
||||
{
|
||||
if (!source.IsEnabled)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
foreach (var path in source.GetPaths())
|
||||
{
|
||||
if (disabledProgramsList.All(x => x.UniqueIdentifier != path) &&
|
||||
!ExecutableApplicationExtensions.Contains(Extension(path)))
|
||||
{
|
||||
pathBag.Add(path);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
paths.UnionWith(pathBag);
|
||||
|
||||
var runCommandPathBag = new ConcurrentBag<string>();
|
||||
|
||||
Parallel.ForEach(runCommandSources, source =>
|
||||
{
|
||||
if (!source.IsEnabled)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
foreach (var path in source.GetPaths())
|
||||
{
|
||||
if (disabledProgramsList.All(x => x.UniqueIdentifier != path))
|
||||
{
|
||||
runCommandPathBag.Add(path);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
runCommandPaths.UnionWith(runCommandPathBag);
|
||||
|
||||
var programsList = new ConcurrentBag<Win32Program>();
|
||||
Parallel.ForEach(paths, source =>
|
||||
{
|
||||
var program = GetProgramFromPath(source);
|
||||
if (program != null)
|
||||
{
|
||||
programsList.Add(program);
|
||||
}
|
||||
});
|
||||
|
||||
var runCommandProgramsList = new ConcurrentBag<Win32Program>();
|
||||
Parallel.ForEach(runCommandPaths, source =>
|
||||
{
|
||||
var program = GetRunCommandProgramFromPath(source);
|
||||
if (program != null)
|
||||
{
|
||||
runCommandProgramsList.Add(program);
|
||||
}
|
||||
});
|
||||
|
||||
var programs = programsList.ToList();
|
||||
var runCommandPrograms = runCommandProgramsList.ToList();
|
||||
|
||||
return DeduplicatePrograms(programs.Concat(runCommandPrograms).Where(program => program?.Valid == true));
|
||||
}
|
||||
|
||||
@@ -69,11 +69,6 @@ public class ListRepository<T> : IRepository<T>, IEnumerable<T>
|
||||
}
|
||||
}
|
||||
|
||||
public ParallelQuery<T> AsParallel()
|
||||
{
|
||||
return _items.Values.AsParallel();
|
||||
}
|
||||
|
||||
public bool Contains(T item)
|
||||
{
|
||||
if (item is not null)
|
||||
|
||||
@@ -6,8 +6,8 @@ using System;
|
||||
using System.Collections.Concurrent;
|
||||
using System.Collections.Generic;
|
||||
using System.Collections.ObjectModel;
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
using System.IO;
|
||||
using System.IO.Abstractions;
|
||||
using System.Threading.Tasks;
|
||||
using ManagedCommon;
|
||||
using Microsoft.CmdPal.Ext.Apps.Programs;
|
||||
@@ -15,11 +15,9 @@ using Win32Program = Microsoft.CmdPal.Ext.Apps.Programs.Win32Program;
|
||||
|
||||
namespace Microsoft.CmdPal.Ext.Apps.Storage;
|
||||
|
||||
[DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.All)]
|
||||
internal sealed partial class Win32ProgramRepository : ListRepository<Programs.Win32Program>, IProgramRepository
|
||||
{
|
||||
private static readonly IFileSystem FileSystem = new FileSystem();
|
||||
private static readonly IPath Path = FileSystem.Path;
|
||||
|
||||
private const string LnkExtension = ".lnk";
|
||||
private const string UrlExtension = ".url";
|
||||
|
||||
|
||||
@@ -0,0 +1,35 @@
|
||||
// Copyright (c) Microsoft Corporation
|
||||
// The Microsoft Corporation licenses this file to you under the MIT license.
|
||||
// See the LICENSE file in the project root for more information.
|
||||
|
||||
using System;
|
||||
using Windows.Win32;
|
||||
using Windows.Win32.Foundation;
|
||||
using Windows.Win32.System.Com;
|
||||
|
||||
namespace Microsoft.CmdPal.Ext.Apps.Utils;
|
||||
|
||||
public static class ComFreeHelper
|
||||
{
|
||||
internal static unsafe string GetStringAndFree(HRESULT hr, PWSTR ptr)
|
||||
{
|
||||
hr.ThrowOnFailure();
|
||||
try
|
||||
{
|
||||
return ptr.ToString();
|
||||
}
|
||||
finally
|
||||
{
|
||||
PInvoke.CoTaskMemFree(ptr);
|
||||
}
|
||||
}
|
||||
|
||||
public static unsafe void ComObjectRelease<T>(T* comPtr)
|
||||
where T : unmanaged
|
||||
{
|
||||
if (comPtr != null)
|
||||
{
|
||||
((IUnknown*)comPtr)->Release();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,157 +0,0 @@
|
||||
// Copyright (c) Microsoft Corporation
|
||||
// The Microsoft Corporation licenses this file to you under the MIT license.
|
||||
// See the LICENSE file in the project root for more information.
|
||||
|
||||
using System;
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Text;
|
||||
|
||||
namespace Microsoft.CmdPal.Ext.Apps.Utils;
|
||||
|
||||
[SuppressMessage("Interoperability", "CA1401:P/Invokes should not be visible", Justification = "We want plugins to share this NativeMethods class, instead of each one creating its own.")]
|
||||
public sealed class Native
|
||||
{
|
||||
[DllImport("shlwapi.dll", CharSet = CharSet.Unicode)]
|
||||
public static extern int SHLoadIndirectString(string pszSource, StringBuilder pszOutBuf, int cchOutBuf, nint ppvReserved);
|
||||
|
||||
[DllImport("shell32.dll", CharSet = CharSet.Unicode, SetLastError = true)]
|
||||
public static extern int SHCreateItemFromParsingName([MarshalAs(UnmanagedType.LPWStr)] string path, nint pbc, ref Guid riid, [MarshalAs(UnmanagedType.Interface)] out IShellItem shellItem);
|
||||
|
||||
[DllImport("shlwapi.dll", CharSet = CharSet.Unicode)]
|
||||
public static extern HRESULT SHCreateStreamOnFileEx(string fileName, STGM grfMode, uint attributes, bool create, System.Runtime.InteropServices.ComTypes.IStream reserved, out System.Runtime.InteropServices.ComTypes.IStream stream);
|
||||
|
||||
[DllImport("shlwapi.dll", CharSet = CharSet.Unicode)]
|
||||
public static extern HRESULT SHLoadIndirectString(string pszSource, StringBuilder pszOutBuf, uint cchOutBuf, nint ppvReserved);
|
||||
|
||||
public enum HRESULT : uint
|
||||
{
|
||||
/// <summary>
|
||||
/// Operation successful.
|
||||
/// </summary>
|
||||
S_OK = 0x00000000,
|
||||
|
||||
/// <summary>
|
||||
/// Operation successful. (negative condition/no operation)
|
||||
/// </summary>
|
||||
S_FALSE = 0x00000001,
|
||||
|
||||
/// <summary>
|
||||
/// Not implemented.
|
||||
/// </summary>
|
||||
E_NOTIMPL = 0x80004001,
|
||||
|
||||
/// <summary>
|
||||
/// No such interface supported.
|
||||
/// </summary>
|
||||
E_NOINTERFACE = 0x80004002,
|
||||
|
||||
/// <summary>
|
||||
/// Pointer that is not valid.
|
||||
/// </summary>
|
||||
E_POINTER = 0x80004003,
|
||||
|
||||
/// <summary>
|
||||
/// Operation aborted.
|
||||
/// </summary>
|
||||
E_ABORT = 0x80004004,
|
||||
|
||||
/// <summary>
|
||||
/// Unspecified failure.
|
||||
/// </summary>
|
||||
E_FAIL = 0x80004005,
|
||||
|
||||
/// <summary>
|
||||
/// Unexpected failure.
|
||||
/// </summary>
|
||||
E_UNEXPECTED = 0x8000FFFF,
|
||||
|
||||
/// <summary>
|
||||
/// General access denied error.
|
||||
/// </summary>
|
||||
E_ACCESSDENIED = 0x80070005,
|
||||
|
||||
/// <summary>
|
||||
/// Handle that is not valid.
|
||||
/// </summary>
|
||||
E_HANDLE = 0x80070006,
|
||||
|
||||
/// <summary>
|
||||
/// Failed to allocate necessary memory.
|
||||
/// </summary>
|
||||
E_OUTOFMEMORY = 0x8007000E,
|
||||
|
||||
/// <summary>
|
||||
/// One or more arguments are not valid.
|
||||
/// </summary>
|
||||
E_INVALIDARG = 0x80070057,
|
||||
|
||||
/// <summary>
|
||||
/// The operation was canceled by the user. (Error source 7 means Win32.)
|
||||
/// </summary>
|
||||
/// <SeeAlso href="https://learn.microsoft.com/windows/win32/debug/system-error-codes--1000-1299-"/>
|
||||
/// <SeeAlso href="https://en.wikipedia.org/wiki/HRESULT"/>
|
||||
E_CANCELLED = 0x800704C7,
|
||||
}
|
||||
|
||||
public static class ShellItemTypeConstants
|
||||
{
|
||||
/// <summary>
|
||||
/// Guid for type IShellItem.
|
||||
/// </summary>
|
||||
public static readonly Guid ShellItemGuid = new("43826d1e-e718-42ee-bc55-a1e261c37bfe");
|
||||
|
||||
/// <summary>
|
||||
/// Guid for type IShellItem2.
|
||||
/// </summary>
|
||||
public static readonly Guid ShellItem2Guid = new("7E9FB0D3-919F-4307-AB2E-9B1860310C93");
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// The following are ShellItem DisplayName types.
|
||||
/// </summary>
|
||||
[Flags]
|
||||
public enum SIGDN : uint
|
||||
{
|
||||
NORMALDISPLAY = 0,
|
||||
PARENTRELATIVEPARSING = 0x80018001,
|
||||
PARENTRELATIVEFORADDRESSBAR = 0x8001c001,
|
||||
DESKTOPABSOLUTEPARSING = 0x80028000,
|
||||
PARENTRELATIVEEDITING = 0x80031001,
|
||||
DESKTOPABSOLUTEEDITING = 0x8004c000,
|
||||
FILESYSPATH = 0x80058000,
|
||||
URL = 0x80068000,
|
||||
}
|
||||
|
||||
[ComImport]
|
||||
[InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
|
||||
[Guid("43826d1e-e718-42ee-bc55-a1e261c37bfe")]
|
||||
public interface IShellItem
|
||||
{
|
||||
void BindToHandler(
|
||||
nint pbc,
|
||||
[MarshalAs(UnmanagedType.LPStruct)] Guid bhid,
|
||||
[MarshalAs(UnmanagedType.LPStruct)] Guid riid,
|
||||
out nint ppv);
|
||||
|
||||
void GetParent(out IShellItem ppsi);
|
||||
|
||||
void GetDisplayName(SIGDN sigdnName, [MarshalAs(UnmanagedType.LPWStr)] out string ppszName);
|
||||
|
||||
void GetAttributes(uint sfgaoMask, out uint psfgaoAttribs);
|
||||
|
||||
void Compare(IShellItem psi, uint hint, out int piOrder);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// <see href="https://learn.microsoft.com/windows/win32/stg/stgm-constants">see all STGM values</see>
|
||||
/// </summary>
|
||||
[Flags]
|
||||
public enum STGM : long
|
||||
{
|
||||
READ = 0x00000000L,
|
||||
WRITE = 0x00000001L,
|
||||
READWRITE = 0x00000002L,
|
||||
CREATE = 0x00001000L,
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,30 @@
|
||||
// Copyright (c) Microsoft Corporation
|
||||
// The Microsoft Corporation licenses this file to you under the MIT license.
|
||||
// See the LICENSE file in the project root for more information.
|
||||
|
||||
using System;
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
namespace Microsoft.CmdPal.Ext.Apps.Utils;
|
||||
|
||||
public partial class SafeComHandle : SafeHandle
|
||||
{
|
||||
public SafeComHandle()
|
||||
: base(IntPtr.Zero, ownsHandle: true)
|
||||
{
|
||||
}
|
||||
|
||||
public SafeComHandle(IntPtr handle)
|
||||
: base(IntPtr.Zero, ownsHandle: true)
|
||||
{
|
||||
SetHandle(handle);
|
||||
}
|
||||
|
||||
public override bool IsInvalid => handle == IntPtr.Zero;
|
||||
|
||||
protected override bool ReleaseHandle()
|
||||
{
|
||||
var count = Marshal.Release(handle);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@@ -3,124 +3,17 @@
|
||||
// See the LICENSE file in the project root for more information.
|
||||
|
||||
using System;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Runtime.InteropServices.ComTypes;
|
||||
using System.Text;
|
||||
using ManagedCommon;
|
||||
using Windows.Win32;
|
||||
using Windows.Win32.Foundation;
|
||||
using Windows.Win32.System.Com;
|
||||
using Windows.Win32.UI.Shell;
|
||||
|
||||
namespace Microsoft.CmdPal.Ext.Apps.Utils;
|
||||
|
||||
public class ShellLinkHelper : IShellLinkHelper
|
||||
{
|
||||
[Flags]
|
||||
private enum SLGP_FLAGS
|
||||
{
|
||||
SLGP_SHORTPATH = 0x1,
|
||||
SLGP_UNCPRIORITY = 0x2,
|
||||
SLGP_RAWPATH = 0x4,
|
||||
}
|
||||
|
||||
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto)]
|
||||
[System.Diagnostics.CodeAnalysis.SuppressMessage("StyleCop.CSharp.NamingRules", "SA1307:Accessible fields should begin with upper-case letter", Justification = "Matching COM")]
|
||||
private struct WIN32_FIND_DATAW
|
||||
{
|
||||
public uint dwFileAttributes;
|
||||
public long ftCreationTime;
|
||||
public long ftLastAccessTime;
|
||||
public long ftLastWriteTime;
|
||||
public uint nFileSizeHigh;
|
||||
public uint nFileSizeLow;
|
||||
public uint dwReserved0;
|
||||
public uint dwReserved1;
|
||||
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 260)]
|
||||
public string cFileName;
|
||||
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 14)]
|
||||
public string cAlternateFileName;
|
||||
}
|
||||
|
||||
[Flags]
|
||||
[System.Diagnostics.CodeAnalysis.SuppressMessage("Naming", "CA1707:Identifiers should not contain underscores", Justification = "Implements COM Interface")]
|
||||
public enum SLR_FLAGS
|
||||
{
|
||||
SLR_NO_UI = 0x1,
|
||||
SLR_ANY_MATCH = 0x2,
|
||||
SLR_UPDATE = 0x4,
|
||||
SLR_NOUPDATE = 0x8,
|
||||
SLR_NOSEARCH = 0x10,
|
||||
SLR_NOTRACK = 0x20,
|
||||
SLR_NOLINKINFO = 0x40,
|
||||
SLR_INVOKE_MSI = 0x80,
|
||||
}
|
||||
|
||||
// Reference : http://www.pinvoke.net/default.aspx/Interfaces.IShellLinkW
|
||||
|
||||
// The IShellLink interface allows Shell links to be created, modified, and resolved
|
||||
[ComImport]
|
||||
[InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
|
||||
[Guid("000214F9-0000-0000-C000-000000000046")]
|
||||
private interface IShellLinkW
|
||||
{
|
||||
/// <summary>Retrieves the path and file name of a Shell link object</summary>
|
||||
void GetPath([Out, MarshalAs(UnmanagedType.LPWStr)] StringBuilder pszFile, int cchMaxPath, ref WIN32_FIND_DATAW pfd, SLGP_FLAGS fFlags);
|
||||
|
||||
/// <summary>Retrieves the list of item identifiers for a Shell link object</summary>
|
||||
void GetIDList(out nint ppidl);
|
||||
|
||||
/// <summary>Sets the pointer to an item identifier list (PIDL) for a Shell link object.</summary>
|
||||
void SetIDList(nint pidl);
|
||||
|
||||
/// <summary>Retrieves the description string for a Shell link object</summary>
|
||||
void GetDescription([Out, MarshalAs(UnmanagedType.LPWStr)] StringBuilder pszName, int cchMaxName);
|
||||
|
||||
/// <summary>Sets the description for a Shell link object. The description can be any application-defined string</summary>
|
||||
void SetDescription([MarshalAs(UnmanagedType.LPWStr)] string pszName);
|
||||
|
||||
/// <summary>Retrieves the name of the working directory for a Shell link object</summary>
|
||||
void GetWorkingDirectory([Out, MarshalAs(UnmanagedType.LPWStr)] StringBuilder pszDir, int cchMaxPath);
|
||||
|
||||
/// <summary>Sets the name of the working directory for a Shell link object</summary>
|
||||
void SetWorkingDirectory([MarshalAs(UnmanagedType.LPWStr)] string pszDir);
|
||||
|
||||
/// <summary>Retrieves the command-line arguments associated with a Shell link object</summary>
|
||||
void GetArguments([Out, MarshalAs(UnmanagedType.LPWStr)] StringBuilder pszArgs, int cchMaxPath);
|
||||
|
||||
/// <summary>Sets the command-line arguments for a Shell link object</summary>
|
||||
void SetArguments([MarshalAs(UnmanagedType.LPWStr)] string pszArgs);
|
||||
|
||||
/// <summary>Retrieves the hot key for a Shell link object</summary>
|
||||
void GetHotkey(out short pwHotkey);
|
||||
|
||||
/// <summary>Sets a hot key for a Shell link object</summary>
|
||||
void SetHotkey(short wHotkey);
|
||||
|
||||
/// <summary>Retrieves the show command for a Shell link object</summary>
|
||||
void GetShowCmd(out int piShowCmd);
|
||||
|
||||
/// <summary>Sets the show command for a Shell link object. The show command sets the initial show state of the window.</summary>
|
||||
void SetShowCmd(int iShowCmd);
|
||||
|
||||
/// <summary>Retrieves the location (path and index) of the icon for a Shell link object</summary>
|
||||
void GetIconLocation([Out, MarshalAs(UnmanagedType.LPWStr)] StringBuilder pszIconPath, int cchIconPath, out int piIcon);
|
||||
|
||||
/// <summary>Sets the location (path and index) of the icon for a Shell link object</summary>
|
||||
void SetIconLocation([MarshalAs(UnmanagedType.LPWStr)] string pszIconPath, int iIcon);
|
||||
|
||||
/// <summary>Sets the relative path to the Shell link object</summary>
|
||||
void SetRelativePath([MarshalAs(UnmanagedType.LPWStr)] string pszPathRel, int dwReserved);
|
||||
|
||||
/// <summary>Attempts to find the target of a Shell link, even if it has been moved or renamed</summary>
|
||||
void Resolve(ref nint hwnd, SLR_FLAGS fFlags);
|
||||
|
||||
/// <summary>Sets the path and file name of a Shell link object</summary>
|
||||
void SetPath([MarshalAs(UnmanagedType.LPWStr)] string pszFile);
|
||||
}
|
||||
|
||||
[ComImport]
|
||||
[Guid("00021401-0000-0000-C000-000000000046")]
|
||||
private class ShellLink
|
||||
{
|
||||
}
|
||||
|
||||
// Contains the description of the app
|
||||
public string Description { get; set; } = string.Empty;
|
||||
|
||||
@@ -130,60 +23,63 @@ public class ShellLinkHelper : IShellLinkHelper
|
||||
public bool HasArguments { get; set; }
|
||||
|
||||
// Retrieve the target path using Shell Link
|
||||
public string RetrieveTargetPath(string path)
|
||||
public unsafe string RetrieveTargetPath(string path)
|
||||
{
|
||||
var link = new ShellLink();
|
||||
const int STGM_READ = 0;
|
||||
|
||||
try
|
||||
{
|
||||
((IPersistFile)link).Load(path, STGM_READ);
|
||||
}
|
||||
catch (System.IO.FileNotFoundException ex)
|
||||
{
|
||||
Logger.LogError(ex.Message);
|
||||
return string.Empty;
|
||||
}
|
||||
|
||||
var hwnd = default(nint);
|
||||
((IShellLinkW)link).Resolve(ref hwnd, 0);
|
||||
|
||||
var target = string.Empty;
|
||||
const int MAX_PATH = 260;
|
||||
var buffer = new StringBuilder(MAX_PATH);
|
||||
IShellLinkW* link = null;
|
||||
|
||||
var data = default(WIN32_FIND_DATAW);
|
||||
((IShellLinkW)link).GetPath(buffer, buffer.Capacity, ref data, SLGP_FLAGS.SLGP_SHORTPATH);
|
||||
var target = buffer.ToString();
|
||||
PInvoke.CoCreateInstance(typeof(ShellLink).GUID, null, CLSCTX.CLSCTX_INPROC_SERVER, out link).ThrowOnFailure();
|
||||
using var linkHandle = new SafeComHandle((IntPtr)link);
|
||||
|
||||
const int STGMREAD = 0;
|
||||
|
||||
IPersistFile* persistFile = null;
|
||||
Guid iid = typeof(IPersistFile).GUID;
|
||||
((IUnknown*)link)->QueryInterface(&iid, (void**)&persistFile);
|
||||
if (persistFile != null)
|
||||
{
|
||||
using var persistFileHandle = new SafeComHandle((IntPtr)persistFile);
|
||||
try
|
||||
{
|
||||
persistFile->Load(path, STGMREAD);
|
||||
}
|
||||
catch (System.IO.FileNotFoundException)
|
||||
{
|
||||
// Log.Exception($"Failed to load {path}, {e.Message}", e, GetType());
|
||||
return string.Empty;
|
||||
}
|
||||
}
|
||||
|
||||
var hwnd = HWND.Null;
|
||||
const uint SLR_NO_UI = 0x1;
|
||||
link->Resolve(hwnd, SLR_NO_UI);
|
||||
|
||||
var buffer = stackalloc char[MAX_PATH];
|
||||
|
||||
var hr = link->GetPath((PWSTR)buffer, MAX_PATH, null, 0x1);
|
||||
|
||||
target = hr.Succeeded ? new string(buffer) : string.Empty;
|
||||
|
||||
// To set the app description
|
||||
if (!string.IsNullOrEmpty(target))
|
||||
{
|
||||
buffer = new StringBuilder(MAX_PATH);
|
||||
try
|
||||
{
|
||||
((IShellLinkW)link).GetDescription(buffer, MAX_PATH);
|
||||
Description = buffer.ToString();
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Logger.LogError(ex.Message);
|
||||
Description = string.Empty;
|
||||
}
|
||||
var descBuffer = stackalloc char[MAX_PATH];
|
||||
var desHr = link->GetDescription(descBuffer, MAX_PATH);
|
||||
Description = desHr.Succeeded ? new string(descBuffer) : string.Empty;
|
||||
|
||||
var argumentBuffer = new StringBuilder(MAX_PATH);
|
||||
((IShellLinkW)link).GetArguments(argumentBuffer, argumentBuffer.Capacity);
|
||||
Arguments = argumentBuffer.ToString();
|
||||
var argsBuffer = stackalloc char[MAX_PATH];
|
||||
var argHr = link->GetArguments(argsBuffer, MAX_PATH);
|
||||
|
||||
Arguments = argHr.Succeeded ? new string(argsBuffer) : string.Empty;
|
||||
|
||||
// Set variable to true if the program takes in any arguments
|
||||
if (argumentBuffer.Length != 0)
|
||||
if (Arguments.Length != 0)
|
||||
{
|
||||
HasArguments = true;
|
||||
}
|
||||
}
|
||||
|
||||
// To release unmanaged memory
|
||||
Marshal.ReleaseComObject(link);
|
||||
|
||||
return target;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4,7 +4,8 @@
|
||||
using System;
|
||||
using System.Collections.Concurrent;
|
||||
using System.IO;
|
||||
using static Microsoft.CmdPal.Ext.Apps.Utils.Native;
|
||||
using Windows.Win32;
|
||||
using Windows.Win32.UI.Shell;
|
||||
|
||||
namespace Microsoft.CmdPal.Ext.Apps.Utils;
|
||||
|
||||
@@ -23,7 +24,7 @@ public class ShellLocalization
|
||||
/// </summary>
|
||||
/// <param name="path">Path to the shell item (e. g. shortcut 'File Explorer.lnk').</param>
|
||||
/// <returns>The localized name as string or <see cref="string.Empty"/>.</returns>
|
||||
public string GetLocalizedName(string path)
|
||||
public unsafe string GetLocalizedName(string path)
|
||||
{
|
||||
var lowerInvariantPath = path.ToLowerInvariant();
|
||||
|
||||
@@ -33,18 +34,29 @@ public class ShellLocalization
|
||||
return value;
|
||||
}
|
||||
|
||||
var shellItemType = ShellItemTypeConstants.ShellItemGuid;
|
||||
var retCode = SHCreateItemFromParsingName(path, nint.Zero, ref shellItemType, out var shellItem);
|
||||
if (retCode != 0)
|
||||
void* shellItemPtrVoid = null;
|
||||
try
|
||||
{
|
||||
var retCode = PInvoke.SHCreateItemFromParsingName(path, null, typeof(IShellItem).GUID, out shellItemPtrVoid).ThrowOnFailure();
|
||||
using var shellItemHandle = new SafeComHandle((IntPtr)shellItemPtrVoid);
|
||||
IShellItem* shellItemPtr = (IShellItem*)shellItemPtrVoid;
|
||||
|
||||
var hr = shellItemPtr->GetDisplayName(SIGDN.SIGDN_NORMALDISPLAY, out var filenamePtr);
|
||||
|
||||
var filename = ComFreeHelper.GetStringAndFree(hr, filenamePtr);
|
||||
|
||||
if (filename == null)
|
||||
{
|
||||
return string.Empty;
|
||||
}
|
||||
|
||||
_ = _localizationCache.TryAdd(lowerInvariantPath, filename);
|
||||
return filename;
|
||||
}
|
||||
catch (Exception)
|
||||
{
|
||||
return string.Empty;
|
||||
}
|
||||
|
||||
shellItem.GetDisplayName(SIGDN.NORMALDISPLAY, out var filename);
|
||||
|
||||
_ = _localizationCache.TryAdd(lowerInvariantPath, filename);
|
||||
|
||||
return filename;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
||||
@@ -35,7 +35,7 @@ public static class CalculateHelper
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(input))
|
||||
{
|
||||
throw new ArgumentNullException(paramName: nameof(input));
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!RegValidExpressChar.IsMatch(input))
|
||||
|
||||
@@ -23,6 +23,9 @@ public static partial class QueryHelper
|
||||
CultureInfo inputCulture = settings.InputUseEnglishFormat ? new CultureInfo("en-us") : CultureInfo.CurrentCulture;
|
||||
CultureInfo outputCulture = settings.OutputUseEnglishFormat ? new CultureInfo("en-us") : CultureInfo.CurrentCulture;
|
||||
|
||||
// In case the user pastes a query with a leading =
|
||||
query = query.TrimStart('=');
|
||||
|
||||
// Happens if the user has only typed the action key so far
|
||||
if (string.IsNullOrEmpty(query))
|
||||
{
|
||||
@@ -32,6 +35,11 @@ public static partial class QueryHelper
|
||||
NumberTranslator translator = NumberTranslator.Create(inputCulture, new CultureInfo("en-US"));
|
||||
var input = translator.Translate(query.Normalize(NormalizationForm.FormKC));
|
||||
|
||||
if (string.IsNullOrWhiteSpace(input))
|
||||
{
|
||||
return ErrorHandler.OnError(isFallbackSearch, query, Properties.Resources.calculator_expression_empty);
|
||||
}
|
||||
|
||||
if (!CalculateHelper.InputValid(input))
|
||||
{
|
||||
return null;
|
||||
|
||||
@@ -132,6 +132,15 @@ namespace Microsoft.CmdPal.Ext.Calc.Properties {
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to Please enter an expression.
|
||||
/// </summary>
|
||||
public static string calculator_expression_empty {
|
||||
get {
|
||||
return ResourceManager.GetString("calculator_expression_empty", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to Expression wrong or incomplete.
|
||||
/// </summary>
|
||||
|
||||
@@ -199,4 +199,7 @@
|
||||
<data name="calculator_copy_binary" xml:space="preserve">
|
||||
<value>Copy binary</value>
|
||||
</data>
|
||||
<data name="calculator_expression_empty" xml:space="preserve">
|
||||
<value>Please enter an expression</value>
|
||||
</data>
|
||||
</root>
|
||||
@@ -30,6 +30,8 @@ internal static class ClipboardHelper
|
||||
(StandardDataFormats.Bitmap, ClipboardFormat.Image),
|
||||
];
|
||||
|
||||
private static readonly ClipboardThreadQueue ClipboardThreadQueue = new ClipboardThreadQueue();
|
||||
|
||||
internal static async Task<ClipboardFormat> GetAvailableClipboardFormatsAsync(DataPackageView clipboardData)
|
||||
{
|
||||
var availableClipboardFormats = DataFormats.Aggregate(
|
||||
@@ -58,9 +60,12 @@ internal static class ClipboardHelper
|
||||
try
|
||||
{
|
||||
// Clipboard.SetContentWithOptions(output, null);
|
||||
Clipboard.SetContent(output);
|
||||
Flush();
|
||||
ExtensionHost.LogMessage(new LogMessage() { Message = "Copied text to clipboard" });
|
||||
ClipboardThreadQueue.EnqueueTask(() =>
|
||||
{
|
||||
Clipboard.SetContent(output);
|
||||
Flush();
|
||||
ExtensionHost.LogMessage(new LogMessage() { Message = "Copied text to clipboard" });
|
||||
});
|
||||
}
|
||||
catch (COMException ex)
|
||||
{
|
||||
@@ -74,27 +79,32 @@ internal static class ClipboardHelper
|
||||
// TODO(stefan): For some reason Flush() fails from time to time when directly activated via hotkey.
|
||||
// Calling inside a loop makes it work.
|
||||
// Exception is: The operation is not permitted because the calling application is not the owner of the data on the clipboard.
|
||||
const int maxAttempts = 5;
|
||||
for (var i = 1; i <= maxAttempts; i++)
|
||||
ClipboardThreadQueue.EnqueueTask(() =>
|
||||
{
|
||||
try
|
||||
const int maxAttempts = 5;
|
||||
|
||||
for (var i = 1; i <= maxAttempts; i++)
|
||||
{
|
||||
Task.Run(Clipboard.Flush).Wait();
|
||||
return true;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
if (i == maxAttempts)
|
||||
try
|
||||
{
|
||||
ExtensionHost.LogMessage(new LogMessage()
|
||||
Task.Run(Clipboard.Flush).Wait();
|
||||
return;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
if (i == maxAttempts)
|
||||
{
|
||||
Message = $"{nameof(Clipboard)}.{nameof(Flush)}() failed: {ex}",
|
||||
});
|
||||
ExtensionHost.LogMessage(new LogMessage()
|
||||
{
|
||||
Message = $"{nameof(Clipboard)}.{nameof(Flush)}() failed: {ex}",
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
return false;
|
||||
// We cannot get the real result of the Flush() call here, as it is executed in a different thread.
|
||||
return true;
|
||||
}
|
||||
|
||||
private static async Task<bool> FlushAsync() => await Task.Run(Flush);
|
||||
@@ -105,7 +115,7 @@ internal static class ClipboardHelper
|
||||
|
||||
DataPackage output = new();
|
||||
output.SetStorageItems([storageFile]);
|
||||
Clipboard.SetContent(output);
|
||||
ClipboardThreadQueue.EnqueueTask(() => Clipboard.SetContent(output));
|
||||
|
||||
await FlushAsync();
|
||||
}
|
||||
@@ -118,7 +128,7 @@ internal static class ClipboardHelper
|
||||
{
|
||||
DataPackage output = new();
|
||||
output.SetBitmap(image);
|
||||
Clipboard.SetContentWithOptions(output, null);
|
||||
ClipboardThreadQueue.EnqueueTask(() => Clipboard.SetContentWithOptions(output, null));
|
||||
|
||||
Flush();
|
||||
}
|
||||
|
||||
@@ -0,0 +1,74 @@
|
||||
// Copyright (c) Microsoft Corporation
|
||||
// The Microsoft Corporation licenses this file to you under the MIT license.
|
||||
// See the LICENSE file in the project root for more information.
|
||||
|
||||
using System;
|
||||
using System.Collections.Concurrent;
|
||||
using System.Threading;
|
||||
using Microsoft.CommandPalette.Extensions.Toolkit;
|
||||
|
||||
namespace Microsoft.CmdPal.Ext.ClipboardHistory.Helpers;
|
||||
|
||||
public partial class ClipboardThreadQueue : IDisposable
|
||||
{
|
||||
private readonly Thread _thread;
|
||||
private readonly ConcurrentQueue<Action> _taskQueue = new ConcurrentQueue<Action>();
|
||||
private readonly AutoResetEvent _taskAvailable = new AutoResetEvent(false);
|
||||
private readonly CancellationTokenSource cancellationToken = new CancellationTokenSource();
|
||||
|
||||
public ClipboardThreadQueue()
|
||||
{
|
||||
_thread = new Thread(() =>
|
||||
{
|
||||
var hr = NativeMethods.CoInitialize(IntPtr.Zero);
|
||||
if (hr != 0)
|
||||
{
|
||||
ExtensionHost.LogMessage($"CoInitialize failed with HRESULT: {hr}");
|
||||
}
|
||||
|
||||
while (true)
|
||||
{
|
||||
_taskAvailable.WaitOne();
|
||||
|
||||
if (cancellationToken.IsCancellationRequested)
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
while (_taskQueue.TryDequeue(out var task))
|
||||
{
|
||||
try
|
||||
{
|
||||
task();
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
ExtensionHost.LogMessage($"Error executing task in ClipboardThreadQueue: {ex.Message}");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
NativeMethods.CoUninitialize();
|
||||
});
|
||||
|
||||
_thread.SetApartmentState(ApartmentState.STA);
|
||||
_thread.IsBackground = true;
|
||||
_thread.Start();
|
||||
}
|
||||
|
||||
public void EnqueueTask(Action task)
|
||||
{
|
||||
_taskQueue.Enqueue(task);
|
||||
_taskAvailable.Set();
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
cancellationToken.Cancel();
|
||||
_taskAvailable.Set();
|
||||
_thread.Join(); // Wait for the thread to finish processing tasks
|
||||
|
||||
_taskAvailable.Dispose();
|
||||
GC.SuppressFinalize(this);
|
||||
}
|
||||
}
|
||||
@@ -8,7 +8,7 @@ using Windows.Foundation;
|
||||
|
||||
namespace Microsoft.CmdPal.Ext.ClipboardHistory.Helpers;
|
||||
|
||||
internal static class NativeMethods
|
||||
public static partial class NativeMethods
|
||||
{
|
||||
[StructLayout(LayoutKind.Sequential)]
|
||||
[System.Diagnostics.CodeAnalysis.SuppressMessage("StyleCop.CSharp.NamingRules", "SA1307:Accessible fields should begin with upper-case letter", Justification = "Matching Native Structure")]
|
||||
@@ -98,4 +98,10 @@ internal static class NativeMethods
|
||||
|
||||
[DllImport("user32.dll")]
|
||||
internal static extern bool GetCursorPos(out PointInter lpPoint);
|
||||
|
||||
[LibraryImport("ole32.dll")]
|
||||
internal static partial int CoInitialize(IntPtr pvReserved);
|
||||
|
||||
[LibraryImport("ole32.dll")]
|
||||
internal static partial void CoUninitialize();
|
||||
}
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
// See the LICENSE file in the project root for more information.
|
||||
|
||||
using System;
|
||||
using System.Runtime.CompilerServices;
|
||||
using System.Runtime.InteropServices;
|
||||
using ManagedCommon;
|
||||
using Microsoft.CmdPal.Ext.Indexer.Data;
|
||||
@@ -13,6 +14,7 @@ using Windows.Win32;
|
||||
using Windows.Win32.Foundation;
|
||||
using Windows.Win32.UI.Shell;
|
||||
using Windows.Win32.UI.WindowsAndMessaging;
|
||||
using static Microsoft.CmdPal.Ext.Indexer.Native.NativeMethods;
|
||||
|
||||
namespace Microsoft.CmdPal.Ext.Indexer.Commands;
|
||||
|
||||
@@ -27,19 +29,16 @@ internal sealed partial class OpenPropertiesCommand : InvokableCommand
|
||||
|
||||
try
|
||||
{
|
||||
var filenamePCWSTR = new PCWSTR((char*)filenamePtr);
|
||||
var propertiesPCWSTR = new PCWSTR((char*)propertiesPtr);
|
||||
|
||||
var info = new SHELLEXECUTEINFOW
|
||||
{
|
||||
cbSize = (uint)Marshal.SizeOf<SHELLEXECUTEINFOW>(),
|
||||
lpVerb = propertiesPCWSTR,
|
||||
lpFile = filenamePCWSTR,
|
||||
cbSize = (uint)sizeof(SHELLEXECUTEINFOW),
|
||||
lpVerb = propertiesPtr,
|
||||
lpFile = filenamePtr,
|
||||
nShow = (int)SHOW_WINDOW_CMD.SW_SHOW,
|
||||
fMask = NativeHelpers.SEEMASKINVOKEIDLIST,
|
||||
};
|
||||
|
||||
return PInvoke.ShellExecuteEx(ref info);
|
||||
return ShellExecuteEx(ref info);
|
||||
}
|
||||
finally
|
||||
{
|
||||
|
||||
@@ -2,6 +2,8 @@
|
||||
// The Microsoft Corporation licenses this file to you under the MIT license.
|
||||
// See the LICENSE file in the project root for more information.
|
||||
|
||||
using System;
|
||||
using System.Runtime.CompilerServices;
|
||||
using System.Runtime.InteropServices;
|
||||
using Microsoft.CmdPal.Ext.Indexer.Data;
|
||||
using Microsoft.CmdPal.Ext.Indexer.Native;
|
||||
@@ -11,6 +13,7 @@ using Windows.Win32;
|
||||
using Windows.Win32.Foundation;
|
||||
using Windows.Win32.UI.Shell;
|
||||
using Windows.Win32.UI.WindowsAndMessaging;
|
||||
using static Microsoft.CmdPal.Ext.Indexer.Native.NativeMethods;
|
||||
|
||||
namespace Microsoft.CmdPal.Ext.Indexer.Commands;
|
||||
|
||||
@@ -25,19 +28,16 @@ internal sealed partial class OpenWithCommand : InvokableCommand
|
||||
|
||||
try
|
||||
{
|
||||
var filenamePCWSTR = new PCWSTR((char*)filenamePtr);
|
||||
var verbPCWSTR = new PCWSTR((char*)verbPtr);
|
||||
|
||||
var info = new SHELLEXECUTEINFOW
|
||||
{
|
||||
cbSize = (uint)Marshal.SizeOf<SHELLEXECUTEINFOW>(),
|
||||
lpVerb = verbPCWSTR,
|
||||
lpFile = filenamePCWSTR,
|
||||
cbSize = (uint)sizeof(SHELLEXECUTEINFOW),
|
||||
lpVerb = verbPtr,
|
||||
lpFile = filenamePtr,
|
||||
nShow = (int)SHOW_WINDOW_CMD.SW_SHOWNORMAL,
|
||||
fMask = NativeHelpers.SEEMASKINVOKEIDLIST,
|
||||
};
|
||||
|
||||
return PInvoke.ShellExecuteEx(ref info);
|
||||
return ShellExecuteEx(ref info);
|
||||
}
|
||||
finally
|
||||
{
|
||||
|
||||
@@ -3,17 +3,17 @@
|
||||
// See the LICENSE file in the project root for more information.
|
||||
|
||||
using System;
|
||||
using System.Runtime.CompilerServices;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Runtime.InteropServices.Marshalling;
|
||||
using ManagedCommon;
|
||||
using Windows.Win32;
|
||||
using Windows.Win32.System.Com;
|
||||
using Windows.Win32.System.Search;
|
||||
using Microsoft.CmdPal.Ext.Indexer.Indexer.SystemSearch;
|
||||
using Microsoft.CmdPal.Ext.Indexer.Native;
|
||||
|
||||
namespace Microsoft.CmdPal.Ext.Indexer.Indexer;
|
||||
|
||||
internal static class DataSourceManager
|
||||
{
|
||||
private static readonly Guid CLSIDCollatorDataSource = new("9E175B8B-F52A-11D8-B9A5-505054503030");
|
||||
|
||||
private static IDBInitialize _dataSource;
|
||||
|
||||
public static IDBInitialize GetDataSource()
|
||||
@@ -28,22 +28,36 @@ internal static class DataSourceManager
|
||||
|
||||
private static bool InitializeDataSource()
|
||||
{
|
||||
var hr = PInvoke.CoCreateInstance(CLSIDCollatorDataSource, null, CLSCTX.CLSCTX_INPROC_SERVER, typeof(IDBInitialize).GUID, out var dataSourceObj);
|
||||
var riid = typeof(IDBInitialize).GUID;
|
||||
var hr = NativeMethods.CoCreateInstance(ref Unsafe.AsRef(in NativeHelpers.CsWin32GUID.CLSIDCollatorDataSource), IntPtr.Zero, NativeHelpers.CLSCTXINPROCALL, ref riid, out var dataSourceObjPtr);
|
||||
if (hr != 0)
|
||||
{
|
||||
Logger.LogError("CoCreateInstance failed: " + hr);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (dataSourceObj == null)
|
||||
if (dataSourceObjPtr == IntPtr.Zero)
|
||||
{
|
||||
Logger.LogError("CoCreateInstance failed: dataSourceObjPtr is null");
|
||||
return false;
|
||||
}
|
||||
|
||||
var comWrappers = new StrategyBasedComWrappers();
|
||||
_dataSource = (IDBInitialize)comWrappers.GetOrCreateObjectForComInstance(dataSourceObjPtr, CreateObjectFlags.None);
|
||||
|
||||
if (_dataSource == null)
|
||||
{
|
||||
Logger.LogError("CoCreateInstance failed: dataSourceObj is null");
|
||||
return false;
|
||||
}
|
||||
|
||||
_dataSource = (IDBInitialize)dataSourceObj;
|
||||
_dataSource.Initialize();
|
||||
|
||||
if (dataSourceObjPtr != IntPtr.Zero)
|
||||
{
|
||||
Marshal.Release(dataSourceObjPtr);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,6 +3,8 @@
|
||||
// See the LICENSE file in the project root for more information.
|
||||
|
||||
using System.Runtime.InteropServices;
|
||||
using Microsoft.CmdPal.Ext.Indexer.Indexer.SystemSearch;
|
||||
using Microsoft.CmdPal.Ext.Indexer.Native;
|
||||
using Windows.Win32.Storage.IndexServer;
|
||||
using Windows.Win32.System.Com.StructuredStorage;
|
||||
|
||||
@@ -16,6 +18,6 @@ internal struct DBPROP
|
||||
public uint dwOptions;
|
||||
public uint dwStatus;
|
||||
public DBID colid;
|
||||
public PROPVARIANT vValue;
|
||||
public PropVariant vValue;
|
||||
#pragma warning restore SA1307 // Accessible fields should begin with upper-case letter
|
||||
}
|
||||
|
||||
@@ -4,40 +4,38 @@
|
||||
|
||||
using System;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Runtime.InteropServices.Marshalling;
|
||||
|
||||
namespace Microsoft.CmdPal.Ext.Indexer.Indexer.OleDB;
|
||||
|
||||
[ComImport]
|
||||
[Guid("0c733a7c-2a1c-11ce-ade5-00aa0044773d")]
|
||||
[InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
|
||||
public interface IRowset
|
||||
[GeneratedComInterface]
|
||||
public partial interface IRowset
|
||||
{
|
||||
[PreserveSig]
|
||||
int AddRefRows(
|
||||
void AddRefRows(
|
||||
uint cRows,
|
||||
[In, MarshalAs(UnmanagedType.LPArray, SizeParamIndex = 0)] IntPtr[] rghRows,
|
||||
[Out, MarshalAs(UnmanagedType.LPArray, SizeParamIndex = 0)] uint[] rgRefCounts,
|
||||
[Out, MarshalAs(UnmanagedType.LPArray, SizeParamIndex = 0)] int[] rgRowStatus);
|
||||
[MarshalAs(UnmanagedType.LPArray, SizeParamIndex = 0)] IntPtr[] rghRows,
|
||||
[MarshalAs(UnmanagedType.LPArray, SizeParamIndex = 0)] uint[] rgRefCounts,
|
||||
[MarshalAs(UnmanagedType.LPArray, SizeParamIndex = 0)] int[] rgRowStatus);
|
||||
|
||||
[PreserveSig]
|
||||
int GetData(
|
||||
void GetData(
|
||||
IntPtr hRow,
|
||||
IntPtr hAccessor,
|
||||
IntPtr pData);
|
||||
|
||||
[PreserveSig]
|
||||
int GetNextRows(
|
||||
void GetNextRows(
|
||||
IntPtr hReserved,
|
||||
long lRowsOffset,
|
||||
long cRows,
|
||||
out uint pcRowsObtained,
|
||||
out IntPtr prghRows);
|
||||
|
||||
[PreserveSig]
|
||||
int ReleaseRows(
|
||||
void ReleaseRows(
|
||||
uint cRows,
|
||||
[In, MarshalAs(UnmanagedType.LPArray, SizeParamIndex = 0)] IntPtr[] rghRows,
|
||||
[MarshalAs(UnmanagedType.LPArray, SizeParamIndex = 0)] IntPtr[] rghRows,
|
||||
IntPtr rgRowOptions,
|
||||
[Out, MarshalAs(UnmanagedType.LPArray, SizeParamIndex = 0)] uint[] rgRefCounts,
|
||||
[Out, MarshalAs(UnmanagedType.LPArray, SizeParamIndex = 0)] int[] rgRowStatus);
|
||||
[MarshalAs(UnmanagedType.LPArray, SizeParamIndex = 0)] uint[] rgRefCounts,
|
||||
[MarshalAs(UnmanagedType.LPArray, SizeParamIndex = 0)] int[] rgRowStatus);
|
||||
|
||||
void RestartPosition(nuint hReserved);
|
||||
}
|
||||
|
||||
@@ -4,29 +4,29 @@
|
||||
|
||||
using System;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Runtime.InteropServices.Marshalling;
|
||||
|
||||
namespace Microsoft.CmdPal.Ext.Indexer.Indexer.OleDB;
|
||||
|
||||
[ComImport]
|
||||
[Guid("0C733A55-2A1C-11CE-ADE5-00AA0044773D")]
|
||||
[InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
|
||||
public interface IRowsetInfo
|
||||
[GeneratedComInterface]
|
||||
public partial interface IRowsetInfo
|
||||
{
|
||||
[PreserveSig]
|
||||
int GetProperties(
|
||||
uint cPropertyIDSets,
|
||||
[In, MarshalAs(UnmanagedType.LPArray, SizeParamIndex = 0)] DBPROPIDSET[] rgPropertyIDSets,
|
||||
[MarshalAs(UnmanagedType.LPArray, SizeParamIndex = 0)] DBPROPIDSET[] rgPropertyIDSets,
|
||||
out ulong pcPropertySets,
|
||||
out IntPtr prgPropertySets);
|
||||
|
||||
[PreserveSig]
|
||||
int GetReferencedRowset(
|
||||
uint iOrdinal,
|
||||
[In] ref Guid riid,
|
||||
[Out, MarshalAs(UnmanagedType.Interface)] out object ppReferencedRowset);
|
||||
ref Guid riid,
|
||||
[MarshalAs(UnmanagedType.Interface)] out object ppReferencedRowset);
|
||||
|
||||
[PreserveSig]
|
||||
int GetSpecification(
|
||||
[In] ref Guid riid,
|
||||
[Out, MarshalAs(UnmanagedType.Interface)] out object ppSpecification);
|
||||
ref Guid riid,
|
||||
[MarshalAs(UnmanagedType.Interface)] out object ppSpecification);
|
||||
}
|
||||
|
||||
@@ -8,12 +8,10 @@ using System.Runtime.InteropServices;
|
||||
using System.Threading;
|
||||
using ManagedCommon;
|
||||
using Microsoft.CmdPal.Ext.Indexer.Indexer.OleDB;
|
||||
using Microsoft.CmdPal.Ext.Indexer.Indexer.SystemSearch;
|
||||
using Microsoft.CmdPal.Ext.Indexer.Indexer.Utils;
|
||||
using Microsoft.CmdPal.Ext.Indexer.Native;
|
||||
using Windows.Win32;
|
||||
using Windows.Win32.System.Com;
|
||||
using Windows.Win32.System.Search;
|
||||
using Windows.Win32.UI.Shell.PropertiesSystem;
|
||||
using static Microsoft.CmdPal.Ext.Indexer.Native.NativeHelpers;
|
||||
|
||||
namespace Microsoft.CmdPal.Ext.Indexer.Indexer;
|
||||
|
||||
@@ -120,11 +118,6 @@ internal sealed partial class SearchQuery : IDisposable
|
||||
// We need to generate a search query string with the search text the user entered above
|
||||
if (currentRowset != null)
|
||||
{
|
||||
if (reuseRowset != null)
|
||||
{
|
||||
Marshal.ReleaseComObject(reuseRowset);
|
||||
}
|
||||
|
||||
// We have a previous rowset, this means the user is typing and we should store this
|
||||
// recapture the where ID from this so the next ExecuteSync call will be faster
|
||||
reuseRowset = currentRowset;
|
||||
@@ -148,13 +141,12 @@ internal sealed partial class SearchQuery : IDisposable
|
||||
|
||||
private bool HandleRow(IGetRow getRow, nuint rowHandle)
|
||||
{
|
||||
object propertyStorePtr = null;
|
||||
|
||||
try
|
||||
{
|
||||
getRow.GetRowFromHROW(null, rowHandle, typeof(IPropertyStore).GUID, out propertyStorePtr);
|
||||
var riid = CsWin32GUID.PropertyStore;
|
||||
|
||||
getRow.GetRowFromHROW(null, rowHandle, ref riid, out var propertyStore);
|
||||
|
||||
var propertyStore = (IPropertyStore)propertyStorePtr;
|
||||
if (propertyStore == null)
|
||||
{
|
||||
Logger.LogError("Failed to get IPropertyStore interface");
|
||||
@@ -176,14 +168,6 @@ internal sealed partial class SearchQuery : IDisposable
|
||||
Logger.LogError("Error handling row", ex);
|
||||
return false;
|
||||
}
|
||||
finally
|
||||
{
|
||||
// Ensure the COM object is released if not returned
|
||||
if (propertyStorePtr != null)
|
||||
{
|
||||
Marshal.ReleaseComObject(propertyStorePtr);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public bool FetchRows(int offset, int limit)
|
||||
@@ -194,16 +178,17 @@ internal sealed partial class SearchQuery : IDisposable
|
||||
return false;
|
||||
}
|
||||
|
||||
if (currentRowset is not IGetRow)
|
||||
IGetRow getRow = null;
|
||||
|
||||
try
|
||||
{
|
||||
getRow = (IGetRow)currentRowset;
|
||||
}
|
||||
catch (Exception)
|
||||
{
|
||||
Logger.LogInfo("Reset the current rowset");
|
||||
ExecuteSyncInternal();
|
||||
}
|
||||
|
||||
if (currentRowset is not IGetRow getRow)
|
||||
{
|
||||
Logger.LogError("Rowset does not support IGetRow interface");
|
||||
return false;
|
||||
getRow = (IGetRow)currentRowset;
|
||||
}
|
||||
|
||||
uint rowCountReturned;
|
||||
@@ -211,12 +196,7 @@ internal sealed partial class SearchQuery : IDisposable
|
||||
|
||||
try
|
||||
{
|
||||
var res = currentRowset.GetNextRows(IntPtr.Zero, offset, limit, out rowCountReturned, out prghRows);
|
||||
if (res < 0)
|
||||
{
|
||||
Logger.LogError($"Error fetching rows: {res}");
|
||||
return false;
|
||||
}
|
||||
currentRowset.GetNextRows(IntPtr.Zero, offset, limit, out rowCountReturned, out prghRows);
|
||||
|
||||
if (rowCountReturned == 0)
|
||||
{
|
||||
@@ -237,11 +217,7 @@ internal sealed partial class SearchQuery : IDisposable
|
||||
}
|
||||
}
|
||||
|
||||
res = currentRowset.ReleaseRows(rowCountReturned, rowHandles, IntPtr.Zero, null, null);
|
||||
if (res != 0)
|
||||
{
|
||||
Logger.LogError($"Error releasing rows: {res}");
|
||||
}
|
||||
currentRowset.ReleaseRows(rowCountReturned, rowHandles, IntPtr.Zero, null, null);
|
||||
|
||||
Marshal.FreeCoTaskMem(prghRows);
|
||||
prghRows = IntPtr.Zero;
|
||||
@@ -268,11 +244,6 @@ internal sealed partial class SearchQuery : IDisposable
|
||||
var rowset = ExecuteCommand(queryStr);
|
||||
if (rowset != null)
|
||||
{
|
||||
if (reuseRowset != null)
|
||||
{
|
||||
Marshal.ReleaseComObject(reuseRowset);
|
||||
}
|
||||
|
||||
reuseRowset = rowset;
|
||||
reuseWhereID = GetReuseWhereId(reuseRowset);
|
||||
}
|
||||
@@ -280,110 +251,50 @@ internal sealed partial class SearchQuery : IDisposable
|
||||
|
||||
private unsafe IRowset ExecuteCommand(string queryStr)
|
||||
{
|
||||
object sessionPtr = null;
|
||||
object commandPtr = null;
|
||||
if (string.IsNullOrEmpty(queryStr))
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
var session = (IDBCreateSession)DataSourceManager.GetDataSource();
|
||||
session.CreateSession(null, typeof(IDBCreateCommand).GUID, out sessionPtr);
|
||||
if (sessionPtr == null)
|
||||
var guid = typeof(IDBCreateCommand).GUID;
|
||||
session.CreateSession(IntPtr.Zero, ref guid, out var ppDBSession);
|
||||
|
||||
if (ppDBSession == null)
|
||||
{
|
||||
Logger.LogError("CreateSession failed");
|
||||
return null;
|
||||
}
|
||||
|
||||
var createCommand = (IDBCreateCommand)sessionPtr;
|
||||
createCommand.CreateCommand(null, typeof(ICommandText).GUID, out commandPtr);
|
||||
if (commandPtr == null)
|
||||
{
|
||||
Logger.LogError("CreateCommand failed");
|
||||
return null;
|
||||
}
|
||||
var createCommand = (IDBCreateCommand)ppDBSession;
|
||||
guid = typeof(ICommandText).GUID;
|
||||
createCommand.CreateCommand(IntPtr.Zero, ref guid, out ICommandText commandText);
|
||||
|
||||
var commandText = (ICommandText)commandPtr;
|
||||
if (commandText == null)
|
||||
{
|
||||
Logger.LogError("Failed to get ICommandText interface");
|
||||
return null;
|
||||
}
|
||||
|
||||
commandText.SetCommandText(in NativeHelpers.OleDb.DbGuidDefault, queryStr);
|
||||
commandText.Execute(null, typeof(IRowset).GUID, null, null, out var rowsetPointer);
|
||||
var riid = NativeHelpers.OleDb.DbGuidDefault;
|
||||
|
||||
return rowsetPointer as IRowset;
|
||||
var irowSetRiid = typeof(IRowset).GUID;
|
||||
|
||||
commandText.SetCommandText(ref riid, queryStr);
|
||||
commandText.Execute(null, ref irowSetRiid, null, out var pcRowsAffected, out var rowsetPointer);
|
||||
|
||||
return rowsetPointer;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Logger.LogError("Unexpected error.", ex);
|
||||
return null;
|
||||
}
|
||||
finally
|
||||
{
|
||||
// Release the command pointer
|
||||
if (commandPtr != null)
|
||||
{
|
||||
Marshal.ReleaseComObject(commandPtr);
|
||||
}
|
||||
|
||||
// Release the session pointer
|
||||
if (sessionPtr != null)
|
||||
{
|
||||
Marshal.ReleaseComObject(sessionPtr);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private IRowsetInfo GetRowsetInfo(IRowset rowset)
|
||||
{
|
||||
if (rowset == null)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
var rowsetPtr = IntPtr.Zero;
|
||||
var rowsetInfoPtr = IntPtr.Zero;
|
||||
|
||||
try
|
||||
{
|
||||
// Get the IUnknown pointer for the IRowset object
|
||||
rowsetPtr = Marshal.GetIUnknownForObject(rowset);
|
||||
|
||||
// Query for IRowsetInfo interface
|
||||
var rowsetInfoGuid = typeof(IRowsetInfo).GUID;
|
||||
var res = Marshal.QueryInterface(rowsetPtr, in rowsetInfoGuid, out rowsetInfoPtr);
|
||||
if (res != 0)
|
||||
{
|
||||
Logger.LogError($"Error getting IRowsetInfo interface: {res}");
|
||||
return null;
|
||||
}
|
||||
|
||||
// Marshal the interface pointer to the actual IRowsetInfo object
|
||||
var rowsetInfo = (IRowsetInfo)Marshal.GetObjectForIUnknown(rowsetInfoPtr);
|
||||
return rowsetInfo;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Logger.LogError($"Exception occurred while getting IRowsetInfo. ", ex);
|
||||
return null;
|
||||
}
|
||||
finally
|
||||
{
|
||||
// Release the IRowsetInfo pointer if it was obtained
|
||||
if (rowsetInfoPtr != IntPtr.Zero)
|
||||
{
|
||||
Marshal.Release(rowsetInfoPtr); // Release the IRowsetInfo pointer
|
||||
}
|
||||
|
||||
// Release the IUnknown pointer for the IRowset object
|
||||
if (rowsetPtr != IntPtr.Zero)
|
||||
{
|
||||
Marshal.Release(rowsetPtr);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private DBPROP? GetPropset(IRowsetInfo rowsetInfo)
|
||||
private unsafe DBPROP? GetPropset(IRowsetInfo rowsetInfo)
|
||||
{
|
||||
var prgPropSetsPtr = IntPtr.Zero;
|
||||
|
||||
@@ -403,16 +314,15 @@ internal sealed partial class SearchQuery : IDisposable
|
||||
return null;
|
||||
}
|
||||
|
||||
var firstPropSetPtr = new IntPtr(prgPropSetsPtr.ToInt64());
|
||||
var propSet = Marshal.PtrToStructure<DBPROPSET>(firstPropSetPtr);
|
||||
var firstPropSetPtr = (DBPROPSET*)prgPropSetsPtr.ToInt64();
|
||||
var propSet = *firstPropSetPtr;
|
||||
if (propSet.cProperties == 0 || propSet.rgProperties == IntPtr.Zero)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
var propPtr = new IntPtr(propSet.rgProperties.ToInt64());
|
||||
var prop = Marshal.PtrToStructure<DBPROP>(propPtr);
|
||||
return prop;
|
||||
var propPtr = (DBPROP*)propSet.rgProperties.ToInt64();
|
||||
return *propPtr;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
@@ -431,7 +341,8 @@ internal sealed partial class SearchQuery : IDisposable
|
||||
|
||||
private uint GetReuseWhereId(IRowset rowset)
|
||||
{
|
||||
var rowsetInfo = GetRowsetInfo(rowset);
|
||||
var rowsetInfo = (IRowsetInfo)rowset;
|
||||
|
||||
if (rowsetInfo == null)
|
||||
{
|
||||
return 0;
|
||||
@@ -443,9 +354,9 @@ internal sealed partial class SearchQuery : IDisposable
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (prop?.vValue.Anonymous.Anonymous.vt == VARENUM.VT_UI4)
|
||||
if (prop?.vValue.VarType == VarEnum.VT_UI4)
|
||||
{
|
||||
var value = prop?.vValue.Anonymous.Anonymous.Anonymous.ulVal;
|
||||
var value = prop?.vValue._ulong;
|
||||
return (uint)value;
|
||||
}
|
||||
|
||||
@@ -462,18 +373,6 @@ internal sealed partial class SearchQuery : IDisposable
|
||||
Marshal.FreeCoTaskMem(dbPropIdSet.rgPropertyIDs);
|
||||
}
|
||||
|
||||
if (reuseRowset != null)
|
||||
{
|
||||
Marshal.ReleaseComObject(reuseRowset);
|
||||
reuseRowset = null;
|
||||
}
|
||||
|
||||
if (currentRowset != null)
|
||||
{
|
||||
Marshal.ReleaseComObject(currentRowset);
|
||||
currentRowset = null;
|
||||
}
|
||||
|
||||
queryCompletedEvent?.Dispose();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,12 +3,11 @@
|
||||
// See the LICENSE file in the project root for more information.
|
||||
|
||||
using System;
|
||||
using System.Runtime.InteropServices;
|
||||
using ManagedCommon;
|
||||
using Microsoft.CmdPal.Ext.Indexer.Indexer.SystemSearch;
|
||||
using Microsoft.CmdPal.Ext.Indexer.Indexer.Utils;
|
||||
using Microsoft.CmdPal.Ext.Indexer.Native;
|
||||
using Windows.Win32.System.Com;
|
||||
using Windows.Win32.System.Com.StructuredStorage;
|
||||
using Windows.Win32.UI.Shell.PropertiesSystem;
|
||||
|
||||
namespace Microsoft.CmdPal.Ext.Indexer.Indexer;
|
||||
|
||||
@@ -39,14 +38,9 @@ internal sealed class SearchResult
|
||||
{
|
||||
try
|
||||
{
|
||||
var key = NativeHelpers.PropertyKeys.PKEYItemNameDisplay;
|
||||
propStore.GetValue(&key, out var itemNameDisplay);
|
||||
|
||||
key = NativeHelpers.PropertyKeys.PKEYItemUrl;
|
||||
propStore.GetValue(&key, out var itemUrl);
|
||||
|
||||
key = NativeHelpers.PropertyKeys.PKEYKindText;
|
||||
propStore.GetValue(&key, out var kindText);
|
||||
propStore.GetValue(NativeHelpers.PropertyKeys.PKEYItemNameDisplay, out var itemNameDisplay);
|
||||
propStore.GetValue(NativeHelpers.PropertyKeys.PKEYItemUrl, out var itemUrl);
|
||||
propStore.GetValue(NativeHelpers.PropertyKeys.PKEYKindText, out var kindText);
|
||||
|
||||
var filePath = GetFilePath(ref itemUrl);
|
||||
var isFolder = IsFoder(ref kindText);
|
||||
@@ -67,28 +61,34 @@ internal sealed class SearchResult
|
||||
}
|
||||
}
|
||||
|
||||
private static bool IsFoder(ref PROPVARIANT kindText)
|
||||
private static bool IsFoder(ref PropVariant kindText)
|
||||
{
|
||||
var kindString = GetStringFromPropVariant(ref kindText);
|
||||
return string.Equals(kindString, "Folder", StringComparison.OrdinalIgnoreCase);
|
||||
}
|
||||
|
||||
private static string GetFilePath(ref PROPVARIANT itemUrl)
|
||||
private static string GetFilePath(ref PropVariant itemUrl)
|
||||
{
|
||||
var filePath = GetStringFromPropVariant(ref itemUrl);
|
||||
filePath = UrlToFilePathConverter.Convert(filePath);
|
||||
return filePath;
|
||||
}
|
||||
|
||||
private static string GetStringFromPropVariant(ref PROPVARIANT propVariant)
|
||||
private static string GetStringFromPropVariant(ref PropVariant propVariant)
|
||||
{
|
||||
if (propVariant.Anonymous.Anonymous.vt == VARENUM.VT_LPWSTR)
|
||||
if (propVariant.VarType == System.Runtime.InteropServices.VarEnum.VT_LPWSTR)
|
||||
{
|
||||
var pwszVal = propVariant.Anonymous.Anonymous.Anonymous.pwszVal;
|
||||
if (pwszVal != null)
|
||||
var pwszVal = propVariant._ptr;
|
||||
|
||||
if (pwszVal == IntPtr.Zero)
|
||||
{
|
||||
return pwszVal.ToString();
|
||||
return string.Empty;
|
||||
}
|
||||
|
||||
// convert to string
|
||||
var str = Marshal.PtrToStringUni(pwszVal);
|
||||
|
||||
return str;
|
||||
}
|
||||
|
||||
return string.Empty;
|
||||
|
||||
@@ -1,18 +0,0 @@
|
||||
// Copyright (c) Microsoft Corporation
|
||||
// The Microsoft Corporation licenses this file to you under the MIT license.
|
||||
// See the LICENSE file in the project root for more information.
|
||||
|
||||
using System;
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
namespace Microsoft.CmdPal.Ext.Indexer.Indexer.SystemSearch;
|
||||
|
||||
[CoClass(typeof(CSearchCatalogManagerClass))]
|
||||
[Guid("AB310581-AC80-11D1-8DF3-00C04FB6EF50")]
|
||||
[ComImport]
|
||||
[System.Diagnostics.CodeAnalysis.SuppressMessage("Naming", "CA1715:Identifiers should have correct prefix", Justification = "Using original name from type lib")]
|
||||
[System.Diagnostics.CodeAnalysis.SuppressMessage("StyleCop.CSharp.NamingRules", "SA1302:Interface names should begin with I", Justification = "Using original name from type lib")]
|
||||
[System.Diagnostics.CodeAnalysis.SuppressMessage("Style", "IDE1006:Naming Styles", Justification = "Using original name from type lib")]
|
||||
public interface CSearchCatalogManager : ISearchCatalogManager
|
||||
{
|
||||
}
|
||||
@@ -1,131 +0,0 @@
|
||||
// Copyright (c) Microsoft Corporation
|
||||
// The Microsoft Corporation licenses this file to you under the MIT license.
|
||||
// See the LICENSE file in the project root for more information.
|
||||
|
||||
using System;
|
||||
using System.Runtime.CompilerServices;
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
namespace Microsoft.CmdPal.Ext.Indexer.Indexer.SystemSearch;
|
||||
|
||||
[ComConversionLoss]
|
||||
[Guid("AAB49DD5-AD0B-40AE-B654-AE8976BF6BD2")]
|
||||
[ClassInterface((short)0)]
|
||||
[ComImport]
|
||||
[System.Diagnostics.CodeAnalysis.SuppressMessage("StyleCop.CSharp.OrderingRules", "SA1212:Property accessors should follow order", Justification = "The order of the property accessors must match the order in which the methods were defined in the vtable")]
|
||||
public class CSearchCatalogManagerClass : ISearchCatalogManager, CSearchCatalogManager
|
||||
{
|
||||
[DispId(1610678272)]
|
||||
public virtual extern string Name
|
||||
{
|
||||
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
|
||||
[return: MarshalAs(UnmanagedType.LPWStr)]
|
||||
get;
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
|
||||
public virtual extern IntPtr GetParameter([MarshalAs(UnmanagedType.LPWStr), In] string pszName);
|
||||
|
||||
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
|
||||
public virtual extern void SetParameter([MarshalAs(UnmanagedType.LPWStr), In] string pszName, [In] ref object pValue);
|
||||
|
||||
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
|
||||
public virtual extern void GetCatalogStatus(
|
||||
out object pStatus,
|
||||
out object pPausedReason);
|
||||
|
||||
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
|
||||
public virtual extern void Reset();
|
||||
|
||||
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
|
||||
public virtual extern void Reindex();
|
||||
|
||||
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
|
||||
public virtual extern void ReindexMatchingURLs([MarshalAs(UnmanagedType.LPWStr), In] string pszPattern);
|
||||
|
||||
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
|
||||
public virtual extern void ReindexSearchRoot([MarshalAs(UnmanagedType.LPWStr), In] string pszRoot);
|
||||
|
||||
[DispId(1610678280)]
|
||||
public virtual extern uint ConnectTimeout
|
||||
{
|
||||
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
|
||||
[param: In]
|
||||
set;
|
||||
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
|
||||
get;
|
||||
}
|
||||
|
||||
[DispId(1610678282)]
|
||||
public virtual extern uint DataTimeout
|
||||
{
|
||||
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
|
||||
[param: In]
|
||||
set;
|
||||
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
|
||||
get;
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
|
||||
public virtual extern int NumberOfItems();
|
||||
|
||||
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
|
||||
public virtual extern void NumberOfItemsToIndex(
|
||||
out int plIncrementalCount,
|
||||
out int plNotificationQueue,
|
||||
out int plHighPriorityQueue);
|
||||
|
||||
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
|
||||
[return: MarshalAs(UnmanagedType.LPWStr)]
|
||||
public virtual extern string URLBeingIndexed();
|
||||
|
||||
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
|
||||
public virtual extern uint GetURLIndexingState([MarshalAs(UnmanagedType.LPWStr), In] string psz);
|
||||
|
||||
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
|
||||
[return: MarshalAs(UnmanagedType.Interface)]
|
||||
public virtual extern object GetPersistentItemsChangedSink();
|
||||
|
||||
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
|
||||
public virtual extern void RegisterViewForNotification(
|
||||
[MarshalAs(UnmanagedType.LPWStr), In] string pszView,
|
||||
[MarshalAs(UnmanagedType.Interface), In] object pViewChangedSink,
|
||||
out uint pdwCookie);
|
||||
|
||||
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
|
||||
public virtual extern void GetItemsChangedSink(
|
||||
[MarshalAs(UnmanagedType.Interface), In] object pISearchNotifyInlineSite,
|
||||
[In] ref Guid riid,
|
||||
out IntPtr ppv,
|
||||
out Guid pGUIDCatalogResetSignature,
|
||||
out Guid pGUIDCheckPointSignature,
|
||||
out uint pdwLastCheckPointNumber);
|
||||
|
||||
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
|
||||
public virtual extern void UnregisterViewForNotification([In] uint dwCookie);
|
||||
|
||||
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
|
||||
public virtual extern void SetExtensionClusion([MarshalAs(UnmanagedType.LPWStr), In] string pszExtension, [In] int fExclude);
|
||||
|
||||
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
|
||||
[return: MarshalAs(UnmanagedType.Interface)]
|
||||
public virtual extern object EnumerateExcludedExtensions();
|
||||
|
||||
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
|
||||
[return: MarshalAs(UnmanagedType.Interface)]
|
||||
public virtual extern CSearchQueryHelper GetQueryHelper();
|
||||
|
||||
[DispId(1610678295)]
|
||||
public virtual extern int DiacriticSensitivity
|
||||
{
|
||||
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
|
||||
[param: In]
|
||||
set;
|
||||
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
|
||||
get;
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
|
||||
[return: MarshalAs(UnmanagedType.Interface)]
|
||||
public virtual extern object GetCrawlScopeManager();
|
||||
}
|
||||
@@ -1,18 +0,0 @@
|
||||
// Copyright (c) Microsoft Corporation
|
||||
// The Microsoft Corporation licenses this file to you under the MIT license.
|
||||
// See the LICENSE file in the project root for more information.
|
||||
|
||||
using System;
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
namespace Microsoft.CmdPal.Ext.Indexer.Indexer.SystemSearch;
|
||||
|
||||
[CoClass(typeof(CSearchManagerClass))]
|
||||
[Guid("AB310581-AC80-11D1-8DF3-00C04FB6EF69")]
|
||||
[ComImport]
|
||||
[System.Diagnostics.CodeAnalysis.SuppressMessage("Naming", "CA1715:Identifiers should have correct prefix", Justification = "Using original name from type lib")]
|
||||
[System.Diagnostics.CodeAnalysis.SuppressMessage("StyleCop.CSharp.NamingRules", "SA1302:Interface names should begin with I", Justification = "Using original name from type lib")]
|
||||
[System.Diagnostics.CodeAnalysis.SuppressMessage("Style", "IDE1006:Naming Styles", Justification = "Using original name from type lib")]
|
||||
public interface CSearchManager : ISearchManager
|
||||
{
|
||||
}
|
||||
@@ -1,90 +0,0 @@
|
||||
// Copyright (c) Microsoft Corporation
|
||||
// The Microsoft Corporation licenses this file to you under the MIT license.
|
||||
// See the LICENSE file in the project root for more information.
|
||||
|
||||
using System;
|
||||
using System.Runtime.CompilerServices;
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
namespace Microsoft.CmdPal.Ext.Indexer.Indexer.SystemSearch;
|
||||
|
||||
[Guid("7D096C5F-AC08-4F1F-BEB7-5C22C517CE39")]
|
||||
[TypeLibType(2)]
|
||||
[ClassInterface((short)0)]
|
||||
[ComConversionLoss]
|
||||
[ComImport]
|
||||
public class CSearchManagerClass : ISearchManager, CSearchManager
|
||||
{
|
||||
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
|
||||
public virtual extern void GetIndexerVersionStr([MarshalAs(UnmanagedType.LPWStr)] out string ppszVersionString);
|
||||
|
||||
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
|
||||
public virtual extern void GetIndexerVersion(out uint pdwMajor, out uint pdwMinor);
|
||||
|
||||
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
|
||||
public virtual extern IntPtr GetParameter([MarshalAs(UnmanagedType.LPWStr), In] string pszName);
|
||||
|
||||
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
|
||||
public virtual extern void SetParameter([MarshalAs(UnmanagedType.LPWStr), In] string pszName, [In] ref object pValue);
|
||||
|
||||
[DispId(1610678276)]
|
||||
public virtual extern string ProxyName
|
||||
{
|
||||
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
|
||||
[return: MarshalAs(UnmanagedType.LPWStr)]
|
||||
get;
|
||||
}
|
||||
|
||||
[DispId(1610678277)]
|
||||
public virtual extern string BypassList
|
||||
{
|
||||
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
|
||||
[return: MarshalAs(UnmanagedType.LPWStr)]
|
||||
get;
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
|
||||
public virtual extern void SetProxy(
|
||||
[In] object sUseProxy,
|
||||
[In] int fLocalByPassProxy,
|
||||
[In] uint dwPortNumber,
|
||||
[MarshalAs(UnmanagedType.LPWStr), In] string pszProxyName,
|
||||
[MarshalAs(UnmanagedType.LPWStr), In] string pszByPassList);
|
||||
|
||||
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
|
||||
[return: MarshalAs(UnmanagedType.Interface)]
|
||||
public virtual extern CSearchCatalogManager GetCatalog([MarshalAs(UnmanagedType.LPWStr), In] string pszCatalog);
|
||||
|
||||
[DispId(1610678280)]
|
||||
public virtual extern string UserAgent
|
||||
{
|
||||
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
|
||||
[return: MarshalAs(UnmanagedType.LPWStr)]
|
||||
get;
|
||||
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
|
||||
[param: MarshalAs(UnmanagedType.LPWStr)]
|
||||
[param: In]
|
||||
set;
|
||||
}
|
||||
|
||||
[DispId(1610678282)]
|
||||
public virtual extern object UseProxy
|
||||
{
|
||||
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
|
||||
get;
|
||||
}
|
||||
|
||||
[DispId(1610678283)]
|
||||
public virtual extern int LocalBypass
|
||||
{
|
||||
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
|
||||
get;
|
||||
}
|
||||
|
||||
[DispId(1610678284)]
|
||||
public virtual extern uint PortNumber
|
||||
{
|
||||
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
|
||||
get;
|
||||
}
|
||||
}
|
||||
@@ -1,18 +0,0 @@
|
||||
// Copyright (c) Microsoft Corporation
|
||||
// The Microsoft Corporation licenses this file to you under the MIT license.
|
||||
// See the LICENSE file in the project root for more information.
|
||||
|
||||
using System;
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
namespace Microsoft.CmdPal.Ext.Indexer.Indexer.SystemSearch;
|
||||
|
||||
[Guid("AB310581-AC80-11D1-8DF3-00C04FB6EF63")]
|
||||
[CoClass(typeof(CSearchQueryHelperClass))]
|
||||
[ComImport]
|
||||
[System.Diagnostics.CodeAnalysis.SuppressMessage("Naming", "CA1715:Identifiers should have correct prefix", Justification = "Using original name from type lib")]
|
||||
[System.Diagnostics.CodeAnalysis.SuppressMessage("StyleCop.CSharp.NamingRules", "SA1302:Interface names should begin with I", Justification = "Using original name from type lib")]
|
||||
[System.Diagnostics.CodeAnalysis.SuppressMessage("Style", "IDE1006:Naming Styles", Justification = "Using original name from type lib")]
|
||||
public interface CSearchQueryHelper : ISearchQueryHelper
|
||||
{
|
||||
}
|
||||
@@ -1,134 +0,0 @@
|
||||
// Copyright (c) Microsoft Corporation
|
||||
// The Microsoft Corporation licenses this file to you under the MIT license.
|
||||
// See the LICENSE file in the project root for more information.
|
||||
|
||||
using System;
|
||||
using System.Runtime.CompilerServices;
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
namespace Microsoft.CmdPal.Ext.Indexer.Indexer.SystemSearch;
|
||||
|
||||
[ClassInterface((short)0)]
|
||||
[Guid("B271E955-09E1-42E1-9B95-5994A534B613")]
|
||||
[ComImport]
|
||||
[System.Diagnostics.CodeAnalysis.SuppressMessage("StyleCop.CSharp.OrderingRules", "SA1212:Property accessors should follow order", Justification = "The order of the property accessors must match the order in which the methods were defined in the vtable")]
|
||||
public class CSearchQueryHelperClass : ISearchQueryHelper, CSearchQueryHelper
|
||||
{
|
||||
[DispId(1610678272)]
|
||||
public virtual extern string ConnectionString
|
||||
{
|
||||
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
|
||||
[return: MarshalAs(UnmanagedType.LPWStr)]
|
||||
get;
|
||||
}
|
||||
|
||||
[DispId(1610678273)]
|
||||
public virtual extern uint QueryContentLocale
|
||||
{
|
||||
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
|
||||
[param: In]
|
||||
set;
|
||||
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
|
||||
get;
|
||||
}
|
||||
|
||||
[DispId(1610678275)]
|
||||
public virtual extern uint QueryKeywordLocale
|
||||
{
|
||||
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
|
||||
[param: In]
|
||||
set;
|
||||
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
|
||||
get;
|
||||
}
|
||||
|
||||
[DispId(1610678277)]
|
||||
public virtual extern object QueryTermExpansion
|
||||
{
|
||||
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
|
||||
[param: In]
|
||||
set;
|
||||
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
|
||||
get;
|
||||
}
|
||||
|
||||
[DispId(1610678279)]
|
||||
public virtual extern object QuerySyntax
|
||||
{
|
||||
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
|
||||
[param: In]
|
||||
set;
|
||||
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
|
||||
get;
|
||||
}
|
||||
|
||||
[DispId(1610678281)]
|
||||
public virtual extern string QueryContentProperties
|
||||
{
|
||||
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
|
||||
[param: MarshalAs(UnmanagedType.LPWStr)]
|
||||
[param: In]
|
||||
set;
|
||||
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
|
||||
[return: MarshalAs(UnmanagedType.LPWStr)]
|
||||
get;
|
||||
}
|
||||
|
||||
[DispId(1610678283)]
|
||||
public virtual extern string QuerySelectColumns
|
||||
{
|
||||
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
|
||||
[param: MarshalAs(UnmanagedType.LPWStr)]
|
||||
[param: In]
|
||||
set;
|
||||
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
|
||||
[return: MarshalAs(UnmanagedType.LPWStr)]
|
||||
get;
|
||||
}
|
||||
|
||||
[DispId(1610678285)]
|
||||
public virtual extern string QueryWhereRestrictions
|
||||
{
|
||||
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
|
||||
[param: MarshalAs(UnmanagedType.LPWStr)]
|
||||
[param: In]
|
||||
set;
|
||||
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
|
||||
[return: MarshalAs(UnmanagedType.LPWStr)]
|
||||
get;
|
||||
}
|
||||
|
||||
[DispId(1610678287)]
|
||||
public virtual extern string QuerySorting
|
||||
{
|
||||
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
|
||||
[param: MarshalAs(UnmanagedType.LPWStr)]
|
||||
[param: In]
|
||||
set;
|
||||
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
|
||||
[return: MarshalAs(UnmanagedType.LPWStr)]
|
||||
get;
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
|
||||
[return: MarshalAs(UnmanagedType.LPWStr)]
|
||||
public virtual extern string GenerateSQLFromUserQuery([MarshalAs(UnmanagedType.LPWStr), In] string pszQuery);
|
||||
|
||||
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
|
||||
public virtual extern void WriteProperties(
|
||||
[In] int itemID,
|
||||
[In] uint dwNumberOfColumns,
|
||||
[In] ref object pColumns,
|
||||
[In] ref object pValues,
|
||||
[In] ref object pftGatherModifiedTime);
|
||||
|
||||
[DispId(1610678291)]
|
||||
public virtual extern int QueryMaxResults
|
||||
{
|
||||
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
|
||||
[param: In]
|
||||
set;
|
||||
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
|
||||
get;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,21 @@
|
||||
// Copyright (c) Microsoft Corporation
|
||||
// The Microsoft Corporation licenses this file to you under the MIT license.
|
||||
// See the LICENSE file in the project root for more information.
|
||||
|
||||
using System;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Runtime.InteropServices.Marshalling;
|
||||
using Microsoft.CmdPal.Ext.Indexer.Indexer.OleDB;
|
||||
|
||||
namespace Microsoft.CmdPal.Ext.Indexer.Indexer.SystemSearch;
|
||||
|
||||
[Guid("0C733A63-2A1C-11CE-ADE5-00AA0044773D")]
|
||||
[GeneratedComInterface(StringMarshalling = StringMarshalling.Utf16)]
|
||||
public partial interface ICommand
|
||||
{
|
||||
void Cancel();
|
||||
|
||||
void Execute([MarshalAs(UnmanagedType.Interface)] object pUnkOuter, ref Guid riid, [Optional][MarshalAs(UnmanagedType.Interface)] object pParams, [Optional]out int pcRowsAffected, out IRowset ppRowset);
|
||||
|
||||
void GetDBSession(ref Guid riid, out IntPtr ppSession);
|
||||
}
|
||||
@@ -0,0 +1,23 @@
|
||||
// Copyright (c) Microsoft Corporation
|
||||
// The Microsoft Corporation licenses this file to you under the MIT license.
|
||||
// See the LICENSE file in the project root for more information.
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Runtime.InteropServices.Marshalling;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using Microsoft.CmdPal.Ext.Indexer.Indexer.OleDB;
|
||||
|
||||
namespace Microsoft.CmdPal.Ext.Indexer.Indexer.SystemSearch;
|
||||
|
||||
[Guid("0C733A27-2A1C-11CE-ADE5-00AA0044773D")]
|
||||
[GeneratedComInterface(StringMarshalling = StringMarshalling.Utf16)]
|
||||
public partial interface ICommandText : ICommand
|
||||
{
|
||||
void GetCommandText([Optional] ref Guid pguidDialect, out IntPtr ppwszCommand);
|
||||
|
||||
void SetCommandText(ref Guid rguidDialect, string pwszCommand);
|
||||
}
|
||||
@@ -0,0 +1,16 @@
|
||||
// Copyright (c) Microsoft Corporation
|
||||
// The Microsoft Corporation licenses this file to you under the MIT license.
|
||||
// See the LICENSE file in the project root for more information.
|
||||
|
||||
using System;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Runtime.InteropServices.Marshalling;
|
||||
|
||||
namespace Microsoft.CmdPal.Ext.Indexer.Indexer.SystemSearch;
|
||||
|
||||
[Guid("0C733A1D-2A1C-11CE-ADE5-00AA0044773D")]
|
||||
[GeneratedComInterface(StringMarshalling = StringMarshalling.Utf16)]
|
||||
public partial interface IDBCreateCommand
|
||||
{
|
||||
void CreateCommand(IntPtr pUnkOuter, ref Guid riid, out ICommandText ppCommand);
|
||||
}
|
||||
@@ -0,0 +1,20 @@
|
||||
// Copyright (c) Microsoft Corporation
|
||||
// The Microsoft Corporation licenses this file to you under the MIT license.
|
||||
// See the LICENSE file in the project root for more information.
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Runtime.InteropServices.Marshalling;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Microsoft.CmdPal.Ext.Indexer.Indexer.SystemSearch;
|
||||
|
||||
[Guid("0C733A5D-2A1C-11CE-ADE5-00AA0044773D")]
|
||||
[GeneratedComInterface(StringMarshalling = StringMarshalling.Utf16)]
|
||||
public partial interface IDBCreateSession
|
||||
{
|
||||
void CreateSession(IntPtr pUnkOuter, ref Guid riid, [MarshalAs(UnmanagedType.Interface)] out object ppDBSession);
|
||||
}
|
||||
@@ -0,0 +1,22 @@
|
||||
// Copyright (c) Microsoft Corporation
|
||||
// The Microsoft Corporation licenses this file to you under the MIT license.
|
||||
// See the LICENSE file in the project root for more information.
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Runtime.InteropServices.Marshalling;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Microsoft.CmdPal.Ext.Indexer.Indexer.SystemSearch;
|
||||
|
||||
[Guid("0C733A8B-2A1C-11CE-ADE5-00AA0044773D")]
|
||||
[GeneratedComInterface(StringMarshalling = StringMarshalling.Utf16)]
|
||||
public partial interface IDBInitialize
|
||||
{
|
||||
void Initialize();
|
||||
|
||||
void Uninitialize();
|
||||
}
|
||||
@@ -0,0 +1,23 @@
|
||||
// Copyright (c) Microsoft Corporation
|
||||
// The Microsoft Corporation licenses this file to you under the MIT license.
|
||||
// See the LICENSE file in the project root for more information.
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Runtime.InteropServices.Marshalling;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using Microsoft.CmdPal.Ext.Indexer.Native;
|
||||
|
||||
namespace Microsoft.CmdPal.Ext.Indexer.Indexer.SystemSearch;
|
||||
|
||||
[Guid("0C733AAF-2A1C-11CE-ADE5-00AA0044773D")]
|
||||
[GeneratedComInterface(StringMarshalling = StringMarshalling.Utf16)]
|
||||
public partial interface IGetRow
|
||||
{
|
||||
unsafe void GetRowFromHROW([MarshalAs(UnmanagedType.Interface)] object pUnkOuter, nuint hRow, ref Guid riid, [MarshalAs(UnmanagedType.Interface)] out IPropertyStore ppUnk);
|
||||
|
||||
unsafe string GetURLFromHROW(nuint hRow);
|
||||
}
|
||||
@@ -0,0 +1,26 @@
|
||||
// Copyright (c) Microsoft Corporation
|
||||
// The Microsoft Corporation licenses this file to you under the MIT license.
|
||||
// See the LICENSE file in the project root for more information.
|
||||
|
||||
using System;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Runtime.InteropServices.Marshalling;
|
||||
|
||||
[assembly: System.Runtime.CompilerServices.DisableRuntimeMarshalling]
|
||||
|
||||
namespace Microsoft.CmdPal.Ext.Indexer.Indexer.SystemSearch;
|
||||
|
||||
[Guid("886d8eeb-8cf2-4446-8d02-cdba1dbdcf99")]
|
||||
[GeneratedComInterface(StringMarshalling = StringMarshalling.Utf16)]
|
||||
public partial interface IPropertyStore
|
||||
{
|
||||
uint GetCount();
|
||||
|
||||
PropertyKey GetAt(uint iProp);
|
||||
|
||||
void GetValue(in PropertyKey pkey, out PropVariant pv);
|
||||
|
||||
void SetValue(in PropertyKey pkey, in PropVariant pv);
|
||||
|
||||
void Commit();
|
||||
}
|
||||
@@ -5,125 +5,68 @@
|
||||
using System;
|
||||
using System.Runtime.CompilerServices;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Runtime.InteropServices.Marshalling;
|
||||
|
||||
namespace Microsoft.CmdPal.Ext.Indexer.Indexer.SystemSearch;
|
||||
|
||||
[Guid("AB310581-AC80-11D1-8DF3-00C04FB6EF50")]
|
||||
[ComConversionLoss]
|
||||
[InterfaceType(1)]
|
||||
[ComImport]
|
||||
[System.Diagnostics.CodeAnalysis.SuppressMessage("StyleCop.CSharp.OrderingRules", "SA1212:Property accessors should follow order", Justification = "The order of the property accessors must match the order in which the methods were defined in the vtable")]
|
||||
public interface ISearchCatalogManager
|
||||
[GeneratedComInterface(StringMarshalling = StringMarshalling.Utf16)]
|
||||
[System.Diagnostics.CodeAnalysis.SuppressMessage("StyleCop.CSharp.NamingRules", "SA1300:Element should begin with upper-case letter", Justification = "Please do not change the function name")]
|
||||
public partial interface ISearchCatalogManager
|
||||
{
|
||||
[DispId(1610678272)]
|
||||
string Name
|
||||
{
|
||||
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
|
||||
[return: MarshalAs(UnmanagedType.LPWStr)]
|
||||
get;
|
||||
}
|
||||
string get_Name();
|
||||
|
||||
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
|
||||
IntPtr GetParameter([MarshalAs(UnmanagedType.LPWStr), In] string pszName);
|
||||
void GetParameter(string pszName, out IntPtr pValue);
|
||||
|
||||
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
|
||||
void SetParameter([MarshalAs(UnmanagedType.LPWStr), In] string pszName, [In] ref object pValue);
|
||||
void SetParameter(string pszName, ref IntPtr pValue);
|
||||
|
||||
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
|
||||
void GetCatalogStatus(out object pStatus, out object pPausedReason);
|
||||
void GetCatalogStatus(out uint pdwStatus, out uint pdwPausedReason);
|
||||
|
||||
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
|
||||
void Reset();
|
||||
|
||||
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
|
||||
void Reindex();
|
||||
|
||||
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
|
||||
void ReindexMatchingURLs([MarshalAs(UnmanagedType.LPWStr), In] string pszPattern);
|
||||
void ReindexMatchingURLs(string pszPattern);
|
||||
|
||||
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
|
||||
void ReindexSearchRoot([MarshalAs(UnmanagedType.LPWStr), In] string pszRoot);
|
||||
void ReindexSearchRoot(string pszRoot);
|
||||
|
||||
[DispId(1610678280)]
|
||||
uint ConnectTimeout
|
||||
{
|
||||
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
|
||||
[param: In]
|
||||
set;
|
||||
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
|
||||
get;
|
||||
}
|
||||
uint get_ConnectTimeout();
|
||||
|
||||
[DispId(1610678282)]
|
||||
uint DataTimeout
|
||||
{
|
||||
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
|
||||
[param: In]
|
||||
set;
|
||||
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
|
||||
get;
|
||||
}
|
||||
void put_ConnectTimeout(uint dwTimeout);
|
||||
|
||||
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
|
||||
int NumberOfItems();
|
||||
uint get_DataTimeout();
|
||||
|
||||
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
|
||||
void NumberOfItemsToIndex(
|
||||
out int plIncrementalCount,
|
||||
out int plNotificationQueue,
|
||||
out int plHighPriorityQueue);
|
||||
void put_DataTimeout(uint dwTimeout);
|
||||
|
||||
uint NumberOfItems();
|
||||
|
||||
uint NumberOfItemsToIndex();
|
||||
|
||||
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
|
||||
[return: MarshalAs(UnmanagedType.LPWStr)]
|
||||
string URLBeingIndexed();
|
||||
|
||||
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
|
||||
uint GetURLIndexingState([MarshalAs(UnmanagedType.LPWStr), In] string psz);
|
||||
void GetURLIndexingState(string pszURL, out uint pdwState);
|
||||
|
||||
IntPtr GetPersistentItemsChangedSink();
|
||||
|
||||
void RegisterViewForNotification(string pszView, IntPtr pViewNotify, out uint pdwCookie);
|
||||
|
||||
IntPtr GetItemsChangedSink();
|
||||
|
||||
void UnregisterViewForNotification(uint dwCookie);
|
||||
|
||||
void SetExtensionClusion(string pszExtension, [MarshalAs(UnmanagedType.Bool)] bool fExclude);
|
||||
|
||||
void EnumerateExcludedExtensions();
|
||||
|
||||
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
|
||||
[return: MarshalAs(UnmanagedType.Interface)]
|
||||
object GetPersistentItemsChangedSink();
|
||||
|
||||
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
|
||||
void RegisterViewForNotification(
|
||||
[MarshalAs(UnmanagedType.LPWStr), In] string pszView,
|
||||
[MarshalAs(UnmanagedType.Interface), In] object pViewChangedSink,
|
||||
out uint pdwCookie);
|
||||
ISearchQueryHelper GetQueryHelper();
|
||||
|
||||
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
|
||||
void GetItemsChangedSink(
|
||||
[MarshalAs(UnmanagedType.Interface), In] object pISearchNotifyInlineSite,
|
||||
[In] ref Guid riid,
|
||||
out IntPtr ppv,
|
||||
out Guid pGUIDCatalogResetSignature,
|
||||
out Guid pGUIDCheckPointSignature,
|
||||
out uint pdwLastCheckPointNumber);
|
||||
[return: MarshalAs(UnmanagedType.Bool)]
|
||||
bool get_DiacriticSensitivity();
|
||||
|
||||
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
|
||||
void UnregisterViewForNotification([In] uint dwCookie);
|
||||
void put_DiacriticSensitivity([MarshalAs(UnmanagedType.Bool)] bool fDiacriticSensitive);
|
||||
|
||||
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
|
||||
void SetExtensionClusion([MarshalAs(UnmanagedType.LPWStr), In] string pszExtension, [In] int fExclude);
|
||||
|
||||
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
|
||||
[return: MarshalAs(UnmanagedType.Interface)]
|
||||
object EnumerateExcludedExtensions();
|
||||
|
||||
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
|
||||
[return: MarshalAs(UnmanagedType.Interface)]
|
||||
CSearchQueryHelper GetQueryHelper();
|
||||
|
||||
[DispId(1610678295)]
|
||||
int DiacriticSensitivity
|
||||
{
|
||||
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
|
||||
[param: In]
|
||||
set;
|
||||
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
|
||||
get;
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
|
||||
[return: MarshalAs(UnmanagedType.Interface)]
|
||||
object GetCrawlScopeManager();
|
||||
IntPtr GetCrawlScopeManager();
|
||||
}
|
||||
|
||||
@@ -3,87 +3,46 @@
|
||||
// See the LICENSE file in the project root for more information.
|
||||
|
||||
using System;
|
||||
using System.Runtime.CompilerServices;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Runtime.InteropServices.Marshalling;
|
||||
|
||||
namespace Microsoft.CmdPal.Ext.Indexer.Indexer.SystemSearch;
|
||||
|
||||
[ComConversionLoss]
|
||||
[Guid("AB310581-AC80-11D1-8DF3-00C04FB6EF69")]
|
||||
[InterfaceType(1)]
|
||||
[ComImport]
|
||||
public interface ISearchManager
|
||||
[GeneratedComInterface(StringMarshalling = StringMarshalling.Utf16)]
|
||||
[System.Diagnostics.CodeAnalysis.SuppressMessage("StyleCop.CSharp.NamingRules", "SA1300:Element should begin with upper-case letter", Justification = "Please do not change the function name")]
|
||||
public partial interface ISearchManager
|
||||
{
|
||||
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
|
||||
void GetIndexerVersionStr([MarshalAs(UnmanagedType.LPWStr)] out string ppszVersionString);
|
||||
string GetIndexerVersionStr();
|
||||
|
||||
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
|
||||
void GetIndexerVersion(out uint pdwMajor, out uint pdwMinor);
|
||||
|
||||
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
|
||||
IntPtr GetParameter([MarshalAs(UnmanagedType.LPWStr), In] string pszName);
|
||||
void GetParameter(string pszName, [MarshalAs(UnmanagedType.Interface)] out object pValue);
|
||||
|
||||
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
|
||||
void SetParameter([MarshalAs(UnmanagedType.LPWStr), In] string pszName, [In] ref object pValue);
|
||||
void SetParameter(string pszName, [MarshalAs(UnmanagedType.Interface)] ref object pValue);
|
||||
|
||||
[DispId(1610678276)]
|
||||
string ProxyName
|
||||
{
|
||||
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
|
||||
[return: MarshalAs(UnmanagedType.LPWStr)]
|
||||
get;
|
||||
}
|
||||
[return: MarshalAs(UnmanagedType.Bool)]
|
||||
bool get_UseProxy();
|
||||
|
||||
[DispId(1610678277)]
|
||||
string BypassList
|
||||
{
|
||||
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
|
||||
[return: MarshalAs(UnmanagedType.LPWStr)]
|
||||
get;
|
||||
}
|
||||
string get_BypassList();
|
||||
|
||||
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
|
||||
void SetProxy(
|
||||
[In] object sUseProxy,
|
||||
[In] int fLocalByPassProxy,
|
||||
[In] uint dwPortNumber,
|
||||
[MarshalAs(UnmanagedType.LPWStr), In] string pszProxyName,
|
||||
[MarshalAs(UnmanagedType.LPWStr), In] string pszByPassList);
|
||||
string pszProxyName,
|
||||
[MarshalAs(UnmanagedType.Bool)] bool fLocalBypass,
|
||||
string pszBypassList,
|
||||
uint dwPortNumber);
|
||||
|
||||
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
|
||||
[return: MarshalAs(UnmanagedType.Interface)]
|
||||
CSearchCatalogManager GetCatalog([MarshalAs(UnmanagedType.LPWStr), In] string pszCatalog);
|
||||
ISearchCatalogManager GetCatalog(string pszCatalog);
|
||||
|
||||
[DispId(1610678280)]
|
||||
string UserAgent
|
||||
{
|
||||
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
|
||||
[return: MarshalAs(UnmanagedType.LPWStr)]
|
||||
get;
|
||||
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
|
||||
[param: MarshalAs(UnmanagedType.LPWStr)]
|
||||
[param: In]
|
||||
set;
|
||||
}
|
||||
string get_UserAgent();
|
||||
|
||||
[DispId(1610678282)]
|
||||
object UseProxy
|
||||
{
|
||||
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
|
||||
get;
|
||||
}
|
||||
void put_UserAgent(string pszUserAgent);
|
||||
|
||||
[DispId(1610678283)]
|
||||
int LocalBypass
|
||||
{
|
||||
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
|
||||
get;
|
||||
}
|
||||
string get_ProxyName();
|
||||
|
||||
[DispId(1610678284)]
|
||||
uint PortNumber
|
||||
{
|
||||
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
|
||||
get;
|
||||
}
|
||||
[return: MarshalAs(UnmanagedType.Bool)]
|
||||
bool get_LocalBypass();
|
||||
|
||||
uint get_PortNumber();
|
||||
}
|
||||
|
||||
@@ -5,130 +5,74 @@
|
||||
using System;
|
||||
using System.Runtime.CompilerServices;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Runtime.InteropServices.Marshalling;
|
||||
|
||||
namespace Microsoft.CmdPal.Ext.Indexer.Indexer.SystemSearch;
|
||||
|
||||
[Guid("AB310581-AC80-11D1-8DF3-00C04FB6EF63")]
|
||||
[InterfaceType(1)]
|
||||
[ComImport]
|
||||
[System.Diagnostics.CodeAnalysis.SuppressMessage("StyleCop.CSharp.OrderingRules", "SA1212:Property accessors should follow order", Justification = "The order of the property accessors must match the order in which the methods were defined in the vtable")]
|
||||
public interface ISearchQueryHelper
|
||||
[GeneratedComInterface(StringMarshalling = StringMarshalling.Utf16)]
|
||||
[System.Diagnostics.CodeAnalysis.SuppressMessage("StyleCop.CSharp.NamingRules", "SA1300:Element should begin with upper-case letter", Justification = "I don't want to change the name")]
|
||||
public partial interface ISearchQueryHelper
|
||||
{
|
||||
[DispId(1610678272)]
|
||||
string ConnectionString
|
||||
{
|
||||
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
|
||||
[return: MarshalAs(UnmanagedType.LPWStr)]
|
||||
get;
|
||||
}
|
||||
string GetConnectionString();
|
||||
|
||||
[DispId(1610678273)]
|
||||
uint QueryContentLocale
|
||||
{
|
||||
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
|
||||
[param: In]
|
||||
set;
|
||||
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
|
||||
get;
|
||||
}
|
||||
void SetQueryContentLocale(int lcid);
|
||||
|
||||
[DispId(1610678275)]
|
||||
uint QueryKeywordLocale
|
||||
{
|
||||
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
|
||||
[param: In]
|
||||
set;
|
||||
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
|
||||
get;
|
||||
}
|
||||
uint GetQueryContentLocale();
|
||||
|
||||
[DispId(1610678277)]
|
||||
object QueryTermExpansion
|
||||
{
|
||||
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
|
||||
[param: In]
|
||||
set;
|
||||
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
|
||||
get;
|
||||
}
|
||||
void SetQueryKeywordLocale(int lcid);
|
||||
|
||||
[DispId(1610678279)]
|
||||
object QuerySyntax
|
||||
{
|
||||
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
|
||||
[param: In]
|
||||
set;
|
||||
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
|
||||
get;
|
||||
}
|
||||
uint GetQueryKeywordLocale();
|
||||
|
||||
[DispId(1610678281)]
|
||||
string QueryContentProperties
|
||||
{
|
||||
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
|
||||
[param: MarshalAs(UnmanagedType.LPWStr)]
|
||||
[param: In]
|
||||
set;
|
||||
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
|
||||
[return: MarshalAs(UnmanagedType.LPWStr)]
|
||||
get;
|
||||
}
|
||||
void SetQueryTermExpansion(SEARCH_TERM_EXPANSION expandTerms);
|
||||
|
||||
[DispId(1610678283)]
|
||||
string QuerySelectColumns
|
||||
{
|
||||
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
|
||||
[param: MarshalAs(UnmanagedType.LPWStr)]
|
||||
[param: In]
|
||||
set;
|
||||
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
|
||||
[return: MarshalAs(UnmanagedType.LPWStr)]
|
||||
get;
|
||||
}
|
||||
void GetQueryTermExpansion(out SEARCH_TERM_EXPANSION pExpandTerms);
|
||||
|
||||
[DispId(1610678285)]
|
||||
string QueryWhereRestrictions
|
||||
{
|
||||
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
|
||||
[param: MarshalAs(UnmanagedType.LPWStr)]
|
||||
[param: In]
|
||||
set;
|
||||
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
|
||||
[return: MarshalAs(UnmanagedType.LPWStr)]
|
||||
get;
|
||||
}
|
||||
void SetQuerySyntax(SEARCH_QUERY_SYNTAX querySyntax);
|
||||
|
||||
[DispId(1610678287)]
|
||||
string QuerySorting
|
||||
{
|
||||
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
|
||||
[param: MarshalAs(UnmanagedType.LPWStr)]
|
||||
[param: In]
|
||||
set;
|
||||
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
|
||||
[return: MarshalAs(UnmanagedType.LPWStr)]
|
||||
get;
|
||||
}
|
||||
[return: MarshalAs(UnmanagedType.Interface)]
|
||||
object GetQuerySyntax();
|
||||
|
||||
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
|
||||
[return: MarshalAs(UnmanagedType.LPWStr)]
|
||||
string GenerateSQLFromUserQuery([MarshalAs(UnmanagedType.LPWStr), In] string pszQuery);
|
||||
void SetQueryContentProperties(string pszContentProperties);
|
||||
|
||||
string GetQueryContentProperties();
|
||||
|
||||
void SetQuerySelectColumns(string pszColumns);
|
||||
|
||||
string GetQuerySelectColumns();
|
||||
|
||||
void SetQueryWhereRestrictions(string pszRestrictions);
|
||||
|
||||
string GetQueryWhereRestrictions();
|
||||
|
||||
void SetQuerySorting(string pszSorting);
|
||||
|
||||
string GetQuerySorting();
|
||||
|
||||
string GenerateSQLFromUserQuery(string pszQuery);
|
||||
|
||||
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
|
||||
void WriteProperties(
|
||||
[In] int itemID,
|
||||
[In] uint dwNumberOfColumns,
|
||||
[In] ref object pColumns,
|
||||
[In] ref object pValues,
|
||||
[In] ref object pftGatherModifiedTime);
|
||||
int itemID,
|
||||
uint dwNumberOfColumns,
|
||||
[MarshalAs(UnmanagedType.Interface)] ref object pColumns,
|
||||
[MarshalAs(UnmanagedType.Interface)] ref object pValues,
|
||||
[MarshalAs(UnmanagedType.Interface)] ref object pftGatherModifiedTime);
|
||||
|
||||
[DispId(1610678291)]
|
||||
int QueryMaxResults
|
||||
{
|
||||
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
|
||||
[param: In]
|
||||
set;
|
||||
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
|
||||
get;
|
||||
}
|
||||
void SetQueryMaxResults(int lMaxResults);
|
||||
|
||||
int GetQueryMaxResults();
|
||||
}
|
||||
|
||||
public enum SEARCH_TERM_EXPANSION
|
||||
{
|
||||
SEARCH_TERM_NO_EXPANSION,
|
||||
SEARCH_TERM_PREFIX_ALL,
|
||||
SEARCH_TERM_STEM_ALL,
|
||||
}
|
||||
|
||||
public enum SEARCH_QUERY_SYNTAX
|
||||
{
|
||||
SEARCH_NO_QUERY_SYNTAX,
|
||||
SEARCH_ADVANCED_QUERY_SYNTAX,
|
||||
SEARCH_NATURAL_QUERY_SYNTAX,
|
||||
}
|
||||
|
||||
@@ -0,0 +1,70 @@
|
||||
// Copyright (c) Microsoft Corporation
|
||||
// The Microsoft Corporation licenses this file to you under the MIT license.
|
||||
// See the LICENSE file in the project root for more information.
|
||||
|
||||
using System;
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
using System.Runtime.InteropServices;
|
||||
using VARTYPE = System.Runtime.InteropServices.VarEnum;
|
||||
|
||||
namespace Microsoft.CmdPal.Ext.Indexer.Indexer.SystemSearch;
|
||||
|
||||
#pragma warning disable SA1307 // Accessible fields should begin with upper-case letter
|
||||
[StructLayout(LayoutKind.Explicit, Pack = 8)]
|
||||
public struct PropVariant
|
||||
{
|
||||
/// <summary>Value type tag.</summary>
|
||||
[FieldOffset(0)]
|
||||
public ushort vt;
|
||||
|
||||
[FieldOffset(2)]
|
||||
public ushort wReserved1;
|
||||
|
||||
/// <summary>Reserved for future use.</summary>
|
||||
[FieldOffset(4)]
|
||||
public ushort wReserved2;
|
||||
|
||||
/// <summary>Reserved for future use.</summary>
|
||||
[FieldOffset(6)]
|
||||
public ushort wReserved3;
|
||||
|
||||
/// <summary>The decimal value when VT_DECIMAL.</summary>
|
||||
[FieldOffset(0)]
|
||||
internal decimal _decimal;
|
||||
|
||||
/// <summary>The raw data pointer.</summary>
|
||||
[FieldOffset(8)]
|
||||
internal IntPtr _ptr;
|
||||
|
||||
/// <summary>The FILETIME when VT_FILETIME.</summary>
|
||||
[FieldOffset(8)]
|
||||
internal System.Runtime.InteropServices.ComTypes.FILETIME _ft;
|
||||
|
||||
[FieldOffset(8)]
|
||||
internal BLOB _blob;
|
||||
|
||||
/// <summary>The value when a numeric value less than 8 bytes.</summary>
|
||||
[FieldOffset(8)]
|
||||
internal ulong _ulong;
|
||||
|
||||
public PropVariant(string value)
|
||||
{
|
||||
ArgumentNullException.ThrowIfNull(value);
|
||||
vt = (ushort)VarEnum.VT_LPWSTR;
|
||||
_ptr = Marshal.StringToCoTaskMemUni(value);
|
||||
}
|
||||
|
||||
public VarEnum VarType { get => (VarEnum)vt; set => vt = (ushort)(VARTYPE)value; }
|
||||
}
|
||||
|
||||
[StructLayout(LayoutKind.Sequential, Pack = 0)]
|
||||
public struct BLOB
|
||||
{
|
||||
/// <summary>The count of bytes</summary>
|
||||
public uint cbSize;
|
||||
|
||||
/// <summary>A pointer to the allocated array of bytes.</summary>
|
||||
public IntPtr pBlobData;
|
||||
}
|
||||
|
||||
#pragma warning restore SA1307 // Accessible fields should begin with upper-case letter
|
||||
@@ -0,0 +1,27 @@
|
||||
// Copyright (c) Microsoft Corporation
|
||||
// The Microsoft Corporation licenses this file to you under the MIT license.
|
||||
// See the LICENSE file in the project root for more information.
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
using System.Linq;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Microsoft.CmdPal.Ext.Indexer.Indexer.SystemSearch;
|
||||
|
||||
[StructLayout(LayoutKind.Sequential)]
|
||||
public struct PropertyKey
|
||||
{
|
||||
public Guid FmtID;
|
||||
|
||||
public uint PID;
|
||||
|
||||
public PropertyKey(Guid fmtid, uint pid)
|
||||
{
|
||||
this.FmtID = fmtid;
|
||||
this.PID = pid;
|
||||
}
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user