Compare commits

...

18 Commits

Author SHA1 Message Date
Muyuan Li (from Dev Box)
e9a55cb906 Address PR review: SetClipboardData leak, GPO UI binding, version patching
- Fix SetClipboardData memory leak: free hMem on failure (dllmain.cpp)
- Add GPO-aware IsEnabled bindings to CopyAsUNC SettingsCard/ToggleSwitch
  following the same pattern as other File Explorer add-on toggles
- Add CopyAsUNC AppxManifest to versionSetting.ps1 so sparse package
  version is patched during release builds

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
2026-05-14 17:56:27 +08:00
Muyuan Li (from Dev Box)
31f60088f1 Fix missing gpo.h include in CopyAsUNC Settings.h (PR #46056) 2026-05-14 12:22:13 +08:00
Muyuan Li (from Dev Box)
e6cff0fb21 Address Copilot review comments (PR #46056)
- Restore GrabAndMove enum/mappings in settings_window.h/.cpp (accidentally replaced)
- Restore PowerDisplay and GrabAndMove module DLLs in runner main.cpp (accidentally removed)
- Restore PowerDisplay projects in PowerToys.slnx (accidentally removed)
- Remove duplicate CopyAsUNCLib solution item entry from PowerToys.slnx
- Uncomment GPO check in CopyAsUNCLib/Settings.h (GPO entry already exists in gpo.h)
- Add GPO policy handling for CopyAsUNC toggle in PowerPreviewViewModel.cs
- Use GET_RESOURCE_STRING_FALLBACK for context menu title (localization, per FileLocksmith pattern)
- Add GlobalLock null check in clipboard write (prevent crash on lock failure)
- Remove stale TODO comment from CopyAsUNCContextMenu.vcxproj
- Restore INITCOMMONCONTROLSEX in spell-check expect.txt (used by GrabAndMove)
2026-05-14 11:56:26 +08:00
Wayne Taylor
cbc8ba082c Merge branch 'main' into users/wtt/copy-as-unc 2026-04-30 13:55:47 +01:00
Wayne Taylor
c7b51ae50f Merge branch 'main' into users/wtt/copy-as-unc 2026-04-21 10:54:40 +01:00
Wayne Taylor
87af25a9c4 Address PR review: add GPO support, remove dev cert signing
- Add ConfigureEnabledUtilityCopyAsUNC GPO policy to gpo.h,
  GPOWrapper.h/.idl/.cpp and wire up in PowerToysModule.cpp
- Remove hardcoded self-signed cert signtool post-build step from
  CopyAsUNCContextMenu.vcxproj (CI pipeline handles signing)
- Remove TODO comment from AppxManifest.xml (PowerToys.exe confirmed
  as correct placeholder for modules with no UI executable)

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-11 22:28:31 +00:00
Wayne Taylor
8e6b7f51df Trigger CI re-run 2026-03-11 18:05:07 +00:00
Wayne Taylor
e36980ac1d Apply clang-format and XamlStyler formatting
Run clang-format on CopyAsUNC C++ files and XamlStyler on
PowerPreviewPage.xaml to comply with repo style enforcement rules.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-11 17:52:11 +00:00
Wayne Taylor
35e3cc3ba3 Add CopyAsUNC spell-check allow-list entries
Adds COPYASUNCCONTEXTMENU, COPYASUNCEXT, WNet, and INFOW to the
spell-check expect list. These are preprocessor macro names and
Windows API identifiers flagged as false positives by CI.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-10 20:55:39 +00:00
Wayne Taylor
ad66ec5c35 Add CopyAsUNC to installer, signing pipeline, and WXS
- ESRPSigning_core.json: add CopyAsUNCExt.dll, CopyAsUNCContextMenu.dll,
  CopyAsUNCContextMenuPackage.msix for code signing
- CopyAsUNC.wxs: new installer fragment for Assets\CopyAsUNC\ folder
  (mirrors FileLocksmith.wxs pattern)
- Product.wxs: reference CopyAsUNCComponentGroup
- PowerToysInstallerVNext.wixproj: compile CopyAsUNC.wxs, restore .bk on post-build
- generateAllFileComponents.ps1: generate file components for CopyAsUNC assets

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-10 20:18:43 +00:00
Wayne Taylor
ffe1249d5b Fix context menu icon not rendering: use BMP encoding for small sizes
Regenerated CopyAsUNC.ico with BMP-encoded DIB entries for 16/32/48px
and PNG for 256px. Windows shell requires BMP encoding for small icon
sizes in context menus; PNG-only ICOs fail to render.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-10 20:07:44 +00:00
Wayne Taylor
51fada2e5b Add icon to Copy as UNC context menu entry
Convert SVG icon to multi-size ICO (16/32/48/256px) and wire up
the post-build copy step so GetIcon() can locate it at runtime
from WinUI3Apps\Assets\CopyAsUNC\CopyAsUNC.ico.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-10 17:54:20 +00:00
Wayne Taylor
251ad50b0a Remove unused CopyAsUNC settings library types
The CopyAsUNC module's enable/disable state is held in GeneralSettings,
so no module-specific settings file or types are needed.

Remove CopyAsUNCSettings, CopyAsUNCProperties, CopyAsUNCLocalProperties
and their JsonSerializable registrations.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-10 17:43:37 +00:00
Wayne Taylor
d5cf0cbccd Move Copy as UNC into File Explorer Add-ons page
Per PowerToys team feedback, Copy as UNC is not a standalone utility.
Instead, integrate it as a 'Shell Integration' section on the
File Explorer Add-ons settings page.

- Remove CopyAsUNCPage, CopyAsUNCViewModel, nav entry, module PNGs
- Remove ModuleType.CopyAsUNC (no longer a top-level module type)
- Add IsCopyAsUNCEnabled property to PowerPreviewViewModel, writing
  to GeneralSettings.Enabled.CopyAsUNC via OutGoingGeneralSettings IPC
- Add 'Shell Integration' SettingsGroup to PowerPreviewPage.xaml
  with a toggle for Copy as UNC
- Replace CopyAsUNC-specific resource strings with
  FileExplorerPreview_ShellIntegration and
  FileExplorerPreview_CopyAsUNC_Enable entries

The C++ module, runner integration, and settings library types are
unchanged — only the Settings UI surface is affected.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-10 17:23:29 +00:00
Wayne Taylor
8661924f5c Rename 'Copy as UNC path' to 'Copy as UNC', add nav icon
- Drop 'path' from all display strings for a cleaner, shorter name
- Add CopyAsUNC.png to Assets/Settings/Icons/ so the navigation
  item shows the module icon

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-08 15:52:18 +00:00
Wayne Taylor
7bdfdbba5d Add CopyAsUNCContextMenu to installer uninstall cleanup
Register CopyAsUNCContextMenu sparse package for removal during
uninstall alongside the other context menu packages.

The DLLs and MSIX are automatically included in the installer via the
existing WinUI3ApplicationsFiles component group.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-08 09:33:04 +00:00
Wayne Taylor
cb78fa1a39 Fix unused field compiler error in CopyAsUNCViewModel
Remove _enabledGpoRuleConfiguration field that was assigned but never
read (GPO is stubbed to Unavailable; no conditional logic reads the field).

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-08 09:20:57 +00:00
Wayne Taylor
f30dca8342 Add Copy as UNC path module
Adds a new PowerToys utility that copies the UNC path of files and
folders on mapped network drives to the clipboard via the shell context
menu. When a user right-clicks a file on a mapped drive, the command
resolves the drive letter to its full UNC path using WNetGetUniversalNameW
and writes it to the clipboard.

Components added:
- CopyAsUNCLib: static lib with settings model and singleton
- CopyAsUNCContextMenu: COM shell extension DLL (IExplorerCommand)
  registered via MSIX sparse package
- CopyAsUNCExt: PowertoyModuleIface DLL loaded by the runner
- Settings UI: Library types, ViewModel, XAML page, nav entry,
  localization strings, and serialization context registrations

GPO support is stubbed (returns Unavailable) pending a formal GPO
policy entry.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-08 09:00:30 +00:00
58 changed files with 1863 additions and 5 deletions

View File

@@ -791,10 +791,11 @@ inetcpl
Infobar
INFOEXAMPLE
Infotip
INFOW
initialfile
INITCOMMONCONTROLSEX
INITDIALOG
INITGUID
initialfile
INITTOLOGFONTSTRUCT
INLINEPREFIX
inlines
@@ -2107,7 +2108,7 @@ WNDCLASSEXW
WNDCLASSW
wndproc
wnode
wom
WNet
WORKSPACESEDITOR
WORKSPACESLAUNCHER
WORKSPACESSNAPSHOTTOOL
@@ -2165,4 +2166,455 @@ Zoneszonabletester
Zoomin
zoomit
ZOOMITX
AAAAs
ABORTIFHUNG
acfs
ACIE
ACR
ACTIVATEOPTIONS
ADate
ADMINS
advancedpaste
advapi
agentskills
AHK
AIUI
Allmodule
ALLNOISE
AOklab
aot
APMPOWERSTATUSCHANGE
APMRESUMEAUTOMATIC
APMRESUMESUSPEND
appext
appsfeatures
appxpackage
Aquadrant
ARTIFACTSTAGINGDIRECTORY
Ashcraft
ASUS
AUO
authenticode
azureaiinference
azureinference
azureopenai
Backlight
backticks
Badflags
Badmode
Badparam
BCIE
BIGGERSIZEOK
binskim
blittable
blt
bluelightreduction
bluelightreductionstate
BOklab
Bootstrappers
breadcrumb
BUNDLEINFO
BYCOMMAND
Canvascustomlayout
carlos
Carlseibert
caub
CBN
CDPX
Cds
cer
chatasweetie
checkmarks
Chunghwa
CIBUILD
CIELCh
classguid
classmethod
claude
CLEARTYPE
clientedge
clp
CMN
CODENAME
Coen
cognitiveservices
colorref
commandnotfound
COMPOSITIONDISABLED
constexpr
contentdialog
Convs
coppied
copyable
COPYASUNCCONTEXTMENU
COPYASUNCEXT
coreclr
Corpor
covrun
Cowait
cpptools
cppvsdbg
creativecommons
cropandlock
CROPTOSQUARE
crt
csdevkit
CSOT
CURSORSHOWING
cursorwrap
CUSTOMFORMATPLACEHOLDER
CWMO
Czechia
DAffine
DAFFINETRANSFORM
dbcc
DBT
DCapabilities
ddc
debouncer
Deduplicator
DEFAULTSIZE
defaulttonearest
DESKTOPHORZRES
DESKTOPVERTRES
devenv
DEVICEINTERFACE
devicetype
DEVINTERFACE
DEVNODES
DEVTYP
dfx
diffs
digicert
DINORMAL
displayconfig
diu
dlgmodalframe
downsampled
downsampling
downscale
DPMS
DString
DSVG
dto
dutil
dwflags
Dxva
eab
EAccess
edid
eep
EInvalid
eku
emojis
ENot
ENTRYW
environmentvariables
EProvider
etd
EXECUTEDEFAULT
exf
exprtk
fdw
fdx
FErase
fesf
FFFF
FFh
Figma
fileexploreraddons
fileexplorerpreview
filelocksmith
FInc
findmymouse
FNumber
foundrylocal
framechanged
FRestore
fsanitize
ftps
fuzzingtesting
fxf
gameid
geolocator
GETLBTEXT
gfx
gitmodules
googleai
googlegemini
Gotchas
grctlext
Gridcustomlayout
Hann
Hantai
HDEVNOTIFY
hgdiobj
HHmmssfff
HICONSM
hkmng
HMON
HOOKPROC
hostsfileeditor
Hostx
hotfixes
HPhysical
hredraw
HSpeed
HSync
hutchinsoniana
HWP
ICONONLY
IDOn
ifd
IIM
ILD
inapp
inlines
Inno
Innolux
installdir
intput
invokecommand
ipreviewhandlervisualssetfont
IPTC
irow
isfinite
issuecomment
istep
IUWP
IVO
jeli
JOBOBJECT
Kantai
keycap
keyring
KVM
kvp
LARGEICON
lbl
Lbuttondown
LCh
lcid
lcl
LEFTALIGN
leftclick
Lenovo
LFU
LGD
LIBFUZZER
lightswitch
LIVEDRAW
livezoom
lng
LOCKTYPE
LOGMSG
lon
lpch
LPrivate
lquadrant
makeappx
makepri
Malware
maximizebox
mber
Mbuttondown
mccs
mcp
Metacharacter
metadatamatters
middleclickaction
MIIM
mikeclayton
mikehall
minimizebox
modelcontextprotocol
mousehighlighter
mousejump
mousepointer
mouseutils
MSAL
msdia
MSIs
mstsc
mswhql
muxx
muxxc
muxxh
MVPs
myorg
myrepo
Nanjing
NEWFILEHEADER
nightlight
nodiscard
nologo
nomove
nosize
NOTOPMOST
Notupdated
notwindows
nowarn
NPU
ntfs
nullref
ollama
onebranch
onnx
OOBEUI
openrdp
openurl
Optronics
outputtype
PARENTRELATIVE
PARENTRELATIVEFORUI
PBP
pbrush
PDBs
pdmodels
phicon
PHL
Photoshop
pii
pkgfamily
PKI
PMs
Pomodoro
POWERBROADCAST
powerdisplay
POWERDISPLAYMODULEINTERFACE
ppwsz
Premul
primaryclickaction
processthreadsapi
prot
pscustomobject
Psr
pvct
qdc
QDS
QNN
quickaccent
RAquadrant
rasterization
rasterizing
Rbuttondown
rdp
regsvr
releaseblog
remotedesktop
RENDERFULLCONTENT
rguid
rhk
rollups
rtb
samsung
sancov
screenruler
secondaryclickaction
securestring
selfhost
settingscard
sharpfuzz
shcore
SHELLICONSIZE
SHIL
shk
Signedness
signtool
SIIGBF
slnf
slnx
smileys
snk
Ssn
sszzz
staticedge
staticmethod
steamapps
STGMREAD
streamable
STRSAFE
stuttery
subresource
swp
SWPNOSIZE
SWPNOZORDER
sysmenu
systemai
TARG
taskbar
TESTONLY
TEXTBOXNEWLINE
textextractor
textvariable
tgamma
THEMECHANGED
thickframe
Tianma
tmain
tontrager
tskill
tweakable
UBreak
ubrk
UError
uild
uitests
UITo
Ultrawide
UMax
UMin
unins
Uninstaller
unsubscribes
upscaling
USEINSTALLERFORTEST
uxt
VARTYPE
vcenter
vcp
vcpname
vesa
viewmodels
virama
vnd
vredraw
VSpeed
VSync
WASDK
WCRAPI
wft
wikimedia
wikipedia
windowedge
WINDOWSAPPRUNTIME
windowsml
winexe
winforms
wingetpkgs
winml
wmi
wmsg
wndproc
wom
worktree
xap
XButton
Xbuttondown
xcopy
XDeployment
xdf
XDimension
XLoc
xmp
XPos
XSpeed
XTimer
XXL
YDimension
YPos
YSpeed
YTimer
zamora
zonability
Zorder

View File

@@ -126,6 +126,10 @@
"FileLocksmithContextMenuPackage.msix",
"FileLocksmithCLI.exe",
"WinUI3Apps\\PowerToys.CopyAsUNCExt.dll",
"WinUI3Apps\\PowerToys.CopyAsUNCContextMenu.dll",
"CopyAsUNCContextMenuPackage.msix",
"WinUI3Apps\\Peek.Common.dll",
"WinUI3Apps\\Peek.FilePreviewer.dll",
"WinUI3Apps\\Powertoys.Peek.UI.dll",

View File

@@ -86,3 +86,12 @@ $newPlusContextMenuAppManifestReadFileLocation = $newPlusContextMenuAppManifestW
$newPlusContextMenuAppManifest.Package.Identity.Version = $versionNumber + '.0'
Write-Host "NewPlusContextMenu version" $newPlusContextMenuAppManifest.Package.Identity.Version
$newPlusContextMenuAppManifest.Save($newPlusContextMenuAppManifestWriteFileLocation);
# Set CopyAsUNCContextMenu package version in AppManifest.xml
$copyAsUNCContextMenuAppManifestWriteFileLocation = $PSScriptRoot + '/../src/modules/CopyAsUNC/CopyAsUNCContextMenu/AppxManifest.xml';
$copyAsUNCContextMenuAppManifestReadFileLocation = $copyAsUNCContextMenuAppManifestWriteFileLocation;
[XML]$copyAsUNCContextMenuAppManifest = Get-Content $copyAsUNCContextMenuAppManifestReadFileLocation
$copyAsUNCContextMenuAppManifest.Package.Identity.Version = $versionNumber + '.0'
Write-Host "CopyAsUNCContextMenu version" $copyAsUNCContextMenuAppManifest.Package.Identity.Version
$copyAsUNCContextMenuAppManifest.Save($copyAsUNCContextMenuAppManifestWriteFileLocation);

View File

@@ -9,11 +9,11 @@
<Platform Solution="*|ARM64" Project="ARM64" />
<Platform Solution="*|x64" Project="x64" />
</Project>
<Project Path="src/common/Common.UI/Common.UI.csproj">
<Project Path="src/common/Common.UI.Controls/Common.UI.Controls.csproj">
<Platform Solution="*|ARM64" Project="ARM64" />
<Platform Solution="*|x64" Project="x64" />
</Project>
<Project Path="src/common/Common.UI.Controls/Common.UI.Controls.csproj">
<Project Path="src/common/Common.UI/Common.UI.csproj">
<Platform Solution="*|ARM64" Project="ARM64" />
<Platform Solution="*|x64" Project="x64" />
</Project>
@@ -380,6 +380,11 @@
</Project>
<Project Path="src/modules/cmdpal/Microsoft.Terminal.UI/Microsoft.Terminal.UI.vcxproj" Id="6515f03f-e56d-4db4-b23d-ac4fb80db36f" />
</Folder>
<Folder Name="/modules/CopyAsUNC/">
<Project Path="src/modules/CopyAsUNC/CopyAsUNCContextMenu/CopyAsUNCContextMenu.vcxproj" Id="caa90eba-0776-4e3a-9d71-7e2c95a3c221" />
<Project Path="src/modules/CopyAsUNC/CopyAsUNCExt/CopyAsUNCExt.vcxproj" Id="7d462a53-6ec3-44eb-ae6f-b86ac892c9e3" />
<Project Path="src/modules/CopyAsUNC/CopyAsUNCLib/CopyAsUNCLib.vcxproj" Id="ddb485b8-e771-4b9e-a9b5-bff587daf5ab" />
</Folder>
<Folder Name="/modules/CropAndLock/">
<Project Path="src/modules/CropAndLock/CropAndLock/CropAndLock.vcxproj" Id="f5e1146e-b7b3-4e11-85fd-270a500bd78c" />
<Project Path="src/modules/CropAndLock/CropAndLockModuleInterface/CropAndLockModuleInterface.vcxproj" Id="3157fa75-86cf-4ee2-8f62-c43f776493c6" />

View File

@@ -1429,7 +1429,7 @@ UINT __stdcall UnRegisterContextMenuPackagesCA(MSIHANDLE hInstall)
try
{
// Packages to unregister
const std::vector<std::wstring> packagesToRemoveDisplayName{{L"PowerRenameContextMenu"}, {L"ImageResizerContextMenu"}, {L"FileLocksmithContextMenu"}, {L"NewPlusContextMenu"}};
const std::vector<std::wstring> packagesToRemoveDisplayName{{L"PowerRenameContextMenu"}, {L"ImageResizerContextMenu"}, {L"FileLocksmithContextMenu"}, {L"NewPlusContextMenu"}, {L"CopyAsUNCContextMenu"}};
for (auto const &package : packagesToRemoveDisplayName)
{

View File

@@ -0,0 +1,27 @@
<Wix xmlns="http://wixtoolset.org/schemas/v4/wxs">
<?include $(sys.CURRENTDIR)\Common.wxi?>
<?define CopyAsUNCAssetsFiles=?>
<?define CopyAsUNCAssetsFilesPath=$(var.BinDir)WinUI3Apps\Assets\CopyAsUNC\?>
<Fragment>
<DirectoryRef Id="WinUI3AppsAssetsFolder">
<Directory Id="CopyAsUNCAssetsInstallFolder" Name="CopyAsUNC" />
</DirectoryRef>
<DirectoryRef Id="CopyAsUNCAssetsInstallFolder" FileSource="$(var.CopyAsUNCAssetsFilesPath)">
<!-- Generated by generateFileComponents.ps1 -->
<!--CopyAsUNCAssetsFiles_Component_Def-->
</DirectoryRef>
<ComponentGroup Id="CopyAsUNCComponentGroup">
<Component Id="RemoveCopyAsUNCFolder" Guid="3E5A1B2C-7F4D-4E8A-9C6B-1D2E3F4A5B6C" Directory="CopyAsUNCAssetsInstallFolder">
<RegistryKey Root="$(var.RegistryScope)" Key="Software\Classes\powertoys\components">
<RegistryValue Type="string" Name="RemoveCopyAsUNCFolder" Value="" KeyPath="yes" />
</RegistryKey>
<RemoveFolder Id="RemoveFolderCopyAsUNCAssetsFolder" Directory="CopyAsUNCAssetsInstallFolder" On="uninstall" />
</Component>
</ComponentGroup>
</Fragment>
</Wix>

View File

@@ -34,6 +34,7 @@ call powershell.exe -NonInteractive -executionpolicy Unrestricted -File $(MSBuil
call move /Y ..\..\..\BaseApplications.wxs.bk ..\..\..\BaseApplications.wxs
call move /Y ..\..\..\CmdPal.wxs.bk ..\..\..\CmdPal.wxs
call move /Y ..\..\..\ColorPicker.wxs.bk ..\..\..\ColorPicker.wxs
call move /Y ..\..\..\CopyAsUNC.wxs.bk ..\..\..\CopyAsUNC.wxs
call move /Y ..\..\..\Core.wxs.bk ..\..\..\Core.wxs
call move /Y ..\..\..\DscResources.wxs.bk ..\..\..\DscResources.wxs
call move /Y ..\..\..\EnvironmentVariables.wxs.bk ..\..\..\EnvironmentVariables.wxs
@@ -115,6 +116,7 @@ call powershell.exe -NonInteractive -executionpolicy Unrestricted -File $(MSBuil
<Compile Include="BaseApplications.wxs" />
<Compile Include="CmdPal.wxs" />
<Compile Include="ColorPicker.wxs" />
<Compile Include="CopyAsUNC.wxs" />
<Compile Include="EnvironmentVariables.wxs" />
<Compile Include="FileExplorerPreview.wxs" />
<Compile Include="FileLocksmith.wxs" />

View File

@@ -45,6 +45,7 @@
<ComponentGroupRef Id="WinUI3ApplicationsComponentGroup" />
<ComponentGroupRef Id="AwakeComponentGroup" />
<ComponentGroupRef Id="ColorPickerComponentGroup" />
<ComponentGroupRef Id="CopyAsUNCComponentGroup" />
<ComponentGroupRef Id="FileExplorerPreviewComponentGroup" />
<ComponentGroupRef Id="FileLocksmithComponentGroup" />
<ComponentGroupRef Id="HostsComponentGroup" />

View File

@@ -178,6 +178,10 @@ Generate-FileList -fileDepsJson "" -fileListName MonacoPreviewHandlerCustomLangu
Generate-FileComponents -fileListName "MonacoPreviewHandlerMonacoAssetsFiles" -wxsFilePath $PSScriptRoot\FileExplorerPreview.wxs
Generate-FileComponents -fileListName "MonacoPreviewHandlerCustomLanguagesFiles" -wxsFilePath $PSScriptRoot\FileExplorerPreview.wxs
#CopyAsUNC
Generate-FileList -fileDepsJson "" -fileListName CopyAsUNCAssetsFiles -wxsFilePath $PSScriptRoot\CopyAsUNC.wxs -depsPath "$PSScriptRoot..\..\..\$platform\Release\WinUI3Apps\Assets\CopyAsUNC"
Generate-FileComponents -fileListName "CopyAsUNCAssetsFiles" -wxsFilePath $PSScriptRoot\CopyAsUNC.wxs
#FileLocksmith
Generate-FileList -fileDepsJson "" -fileListName FileLocksmithAssetsFiles -wxsFilePath $PSScriptRoot\FileLocksmith.wxs -depsPath "$PSScriptRoot..\..\..\$platform\Release\WinUI3Apps\Assets\FileLocksmith"
Generate-FileComponents -fileListName "FileLocksmithAssetsFiles" -wxsFilePath $PSScriptRoot\FileLocksmith.wxs

View File

@@ -300,4 +300,8 @@ namespace winrt::PowerToys::GPOWrapper::implementation
{
return static_cast<GpoRuleConfigured>(powertoys_gpo::getConfiguredNewPlusHideBuiltInNewContextMenuValue());
}
GpoRuleConfigured GPOWrapper::GetConfiguredCopyAsUNCEnabledValue()
{
return static_cast<GpoRuleConfigured>(powertoys_gpo::getConfiguredCopyAsUNCEnabledValue());
}
}

View File

@@ -80,6 +80,7 @@ namespace winrt::PowerToys::GPOWrapper::implementation
static GpoRuleConfigured GetConfiguredRunAtStartupValue();
static GpoRuleConfigured GetConfiguredNewPlusReplaceVariablesValue();
static GpoRuleConfigured GetConfiguredNewPlusHideBuiltInNewContextMenuValue();
static GpoRuleConfigured GetConfiguredCopyAsUNCEnabledValue();
};
}

View File

@@ -84,6 +84,7 @@ namespace PowerToys
static GpoRuleConfigured GetConfiguredRunAtStartupValue();
static GpoRuleConfigured GetConfiguredNewPlusReplaceVariablesValue();
static GpoRuleConfigured GetConfiguredNewPlusHideBuiltInNewContextMenuValue();
static GpoRuleConfigured GetConfiguredCopyAsUNCEnabledValue();
}
}
}

View File

@@ -72,6 +72,7 @@ namespace powertoys_gpo
const std::wstring POLICY_CONFIGURE_ENABLED_QOI_THUMBNAILS = L"ConfigureEnabledUtilityFileExplorerQOIThumbnails";
const std::wstring POLICY_CONFIGURE_ENABLED_NEWPLUS = L"ConfigureEnabledUtilityNewPlus";
const std::wstring POLICY_CONFIGURE_ENABLED_WORKSPACES = L"ConfigureEnabledUtilityWorkspaces";
const std::wstring POLICY_CONFIGURE_ENABLED_COPY_AS_UNC = L"ConfigureEnabledUtilityCopyAsUNC";
// The registry value names for PowerToys installer and update policies.
const std::wstring POLICY_DISABLE_PER_USER_INSTALLATION = L"PerUserInstallationDisabled";
@@ -512,6 +513,11 @@ namespace powertoys_gpo
{
return getUtilityEnabledValue(POLICY_CONFIGURE_ENABLED_NEWPLUS);
}
inline gpo_rule_configured_t getConfiguredCopyAsUNCEnabledValue()
{
return getUtilityEnabledValue(POLICY_CONFIGURE_ENABLED_COPY_AS_UNC);
}
#pragma endregion UtilityEnabledStatePolicies
// Individual module setting policies

View File

@@ -0,0 +1,56 @@
<?xml version="1.0" encoding="utf-8"?>
<Package xmlns="http://schemas.microsoft.com/appx/manifest/foundation/windows10"
xmlns:uap="http://schemas.microsoft.com/appx/manifest/uap/windows10"
xmlns:uap2="http://schemas.microsoft.com/appx/manifest/uap/windows10/2"
xmlns:uap3="http://schemas.microsoft.com/appx/manifest/uap/windows10/3"
xmlns:rescap="http://schemas.microsoft.com/appx/manifest/foundation/windows10/restrictedcapabilities"
xmlns:desktop="http://schemas.microsoft.com/appx/manifest/desktop/windows10"
xmlns:desktop4="http://schemas.microsoft.com/appx/manifest/desktop/windows10/4"
xmlns:desktop5="http://schemas.microsoft.com/appx/manifest/desktop/windows10/5"
xmlns:uap10="http://schemas.microsoft.com/appx/manifest/uap/windows10/10"
xmlns:com="http://schemas.microsoft.com/appx/manifest/com/windows10" IgnorableNamespaces="uap uap2 uap3 rescap desktop desktop4 desktop5 uap10 com">
<Identity Name="Microsoft.PowerToys.CopyAsUNCContextMenu" ProcessorArchitecture="neutral" Publisher="CN=Microsoft Corporation, O=Microsoft Corporation, L=Redmond, S=Washington, C=US" Version="1.0.0.0" />
<Properties>
<DisplayName>PowerToys Copy as UNC Context Menu</DisplayName>
<PublisherDisplayName>Microsoft</PublisherDisplayName>
<Logo>Assets\CopyAsUNC\storelogo.png</Logo>
<uap10:AllowExternalContent>true</uap10:AllowExternalContent>
</Properties>
<Resources>
<Resource Language="en-us" />
</Resources>
<Dependencies>
<TargetDeviceFamily Name="Windows.Desktop" MinVersion="10.0.18950.0" MaxVersionTested="10.0.19000.0" />
</Dependencies>
<Capabilities>
<rescap:Capability Name="runFullTrust" />
<rescap:Capability Name="unvirtualizedResources"/>
</Capabilities>
<Applications>
<Application Id="Microsoft.PowerToys.CopyAsUNCContextMenu" Executable="PowerToys.exe" uap10:TrustLevel="mediumIL" uap10:RuntimeBehavior="win32App">
<uap:VisualElements AppListEntry="none" DisplayName="PowerToys Copy as UNC Context Menu" Description="CopyAsUNCContextMenu" BackgroundColor="transparent" Square150x150Logo="Assets\CopyAsUNC\Square150x150Logo.png" Square44x44Logo="Assets\CopyAsUNC\Square44x44Logo.png">
<uap:DefaultTile Wide310x150Logo="Assets\CopyAsUNC\Wide310x150Logo.png" Square310x310Logo="Assets\CopyAsUNC\LargeTile.png" Square71x71Logo="Assets\CopyAsUNC\SmallTile.png"></uap:DefaultTile>
<uap:SplashScreen Image="Assets\CopyAsUNC\SplashScreen.png" />
</uap:VisualElements>
<Extensions>
<desktop4:Extension Category="windows.fileExplorerContextMenus">
<desktop4:FileExplorerContextMenus>
<desktop5:ItemType Type="Directory">
<desktop5:Verb Id="CopyAsUNCCommand" Clsid="89A22F51-9ED6-48FE-81FE-5DFD36F8CD32" />
</desktop5:ItemType>
<desktop5:ItemType Type="*">
<desktop5:Verb Id="CopyAsUNCCommand" Clsid="89A22F51-9ED6-48FE-81FE-5DFD36F8CD32" />
</desktop5:ItemType>
</desktop4:FileExplorerContextMenus>
</desktop4:Extension>
<com:Extension Category="windows.comServer" uap10:RuntimeBehavior="packagedClassicApp">
<com:ComServer>
<com:SurrogateServer DisplayName="Context menu verb handler">
<com:Class Id="89A22F51-9ED6-48FE-81FE-5DFD36F8CD32" Path="PowerToys.CopyAsUNCContextMenu.dll" ThreadingModel="STA"/>
</com:SurrogateServer>
</com:ComServer>
</com:Extension>
</Extensions>
</Application>
</Applications>
</Package>

Binary file not shown.

After

Width:  |  Height:  |  Size: 21 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 964 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 564 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 564 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 564 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 780 B

View File

@@ -0,0 +1,45 @@
#include <windows.h>
#include "Generated Files/resource.h"
#include "../../../common/version/version.h"
#define APSTUDIO_READONLY_SYMBOLS
#include "winres.h"
#undef APSTUDIO_READONLY_SYMBOLS
/////////////////////////////////////////////////////////////////////////////
//
// Version
//
VS_VERSION_INFO VERSIONINFO
FILEVERSION FILE_VERSION
PRODUCTVERSION PRODUCT_VERSION
FILEFLAGSMASK 0x3fL
#ifdef _DEBUG
FILEFLAGS 0x1L
#else
FILEFLAGS 0x0L
#endif
FILEOS 0x40004L
FILETYPE 0x2L
FILESUBTYPE 0x0L
BEGIN
BLOCK "StringFileInfo"
BEGIN
BLOCK "040904b0"
BEGIN
VALUE "CompanyName", COMPANY_NAME
VALUE "FileDescription", FILE_DESCRIPTION
VALUE "FileVersion", FILE_VERSION_STRING
VALUE "InternalName", INTERNAL_NAME
VALUE "LegalCopyright", COPYRIGHT_NOTE
VALUE "OriginalFilename", ORIGINAL_FILENAME
VALUE "ProductName", PRODUCT_NAME
VALUE "ProductVersion", PRODUCT_VERSION_STRING
END
END
BLOCK "VarFileInfo"
BEGIN
VALUE "Translation", 0x409, 1200
END
END

View File

@@ -0,0 +1,161 @@
<?xml version="1.0" encoding="utf-8"?>
<Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
<Import Project="$(RepoRoot)packages\Microsoft.Windows.CppWinRT.2.0.250303.1\build\native\Microsoft.Windows.CppWinRT.props" Condition="Exists('$(RepoRoot)packages\Microsoft.Windows.CppWinRT.2.0.250303.1\build\native\Microsoft.Windows.CppWinRT.props')" />
<Target Name="GenerateResourceFiles" BeforeTargets="PrepareForBuild">
<Exec Command="powershell -NonInteractive -executionpolicy Unrestricted $(RepoRoot)tools\build\convert-resx-to-rc.ps1 $(MSBuildThisFileDirectory) resource.base.h resource.h CopyAsUNCContextMenu.base.rc CopyAsUNCContextMenu.rc" />
</Target>
<PropertyGroup Label="Globals">
<VCProjectVersion>17.0</VCProjectVersion>
<Keyword>Win32Proj</Keyword>
<ProjectGuid>{caa90eba-0776-4e3a-9d71-7e2c95a3c221}</ProjectGuid>
<RootNamespace>CopyAsUNCContextMenu</RootNamespace>
</PropertyGroup>
<PropertyGroup>
<TargetName>PowerToys.CopyAsUNCContextMenu</TargetName>
<!-- Needs a different int dir to avoid conflicts in msix creation. -->
<IntDir>$(SolutionDir)$(Platform)\$(Configuration)\TemporaryBuild\obj\$(ProjectName)\</IntDir>
<OutDir>$(RepoRoot)$(Platform)\$(Configuration)\WinUI3Apps\</OutDir>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)'=='Debug'" Label="Configuration">
<ConfigurationType>DynamicLibrary</ConfigurationType>
<UseDebugLibraries>true</UseDebugLibraries>
<CharacterSet>Unicode</CharacterSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)'=='Release'" Label="Configuration">
<ConfigurationType>DynamicLibrary</ConfigurationType>
<UseDebugLibraries>false</UseDebugLibraries>
<WholeProgramOptimization>true</WholeProgramOptimization>
<CharacterSet>Unicode</CharacterSet>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
<ImportGroup Label="ExtensionSettings">
</ImportGroup>
<ImportGroup Label="Shared">
</ImportGroup>
<ImportGroup Label="PropertySheets">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<PropertyGroup Label="UserMacros" />
<ItemDefinitionGroup Condition="'$(Configuration)'=='Debug'">
<ClCompile>
<WarningLevel>Level3</WarningLevel>
<SDLCheck>true</SDLCheck>
<PreprocessorDefinitions>WIN32;_DEBUG;COPYASUNCCONTEXTMENU_EXPORTS;_WINDOWS;_USRDLL;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<ConformanceMode>true</ConformanceMode>
<AdditionalIncludeDirectories>..;../../..;</AdditionalIncludeDirectories>
</ClCompile>
<Link>
<SubSystem>Windows</SubSystem>
<GenerateDebugInformation>true</GenerateDebugInformation>
<EnableUAC>false</EnableUAC>
<AdditionalDependencies>runtimeobject.lib;Mpr.lib;%(AdditionalDependencies)</AdditionalDependencies>
<ModuleDefinitionFile>Source.def</ModuleDefinitionFile>
</Link>
<PreBuildEvent>
<Command>del $(OutDir)\CopyAsUNCContextMenuPackage.msix /q
MakeAppx.exe pack /d . /p $(OutDir)CopyAsUNCContextMenuPackage.msix /nv</Command>
</PreBuildEvent>
<PostBuildEvent>
<Command>if not exist "$(OutDir)Assets\CopyAsUNC\" mkdir "$(OutDir)Assets\CopyAsUNC\"
xcopy /Y "$(ProjectDir)Assets\CopyAsUNC\CopyAsUNC.ico" "$(OutDir)Assets\CopyAsUNC\"</Command>
</PostBuildEvent>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)'=='Release'">
<ClCompile>
<WarningLevel>Level3</WarningLevel>
<FunctionLevelLinking>true</FunctionLevelLinking>
<IntrinsicFunctions>true</IntrinsicFunctions>
<SDLCheck>true</SDLCheck>
<PreprocessorDefinitions>WIN32;NDEBUG;COPYASUNCCONTEXTMENU_EXPORTS;_WINDOWS;_USRDLL;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<ConformanceMode>true</ConformanceMode>
<AdditionalIncludeDirectories>..;../../..;</AdditionalIncludeDirectories>
</ClCompile>
<Link>
<SubSystem>Windows</SubSystem>
<EnableCOMDATFolding>true</EnableCOMDATFolding>
<OptimizeReferences>true</OptimizeReferences>
<GenerateDebugInformation>true</GenerateDebugInformation>
<EnableUAC>false</EnableUAC>
<AdditionalDependencies>runtimeobject.lib;Mpr.lib;%(AdditionalDependencies)</AdditionalDependencies>
<ModuleDefinitionFile>Source.def</ModuleDefinitionFile>
</Link>
<PreBuildEvent>
<Command>del $(OutDir)\CopyAsUNCContextMenuPackage.msix /q
MakeAppx.exe pack /d . /p $(OutDir)CopyAsUNCContextMenuPackage.msix /nv</Command>
</PreBuildEvent>
<PostBuildEvent>
<Command>if not exist "$(OutDir)Assets\CopyAsUNC\" mkdir "$(OutDir)Assets\CopyAsUNC\"
xcopy /Y "$(ProjectDir)Assets\CopyAsUNC\CopyAsUNC.ico" "$(OutDir)Assets\CopyAsUNC\"</Command>
</PostBuildEvent>
</ItemDefinitionGroup>
<ItemGroup>
<ClInclude Include="framework.h" />
<ClInclude Include="pch.h" />
<ClInclude Include="resource.base.h" />
</ItemGroup>
<ItemGroup>
<ClCompile Include="dllmain.cpp" />
<ClCompile Include="pch.cpp">
<PrecompiledHeader Condition="'$(UsePrecompiledHeaders)' != 'false'">Create</PrecompiledHeader>
</ClCompile>
</ItemGroup>
<ItemGroup>
<None Include="packages.config" />
<None Include="Resources.resx" />
</ItemGroup>
<ItemGroup>
<None Include="Assets\CopyAsUNC\CopyAsUNC.ico">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
<None Include="Assets\CopyAsUNC\LargeTile.png">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
<None Include="Assets\CopyAsUNC\SmallTile.png">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
<None Include="Assets\CopyAsUNC\SplashScreen.png">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
<None Include="Assets\CopyAsUNC\Square150x150Logo.png">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
<None Include="Assets\CopyAsUNC\Square44x44Logo.png">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
<None Include="Assets\CopyAsUNC\storelogo.png">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
<None Include="Assets\CopyAsUNC\Wide310x150Logo.png">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
</ItemGroup>
<ItemGroup>
<ProjectReference Include="$(RepoRoot)src\common\SettingsAPI\SettingsAPI.vcxproj">
<Project>{6955446d-23f7-4023-9bb3-8657f904af99}</Project>
</ProjectReference>
<ProjectReference Include="$(RepoRoot)src\common\version\version.vcxproj">
<Project>{cc6e41ac-8174-4e8a-8d22-85dd7f4851df}</Project>
</ProjectReference>
<ProjectReference Include="..\CopyAsUNCLib\CopyAsUNCLib.vcxproj">
<Project>{ddb485b8-e771-4b9e-a9b5-bff587daf5ab}</Project>
</ProjectReference>
</ItemGroup>
<ItemGroup>
<ResourceCompile Include="CopyAsUNCContextMenu.base.rc" />
</ItemGroup>
<Import Project="$(RepoRoot)deps\spdlog.props" />
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
<ImportGroup Label="ExtensionTargets">
<Import Project="$(RepoRoot)packages\Microsoft.Windows.ImplementationLibrary.1.0.231216.1\build\native\Microsoft.Windows.ImplementationLibrary.targets" Condition="Exists('$(RepoRoot)packages\Microsoft.Windows.ImplementationLibrary.1.0.231216.1\build\native\Microsoft.Windows.ImplementationLibrary.targets')" />
<Import Project="$(RepoRoot)packages\Microsoft.Windows.CppWinRT.2.0.250303.1\build\native\Microsoft.Windows.CppWinRT.targets" Condition="Exists('$(RepoRoot)packages\Microsoft.Windows.CppWinRT.2.0.250303.1\build\native\Microsoft.Windows.CppWinRT.targets')" />
</ImportGroup>
<Target Name="EnsureNuGetPackageBuildImports" BeforeTargets="PrepareForBuild">
<PropertyGroup>
<ErrorText>This project references NuGet package(s) that are missing on this computer. Use NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}.</ErrorText>
</PropertyGroup>
<Error Condition="!Exists('$(RepoRoot)packages\Microsoft.Windows.ImplementationLibrary.1.0.231216.1\build\native\Microsoft.Windows.ImplementationLibrary.targets')" Text="$([System.String]::Format('$(ErrorText)', '$(RepoRoot)packages\Microsoft.Windows.ImplementationLibrary.1.0.231216.1\build\native\Microsoft.Windows.ImplementationLibrary.targets'))" />
<Error Condition="!Exists('$(RepoRoot)packages\Microsoft.Windows.CppWinRT.2.0.250303.1\build\native\Microsoft.Windows.CppWinRT.props')" Text="$([System.String]::Format('$(ErrorText)', '$(RepoRoot)packages\Microsoft.Windows.CppWinRT.2.0.250303.1\build\native\Microsoft.Windows.CppWinRT.props'))" />
<Error Condition="!Exists('$(RepoRoot)packages\Microsoft.Windows.CppWinRT.2.0.250303.1\build\native\Microsoft.Windows.CppWinRT.targets')" Text="$([System.String]::Format('$(ErrorText)', '$(RepoRoot)packages\Microsoft.Windows.CppWinRT.2.0.250303.1\build\native\Microsoft.Windows.CppWinRT.targets'))" />
</Target>
</Project>

View File

@@ -0,0 +1,68 @@
<?xml version="1.0" encoding="utf-8"?>
<root>
<xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
<xsd:import namespace="http://www.w3.org/XML/1998/namespace" />
<xsd:element name="root" msdata:IsDataSet="true">
<xsd:complexType>
<xsd:choice maxOccurs="unbounded">
<xsd:element name="metadata">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" />
</xsd:sequence>
<xsd:attribute name="name" use="required" type="xsd:string" />
<xsd:attribute name="type" type="xsd:string" />
<xsd:attribute name="mimetype" type="xsd:string" />
<xsd:attribute ref="xml:space" />
</xsd:complexType>
</xsd:element>
<xsd:element name="assembly">
<xsd:complexType>
<xsd:attribute name="alias" type="xsd:string" />
<xsd:attribute name="name" type="xsd:string" />
</xsd:complexType>
</xsd:element>
<xsd:element name="data">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
<xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1" />
<xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
<xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
<xsd:attribute ref="xml:space" />
</xsd:complexType>
</xsd:element>
<xsd:element name="resheader">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" />
</xsd:complexType>
</xsd:element>
</xsd:choice>
</xsd:complexType>
</xsd:element>
</xsd:schema>
<resheader name="resmimetype">
<value>text/microsoft-resx</value>
</resheader>
<resheader name="version">
<value>2.0</value>
</resheader>
<resheader name="reader">
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<resheader name="writer">
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<data name="Copy_As_UNC_Context_Menu_Entry" xml:space="preserve">
<value>Copy as UNC path</value>
<comment>This text will be shown when the user opens the context menu (right clicks) a file or folder on a mapped network drive.</comment>
</data>
<data name="Copy_As_UNC_App_Name" xml:space="preserve">
<value>Copy as UNC</value>
</data>
</root>

View File

@@ -0,0 +1,5 @@
LIBRARY
EXPORTS
DllCanUnloadNow PRIVATE
DllGetClassObject PRIVATE
DllGetActivationFactory PRIVATE

View File

@@ -0,0 +1,221 @@
// dllmain.cpp : Defines the entry point for the DLL application.
#include "pch.h"
#include <common/utils/process_path.h>
#include <common/utils/resources.h>
#include "CopyAsUNCLib/Settings.h"
#include <Shlwapi.h>
#include <shobjidl_core.h>
#include <winnetwk.h>
#include <string>
#include <vector>
#include <wrl/module.h>
#include "Generated Files/resource.h"
#pragma comment(lib, "Mpr.lib")
using namespace Microsoft::WRL;
HINSTANCE g_hInst = 0;
BOOL APIENTRY DllMain(HMODULE hModule,
DWORD ul_reason_for_call,
LPVOID lpReserved)
{
switch (ul_reason_for_call)
{
case DLL_PROCESS_ATTACH:
g_hInst = hModule;
break;
case DLL_PROCESS_DETACH:
break;
}
return TRUE;
}
class __declspec(uuid("89A22F51-9ED6-48FE-81FE-5DFD36F8CD32")) CopyAsUNCContextMenuCommand final : public RuntimeClass<RuntimeClassFlags<ClassicCom>, IExplorerCommand, IObjectWithSite>
{
public:
virtual const wchar_t* Title() { return L"Copy as UNC path"; }
virtual const EXPCMDFLAGS Flags() { return ECF_DEFAULT; }
virtual const EXPCMDSTATE State(_In_opt_ IShellItemArray*) { return ECS_ENABLED; }
// IExplorerCommand
IFACEMETHODIMP GetTitle(_In_opt_ IShellItemArray*, _Outptr_result_nullonfailure_ PWSTR* name)
{
return SHStrDup(context_menu_caption.c_str(), name);
}
IFACEMETHODIMP GetIcon(_In_opt_ IShellItemArray*, _Outptr_result_nullonfailure_ PWSTR* icon)
{
std::wstring iconResourcePath = get_module_folderpath(g_hInst);
iconResourcePath += L"\\Assets\\CopyAsUNC\\";
iconResourcePath += L"CopyAsUNC.ico";
return SHStrDup(iconResourcePath.c_str(), icon);
}
IFACEMETHODIMP GetToolTip(_In_opt_ IShellItemArray*, _Outptr_result_nullonfailure_ PWSTR* infoTip)
{
*infoTip = nullptr;
return E_NOTIMPL;
}
IFACEMETHODIMP GetCanonicalName(_Out_ GUID* guidCommandName)
{
*guidCommandName = __uuidof(this);
return S_OK;
}
IFACEMETHODIMP GetState(_In_opt_ IShellItemArray* selection, _In_ BOOL /*okToBeSlow*/, _Out_ EXPCMDSTATE* cmdState)
{
*cmdState = ECS_HIDDEN;
if (!CopyAsUNCSettingsInstance().GetEnabled())
return S_OK;
if (CopyAsUNCSettingsInstance().GetShowInExtendedContextMenu())
return S_OK;
// Only show for items on mapped network drives
if (selection)
{
IShellItem* item = nullptr;
if (SUCCEEDED(selection->GetItemAt(0, &item)))
{
LPWSTR filePath = nullptr;
if (SUCCEEDED(item->GetDisplayName(SIGDN_FILESYSPATH, &filePath)))
{
// Check first 3 chars for drive root (e.g. "Z:\")
std::wstring root(filePath, min((size_t)3, wcslen(filePath)));
if (GetDriveTypeW(root.c_str()) == DRIVE_REMOTE)
{
*cmdState = ECS_ENABLED;
}
CoTaskMemFree(filePath);
}
item->Release();
}
}
return S_OK;
}
IFACEMETHODIMP Invoke(_In_opt_ IShellItemArray* selection, _In_opt_ IBindCtx*) noexcept
{
if (!selection)
return S_OK;
IShellItem* item = nullptr;
if (FAILED(selection->GetItemAt(0, &item)))
return S_OK;
LPWSTR filePath = nullptr;
if (SUCCEEDED(item->GetDisplayName(SIGDN_FILESYSPATH, &filePath)))
{
std::wstring uncPath;
// If already a UNC path, use it directly
if (wcslen(filePath) >= 2 && filePath[0] == L'\\' && filePath[1] == L'\\')
{
uncPath = filePath;
}
else
{
// Resolve mapped drive letter to UNC via WNetGetUniversalName
DWORD bufSize = MAX_PATH * 2;
std::vector<BYTE> buf(bufSize);
DWORD result = WNetGetUniversalNameW(filePath, UNIVERSAL_NAME_INFO_LEVEL, buf.data(), &bufSize);
if (result == ERROR_MORE_DATA)
{
buf.resize(bufSize);
result = WNetGetUniversalNameW(filePath, UNIVERSAL_NAME_INFO_LEVEL, buf.data(), &bufSize);
}
if (result == NO_ERROR)
{
auto info = reinterpret_cast<UNIVERSAL_NAME_INFOW*>(buf.data());
uncPath = info->lpUniversalName;
}
}
if (!uncPath.empty())
{
if (OpenClipboard(nullptr))
{
EmptyClipboard();
size_t byteLen = (uncPath.size() + 1) * sizeof(wchar_t);
HGLOBAL hMem = GlobalAlloc(GMEM_MOVEABLE, byteLen);
if (hMem)
{
void* locked = GlobalLock(hMem);
if (locked)
{
memcpy(locked, uncPath.c_str(), byteLen);
GlobalUnlock(hMem);
if (!SetClipboardData(CF_UNICODETEXT, hMem))
{
GlobalFree(hMem);
}
}
else
{
GlobalFree(hMem);
}
}
CloseClipboard();
}
}
CoTaskMemFree(filePath);
}
item->Release();
return S_OK;
}
IFACEMETHODIMP GetFlags(_Out_ EXPCMDFLAGS* flags)
{
*flags = Flags();
return S_OK;
}
IFACEMETHODIMP EnumSubCommands(_COM_Outptr_ IEnumExplorerCommand** enumCommands)
{
*enumCommands = nullptr;
return E_NOTIMPL;
}
// IObjectWithSite
IFACEMETHODIMP SetSite(_In_ IUnknown* site) noexcept
{
m_site = site;
return S_OK;
}
IFACEMETHODIMP GetSite(_In_ REFIID riid, _COM_Outptr_ void** site) noexcept { return m_site.CopyTo(riid, site); }
protected:
ComPtr<IUnknown> m_site;
std::wstring context_menu_caption = GET_RESOURCE_STRING_FALLBACK(IDS_COPY_AS_UNC_CONTEXT_MENU_ENTRY, L"Copy as UNC path");
};
CoCreatableClass(CopyAsUNCContextMenuCommand)
CoCreatableClassWrlCreatorMapInclude(CopyAsUNCContextMenuCommand)
STDAPI DllGetActivationFactory(_In_ HSTRING activatableClassId, _COM_Outptr_ IActivationFactory** factory)
{
return Module<ModuleType::InProc>::GetModule().GetActivationFactory(activatableClassId, factory);
}
STDAPI DllCanUnloadNow()
{
return Module<InProc>::GetModule().GetObjectCount() == 0 ? S_OK : S_FALSE;
}
STDAPI DllGetClassObject(_In_ REFCLSID rclsid, _In_ REFIID riid, _COM_Outptr_ void** instance)
{
return Module<InProc>::GetModule().GetClassObject(rclsid, riid, instance);
}

View File

@@ -0,0 +1,5 @@
#pragma once
#define WIN32_LEAN_AND_MEAN // Exclude rarely-used stuff from Windows headers
// Windows Header Files
#include <windows.h>

View File

@@ -0,0 +1,5 @@
<?xml version="1.0" encoding="utf-8"?>
<packages>
<package id="Microsoft.Windows.CppWinRT" version="2.0.250303.1" targetFramework="native" />
<package id="Microsoft.Windows.ImplementationLibrary" version="1.0.231216.1" targetFramework="native" />
</packages>

View File

@@ -0,0 +1,5 @@
// pch.cpp: source file corresponding to the pre-compiled header
#include "pch.h"
// When you are using pre-compiled headers, this source file is necessary for compilation to succeed.

View File

@@ -0,0 +1,8 @@
#ifndef PCH_H
#define PCH_H
#include <atlbase.h>
#include "framework.h"
#endif //PCH_H

View File

@@ -0,0 +1,12 @@
//{{NO_DEPENDENCIES}}
// Microsoft Visual C++ generated include file.
//////////////////////////////
// Non-localizable
#define FILE_DESCRIPTION "PowerToys Copy as UNC Context Menu"
#define INTERNAL_NAME "PowerToys.CopyAsUNCContextMenu.dll"
#define ORIGINAL_FILENAME "PowerToys.CopyAsUNCContextMenu.dll"
// Non-localizable
//////////////////////////////

View File

@@ -0,0 +1,40 @@
#include <windows.h>
#include "Generated Files/resource.h"
#include "../../../common/version/version.h"
#define APSTUDIO_READONLY_SYMBOLS
#include "winres.h"
#undef APSTUDIO_READONLY_SYMBOLS
VS_VERSION_INFO VERSIONINFO
FILEVERSION FILE_VERSION
PRODUCTVERSION PRODUCT_VERSION
FILEFLAGSMASK 0x3fL
#ifdef _DEBUG
FILEFLAGS 0x1L
#else
FILEFLAGS 0x0L
#endif
FILEOS 0x40004L
FILETYPE 0x2L
FILESUBTYPE 0x0L
BEGIN
BLOCK "StringFileInfo"
BEGIN
BLOCK "040904b0"
BEGIN
VALUE "CompanyName", COMPANY_NAME
VALUE "FileDescription", FILE_DESCRIPTION
VALUE "FileVersion", FILE_VERSION_STRING
VALUE "InternalName", INTERNAL_NAME
VALUE "LegalCopyright", COPYRIGHT_NOTE
VALUE "OriginalFilename", ORIGINAL_FILENAME
VALUE "ProductName", PRODUCT_NAME
VALUE "ProductVersion", PRODUCT_VERSION_STRING
END
END
BLOCK "VarFileInfo"
BEGIN
VALUE "Translation", 0x409, 1200
END
END

View File

@@ -0,0 +1,114 @@
<?xml version="1.0" encoding="utf-8"?>
<Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
<Import Project="$(RepoRoot)packages\Microsoft.Windows.CppWinRT.2.0.250303.1\build\native\Microsoft.Windows.CppWinRT.props" Condition="Exists('$(RepoRoot)packages\Microsoft.Windows.CppWinRT.2.0.250303.1\build\native\Microsoft.Windows.CppWinRT.props')" />
<Target Name="GenerateResourceFiles" BeforeTargets="PrepareForBuild">
<Exec Command="powershell -NonInteractive -executionpolicy Unrestricted $(RepoRoot)tools\build\convert-resx-to-rc.ps1 $(MSBuildThisFileDirectory) resource.base.h resource.h CopyAsUNCExt.base.rc CopyAsUNCExt.rc" />
</Target>
<PropertyGroup Label="Globals">
<VCProjectVersion>16.0</VCProjectVersion>
<Keyword>Win32Proj</Keyword>
<ProjectGuid>{7d462a53-6ec3-44eb-ae6f-b86ac892c9e3}</ProjectGuid>
<RootNamespace>CopyAsUNCExt</RootNamespace>
<OutDir>$(RepoRoot)$(Platform)\$(Configuration)\WinUI3Apps\</OutDir>
<TargetName>PowerToys.CopyAsUNCExt</TargetName>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)'=='Debug'" Label="Configuration">
<ConfigurationType>DynamicLibrary</ConfigurationType>
<UseDebugLibraries>true</UseDebugLibraries>
<CharacterSet>Unicode</CharacterSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)'=='Release'" Label="Configuration">
<ConfigurationType>DynamicLibrary</ConfigurationType>
<UseDebugLibraries>false</UseDebugLibraries>
<WholeProgramOptimization>true</WholeProgramOptimization>
<CharacterSet>Unicode</CharacterSet>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
<ImportGroup Label="ExtensionSettings">
</ImportGroup>
<ImportGroup Label="Shared">
</ImportGroup>
<ImportGroup Label="PropertySheets">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<PropertyGroup Label="UserMacros" />
<ItemDefinitionGroup Condition="'$(Configuration)'=='Debug'">
<ClCompile>
<WarningLevel>Level3</WarningLevel>
<SDLCheck>true</SDLCheck>
<PreprocessorDefinitions>WIN32;_DEBUG;COPYASUNCEXT_EXPORTS;_WINDOWS;_USRDLL;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<ConformanceMode>true</ConformanceMode>
<AdditionalIncludeDirectories>..;../../;../../../;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
</ClCompile>
<Link>
<SubSystem>Windows</SubSystem>
<GenerateDebugInformation>true</GenerateDebugInformation>
<EnableUAC>false</EnableUAC>
<ModuleDefinitionFile>dll.def</ModuleDefinitionFile>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)'=='Release'">
<ClCompile>
<WarningLevel>Level3</WarningLevel>
<FunctionLevelLinking>true</FunctionLevelLinking>
<IntrinsicFunctions>true</IntrinsicFunctions>
<SDLCheck>true</SDLCheck>
<PreprocessorDefinitions>WIN32;NDEBUG;COPYASUNCEXT_EXPORTS;_WINDOWS;_USRDLL;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<ConformanceMode>true</ConformanceMode>
<AdditionalIncludeDirectories>..;../../;../../../;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
</ClCompile>
<Link>
<SubSystem>Windows</SubSystem>
<EnableCOMDATFolding>true</EnableCOMDATFolding>
<OptimizeReferences>true</OptimizeReferences>
<GenerateDebugInformation>true</GenerateDebugInformation>
<EnableUAC>false</EnableUAC>
<ModuleDefinitionFile>dll.def</ModuleDefinitionFile>
</Link>
</ItemDefinitionGroup>
<ItemGroup>
<ClInclude Include="dllmain.h" />
<ClInclude Include="pch.h" />
<None Include="packages.config" />
<None Include="resource.base.h" />
</ItemGroup>
<ItemGroup>
<ResourceCompile Include="Generated Files/CopyAsUNCExt.rc" />
<None Include="CopyAsUNCExt.base.rc" />
</ItemGroup>
<ItemGroup>
<None Include="Resources.resx" />
<None Include="dll.def" />
</ItemGroup>
<ItemGroup>
<ClCompile Include="dllmain.cpp" />
<ClCompile Include="pch.cpp">
<PrecompiledHeader Condition="'$(UsePrecompiledHeaders)' != 'false'">Create</PrecompiledHeader>
</ClCompile>
<ClCompile Include="PowerToysModule.cpp" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="$(RepoRoot)src\common\logger\logger.vcxproj">
<Project>{d9b8fc84-322a-4f9f-bbb9-20915c47ddfd}</Project>
</ProjectReference>
<ProjectReference Include="$(RepoRoot)src\common\SettingsAPI\SettingsAPI.vcxproj">
<Project>{6955446d-23f7-4023-9bb3-8657f904af99}</Project>
</ProjectReference>
<ProjectReference Include="..\CopyAsUNCLib\CopyAsUNCLib.vcxproj">
<Project>{ddb485b8-e771-4b9e-a9b5-bff587daf5ab}</Project>
</ProjectReference>
</ItemGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
<Import Project="$(RepoRoot)deps\spdlog.props" />
<ImportGroup Label="ExtensionTargets">
<Import Project="$(RepoRoot)packages\Microsoft.Windows.CppWinRT.2.0.250303.1\build\native\Microsoft.Windows.CppWinRT.targets" Condition="Exists('$(RepoRoot)packages\Microsoft.Windows.CppWinRT.2.0.250303.1\build\native\Microsoft.Windows.CppWinRT.targets')" />
</ImportGroup>
<Target Name="EnsureNuGetPackageBuildImports" BeforeTargets="PrepareForBuild">
<PropertyGroup>
<ErrorText>This project references NuGet package(s) that are missing on this computer. Use NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}.</ErrorText>
</PropertyGroup>
<Error Condition="!Exists('$(RepoRoot)packages\Microsoft.Windows.CppWinRT.2.0.250303.1\build\native\Microsoft.Windows.CppWinRT.props')" Text="$([System.String]::Format('$(ErrorText)', '$(RepoRoot)packages\Microsoft.Windows.CppWinRT.2.0.250303.1\build\native\Microsoft.Windows.CppWinRT.props'))" />
<Error Condition="!Exists('$(RepoRoot)packages\Microsoft.Windows.CppWinRT.2.0.250303.1\build\native\Microsoft.Windows.CppWinRT.targets')" Text="$([System.String]::Format('$(ErrorText)', '$(RepoRoot)packages\Microsoft.Windows.CppWinRT.2.0.250303.1\build\native\Microsoft.Windows.CppWinRT.targets'))" />
</Target>
</Project>

View File

@@ -0,0 +1,118 @@
#include "pch.h"
#include <interface/powertoy_module_interface.h>
#include <common/SettingsAPI/settings_objects.h>
#include <common/logger/logger.h>
#include <common/logger/logger_settings.h>
#include <common/utils/logger_helper.h>
#include <common/utils/package.h>
#include <common/utils/process_path.h>
#include "CopyAsUNCLib/Constants.h"
#include "CopyAsUNCLib/Settings.h"
#include "dllmain.h"
#include "Generated Files/resource.h"
class CopyAsUNCModule : public PowertoyModuleIface
{
public:
CopyAsUNCModule()
{
LoggerHelpers::init_logger(constants::nonlocalizable::PowerToyName, L"ModuleInterface", "CopyAsUNC");
init_settings();
}
virtual const wchar_t* get_name() override
{
static WCHAR buffer[128];
LoadStringW(globals::instance, IDS_COPY_AS_UNC_POWERTOYNAME, buffer, ARRAYSIZE(buffer));
return buffer;
}
virtual const wchar_t* get_key() override
{
return constants::nonlocalizable::PowerToyKey;
}
virtual powertoys_gpo::gpo_rule_configured_t gpo_policy_enabled_configuration() override
{
return powertoys_gpo::getConfiguredCopyAsUNCEnabledValue();
}
virtual bool get_config(_Out_ PWSTR buffer, _Out_ int* buffer_size) override
{
HINSTANCE hinstance = reinterpret_cast<HINSTANCE>(&__ImageBase);
PowerToysSettings::Settings settings(hinstance, get_name());
settings.add_bool_toggle(L"bool_show_extended_menu",
L"",
CopyAsUNCSettingsInstance().GetShowInExtendedContextMenu());
return settings.serialize_to_buffer(buffer, buffer_size);
}
virtual void set_config(PCWSTR config) override
{
try
{
PowerToysSettings::PowerToyValues values =
PowerToysSettings::PowerToyValues::from_json_string(config, get_key());
auto extendedMenu = values.get_bool_value(L"bool_show_extended_menu");
if (extendedMenu.has_value())
{
CopyAsUNCSettingsInstance().SetExtendedContextMenuOnly(extendedMenu.value());
CopyAsUNCSettingsInstance().Save();
}
}
catch (std::exception& e)
{
Logger::error("Configuration parsing failed: {}", std::string{ e.what() });
}
}
virtual void enable() override
{
Logger::info(L"Copy as UNC enabled");
if (package::IsWin11OrGreater())
{
std::wstring path = get_module_folderpath(globals::instance);
std::wstring packageUri = path + L"\\CopyAsUNCContextMenuPackage.msix";
if (!package::IsPackageRegisteredWithPowerToysVersion(constants::nonlocalizable::ContextMenuPackageName))
{
package::RegisterSparsePackage(path, packageUri);
}
}
m_enabled = true;
}
virtual void disable() override
{
Logger::info(L"Copy as UNC disabled");
m_enabled = false;
}
virtual bool is_enabled() override
{
return m_enabled;
}
virtual void destroy() override
{
delete this;
}
private:
bool m_enabled = false;
void init_settings()
{
m_enabled = CopyAsUNCSettingsInstance().GetEnabled();
}
};
extern "C" __declspec(dllexport) PowertoyModuleIface* __cdecl powertoy_create()
{
return new CopyAsUNCModule();
}

View File

@@ -0,0 +1,10 @@
<?xml version="1.0" encoding="utf-8"?>
<root>
<resheader name="resmimetype"><value>text/microsoft-resx</value></resheader>
<resheader name="version"><value>2.0</value></resheader>
<resheader name="reader"><value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value></resheader>
<resheader name="writer"><value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value></resheader>
<data name="Copy_As_UNC_PowerToyName" xml:space="preserve">
<value>Copy as UNC</value>
</data>
</root>

View File

@@ -0,0 +1,3 @@
LIBRARY
EXPORTS
powertoy_create

View File

@@ -0,0 +1,25 @@
#include "pch.h"
#pragma comment(lib, "shlwapi")
#include "dllmain.h"
namespace globals
{
HMODULE instance;
}
BOOL APIENTRY DllMain(HMODULE hModule,
DWORD ul_reason_for_call,
LPVOID /*lpReserved*/)
{
switch (ul_reason_for_call)
{
case DLL_PROCESS_ATTACH:
globals::instance = hModule;
break;
case DLL_PROCESS_DETACH:
break;
}
return TRUE;
}

View File

@@ -0,0 +1,8 @@
#pragma once
#include "pch.h"
namespace globals
{
extern HMODULE instance;
}

View File

@@ -0,0 +1,4 @@
<?xml version="1.0" encoding="utf-8"?>
<packages>
<package id="Microsoft.Windows.CppWinRT" version="2.0.250303.1" targetFramework="native" />
</packages>

View File

@@ -0,0 +1,3 @@
// pch.cpp: source file corresponding to the pre-compiled header
#include "pch.h"

View File

@@ -0,0 +1,11 @@
#pragma once
#define WIN32_LEAN_AND_MEAN
#include <Windows.h>
#include <Shlwapi.h>
#include <ShlObj_core.h>
#include <atlbase.h>
#include <atomic>
#include <string>
#include <filesystem>

View File

@@ -0,0 +1,14 @@
//{{NO_DEPENDENCIES}}
// Microsoft Visual C++ generated include file.
//////////////////////////////
// Non-localizable
#define IDS_COPY_AS_UNC_POWERTOYNAME 101
#define FILE_DESCRIPTION "PowerToys Copy as UNC Module Interface"
#define INTERNAL_NAME "PowerToys.CopyAsUNCExt.dll"
#define ORIGINAL_FILENAME "PowerToys.CopyAsUNCExt.dll"
// Non-localizable
//////////////////////////////

View File

@@ -0,0 +1,22 @@
#pragma once
#include "pch.h"
// Non-localizable constants
namespace constants::nonlocalizable
{
// String key used by PowerToys runner
constexpr WCHAR PowerToyKey[] = L"Copy as UNC";
// Nonlocalized name of this PowerToy, for logs, etc.
constexpr WCHAR PowerToyName[] = L"CopyAsUNC";
// JSON key used to store extended menu enabled
constexpr WCHAR JsonKeyShowInExtendedContextMenu[] = L"showInExtendedContextMenu";
// Path of the JSON file used to store settings
constexpr WCHAR DataFilePath[] = L"\\copy-as-unc-settings.json";
// Name of the tier 1 context menu package
constexpr WCHAR ContextMenuPackageName[] = L"CopyAsUNCContextMenu";
}

View File

@@ -0,0 +1,86 @@
<?xml version="1.0" encoding="utf-8"?>
<Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
<Import Project="$(RepoRoot)packages\Microsoft.Windows.CppWinRT.2.0.250303.1\build\native\Microsoft.Windows.CppWinRT.props" Condition="Exists('$(RepoRoot)packages\Microsoft.Windows.CppWinRT.2.0.250303.1\build\native\Microsoft.Windows.CppWinRT.props')" />
<PropertyGroup Label="Globals">
<VCProjectVersion>17.0</VCProjectVersion>
<Keyword>Win32Proj</Keyword>
<ProjectGuid>{ddb485b8-e771-4b9e-a9b5-bff587daf5ab}</ProjectGuid>
<RootNamespace>CopyAsUNCLib</RootNamespace>
<WindowsTargetPlatformVersion>10.0</WindowsTargetPlatformVersion>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)'=='Debug'" Label="Configuration">
<ConfigurationType>StaticLibrary</ConfigurationType>
<UseDebugLibraries>true</UseDebugLibraries>
<CharacterSet>Unicode</CharacterSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)'=='Release'" Label="Configuration">
<ConfigurationType>StaticLibrary</ConfigurationType>
<UseDebugLibraries>false</UseDebugLibraries>
<CharacterSet>Unicode</CharacterSet>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
<ImportGroup Label="ExtensionSettings">
</ImportGroup>
<ImportGroup Label="Shared">
</ImportGroup>
<ImportGroup Label="PropertySheets">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<PropertyGroup Label="UserMacros" />
<ItemDefinitionGroup Condition="'$(Configuration)'=='Debug'">
<ClCompile>
<WarningLevel>Level3</WarningLevel>
<SDLCheck>true</SDLCheck>
<PreprocessorDefinitions>WIN32;_DEBUG;_LIB;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<ConformanceMode>true</ConformanceMode>
<AdditionalIncludeDirectories>../../..;</AdditionalIncludeDirectories>
</ClCompile>
<Link>
<GenerateDebugInformation>true</GenerateDebugInformation>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)'=='Release'">
<ClCompile>
<WarningLevel>Level3</WarningLevel>
<FunctionLevelLinking>true</FunctionLevelLinking>
<IntrinsicFunctions>true</IntrinsicFunctions>
<SDLCheck>true</SDLCheck>
<PreprocessorDefinitions>WIN32;NDEBUG;_LIB;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<ConformanceMode>true</ConformanceMode>
<AdditionalIncludeDirectories>../../..;</AdditionalIncludeDirectories>
</ClCompile>
<Link>
<EnableCOMDATFolding>true</EnableCOMDATFolding>
<OptimizeReferences>true</OptimizeReferences>
<GenerateDebugInformation>true</GenerateDebugInformation>
</Link>
</ItemDefinitionGroup>
<ItemGroup>
<ClInclude Include="Constants.h" />
<ClInclude Include="Settings.h" />
<ClInclude Include="framework.h" />
<ClInclude Include="pch.h" />
</ItemGroup>
<ItemGroup>
<ClCompile Include="Settings.cpp" />
<ClCompile Include="pch.cpp">
<PrecompiledHeader Condition="'$(UsePrecompiledHeaders)' != 'false'">Create</PrecompiledHeader>
</ClCompile>
</ItemGroup>
<ItemGroup>
<None Include="packages.config" />
</ItemGroup>
<Import Project="$(RepoRoot)deps\spdlog.props" />
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
<ImportGroup Label="ExtensionTargets">
<Import Project="$(RepoRoot)packages\Microsoft.Windows.CppWinRT.2.0.250303.1\build\native\Microsoft.Windows.CppWinRT.targets" Condition="Exists('$(RepoRoot)packages\Microsoft.Windows.CppWinRT.2.0.250303.1\build\native\Microsoft.Windows.CppWinRT.targets')" />
</ImportGroup>
<Target Name="EnsureNuGetPackageBuildImports" BeforeTargets="PrepareForBuild">
<PropertyGroup>
<ErrorText>This project references NuGet package(s) that are missing on this computer. Use NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}.</ErrorText>
</PropertyGroup>
<Error Condition="!Exists('$(RepoRoot)packages\Microsoft.Windows.CppWinRT.2.0.250303.1\build\native\Microsoft.Windows.CppWinRT.props')" Text="$([System.String]::Format('$(ErrorText)', '$(RepoRoot)packages\Microsoft.Windows.CppWinRT.2.0.250303.1\build\native\Microsoft.Windows.CppWinRT.props'))" />
<Error Condition="!Exists('$(RepoRoot)packages\Microsoft.Windows.CppWinRT.2.0.250303.1\build\native\Microsoft.Windows.CppWinRT.targets')" Text="$([System.String]::Format('$(ErrorText)', '$(RepoRoot)packages\Microsoft.Windows.CppWinRT.2.0.250303.1\build\native\Microsoft.Windows.CppWinRT.targets'))" />
</Target>
</Project>

View File

@@ -0,0 +1,112 @@
#include "pch.h"
#include "Settings.h"
#include "Constants.h"
#include <filesystem>
#include <common/utils/json.h>
#include <common/SettingsAPI/settings_helpers.h>
static bool LastModifiedTime(const std::wstring& filePath, FILETIME* lpFileTime)
{
WIN32_FILE_ATTRIBUTE_DATA attr{};
if (GetFileAttributesExW(filePath.c_str(), GetFileExInfoStandard, &attr))
{
*lpFileTime = attr.ftLastWriteTime;
return true;
}
return false;
}
CopyAsUNCSettings::CopyAsUNCSettings()
{
generalJsonFilePath = PTSettingsHelper::get_powertoys_general_save_file_location();
std::wstring savePath = PTSettingsHelper::get_module_save_folder_location(constants::nonlocalizable::PowerToyKey);
std::error_code ec;
jsonFilePath = savePath + constants::nonlocalizable::DataFilePath;
RefreshEnabledState();
Load();
}
void CopyAsUNCSettings::Save()
{
json::JsonObject jsonData;
jsonData.SetNamedValue(constants::nonlocalizable::JsonKeyShowInExtendedContextMenu, json::value(settings.showInExtendedContextMenu));
json::to_file(jsonFilePath, jsonData);
GetSystemTimeAsFileTime(&lastLoadedTime);
}
void CopyAsUNCSettings::Load()
{
if (!std::filesystem::exists(jsonFilePath))
{
Save();
}
else
{
ParseJson();
}
}
void CopyAsUNCSettings::RefreshEnabledState()
{
FILETIME lastModifiedTime{};
if (!(LastModifiedTime(generalJsonFilePath, &lastModifiedTime) &&
CompareFileTime(&lastModifiedTime, &lastLoadedGeneralSettingsTime) == 1))
return;
lastLoadedGeneralSettingsTime = lastModifiedTime;
auto json = json::from_file(generalJsonFilePath);
if (!json)
return;
const json::JsonObject& jsonSettings = json.value();
try
{
json::JsonObject modulesEnabledState;
json::get(jsonSettings, L"enabled", modulesEnabledState, json::JsonObject{});
json::get(modulesEnabledState, L"Copy as UNC", settings.enabled, true);
}
catch (const winrt::hresult_error&)
{
}
}
void CopyAsUNCSettings::Reload()
{
FILETIME lastModifiedTime{};
if (LastModifiedTime(jsonFilePath, &lastModifiedTime) &&
CompareFileTime(&lastModifiedTime, &lastLoadedTime) == 1)
{
Load();
}
}
void CopyAsUNCSettings::ParseJson()
{
auto json = json::from_file(jsonFilePath);
if (json)
{
const json::JsonObject& jsonSettings = json.value();
try
{
if (json::has(jsonSettings, constants::nonlocalizable::JsonKeyShowInExtendedContextMenu, json::JsonValueType::Boolean))
{
settings.showInExtendedContextMenu = jsonSettings.GetNamedBoolean(constants::nonlocalizable::JsonKeyShowInExtendedContextMenu);
}
}
catch (const winrt::hresult_error&)
{
}
}
GetSystemTimeAsFileTime(&lastLoadedTime);
}
CopyAsUNCSettings& CopyAsUNCSettingsInstance()
{
static CopyAsUNCSettings instance;
return instance;
}

View File

@@ -0,0 +1,53 @@
#pragma once
#include "pch.h"
#include <common/utils/gpo.h>
class CopyAsUNCSettings
{
public:
CopyAsUNCSettings();
inline bool GetEnabled()
{
auto gpoSetting = powertoys_gpo::getConfiguredCopyAsUNCEnabledValue();
if (gpoSetting == powertoys_gpo::gpo_rule_configured_enabled) return true;
if (gpoSetting == powertoys_gpo::gpo_rule_configured_disabled) return false;
Reload();
RefreshEnabledState();
return settings.enabled;
}
inline bool GetShowInExtendedContextMenu() const
{
return settings.showInExtendedContextMenu;
}
inline void SetExtendedContextMenuOnly(bool extendedOnly)
{
settings.showInExtendedContextMenu = extendedOnly;
}
void Save();
void Load();
private:
struct Settings
{
bool enabled{ true };
bool showInExtendedContextMenu{ false };
};
void RefreshEnabledState();
void Reload();
void ParseJson();
Settings settings;
std::wstring generalJsonFilePath;
std::wstring jsonFilePath;
FILETIME lastLoadedTime{};
FILETIME lastLoadedGeneralSettingsTime{};
};
CopyAsUNCSettings& CopyAsUNCSettingsInstance();

View File

@@ -0,0 +1,5 @@
#pragma once
#define WIN32_LEAN_AND_MEAN // Exclude rarely-used stuff from Windows headers
// Windows Header Files
#include <windows.h>

View File

@@ -0,0 +1,4 @@
<?xml version="1.0" encoding="utf-8"?>
<packages>
<package id="Microsoft.Windows.CppWinRT" version="2.0.250303.1" targetFramework="native" />
</packages>

View File

@@ -0,0 +1,5 @@
// pch.cpp: source file corresponding to the pre-compiled header
#include "pch.h"
// When you are using pre-compiled headers, this source file is necessary for compilation to succeed.

View File

@@ -0,0 +1,9 @@
#ifndef PCH_H
#define PCH_H
#include <atlbase.h>
#include <string>
#include "framework.h"
#endif //PCH_H

View File

@@ -288,6 +288,7 @@ int runner(bool isProcessElevated, bool openSettings, std::string settingsWindow
L"PowerToys.LightSwitchModuleInterface.dll",
L"PowerToys.PowerDisplayModuleInterface.dll",
L"PowerToys.GrabAndMoveModuleInterface.dll",
L"WinUI3Apps/PowerToys.CopyAsUNCExt.dll",
};
for (auto moduleSubdir : knownModules)

View File

@@ -809,6 +809,8 @@ std::string ESettingsWindowNames_to_string(ESettingsWindowNames value)
return "PowerDisplay";
case ESettingsWindowNames::GrabAndMove:
return "GrabAndMove";
case ESettingsWindowNames::CopyAsUNC:
return "CopyAsUNC";
default:
{
Logger::error(L"Can't convert ESettingsWindowNames value={} to string", static_cast<int>(value));
@@ -956,6 +958,10 @@ ESettingsWindowNames ESettingsWindowNames_from_string(std::string value)
{
return ESettingsWindowNames::GrabAndMove;
}
else if (value == "CopyAsUNC")
{
return ESettingsWindowNames::CopyAsUNC;
}
else
{
Logger::error(L"Can't convert string value={} to ESettingsWindowNames", winrt::to_hstring(value));

View File

@@ -38,6 +38,7 @@ enum class ESettingsWindowNames
ZoomIt,
PowerDisplay,
GrabAndMove,
CopyAsUNC,
};
std::string ESettingsWindowNames_to_string(ESettingsWindowNames value);

View File

@@ -366,6 +366,22 @@ namespace Microsoft.PowerToys.Settings.UI.Library
}
}
private bool copyAsUNC = true;
[JsonPropertyName("Copy as UNC")]
public bool CopyAsUNC
{
get => copyAsUNC;
set
{
if (copyAsUNC != value)
{
LogTelemetryEvent(value);
copyAsUNC = value;
}
}
}
private bool fileLocksmith = true;
[JsonPropertyName("File Locksmith")]

View File

@@ -279,6 +279,18 @@
</tkcontrols:SettingsExpander.Items>
</tkcontrols:SettingsExpander>
</controls:SettingsGroup>
<controls:SettingsGroup x:Uid="FileExplorerPreview_ShellIntegration">
<tkcontrols:SettingsCard
Name="FileExplorerPreviewCopyAsUNCEnable"
x:Uid="FileExplorerPreview_CopyAsUNC_Enable"
HeaderIcon="{ui:FontIcon Glyph=&#xE8C8;}"
IsEnabled="{x:Bind ViewModel.CopyAsUNCIsGpoDisabled, Mode=OneWay, Converter={StaticResource BoolNegationConverter}}">
<ToggleSwitch
x:Uid="ToggleSwitch"
IsEnabled="{x:Bind ViewModel.CopyAsUNCIsGpoEnabled, Mode=OneWay, Converter={StaticResource BoolNegationConverter}}"
IsOn="{x:Bind ViewModel.IsCopyAsUNCEnabled, Mode=TwoWay}" />
</tkcontrols:SettingsCard>
</controls:SettingsGroup>
</StackPanel>
</controls:SettingsPageControl.ModuleContent>

View File

@@ -3774,6 +3774,14 @@ Activate by holding the key for the character you want to add an accent to, then
<value>Press duration before showing taskbar icon shortcuts (ms)</value>
<comment>ms = milliseconds</comment>
</data>
<data name="FileExplorerPreview_ShellIntegration.Header" xml:space="preserve">
<value>Shell integration</value>
<comment>This refers to directly integrating in with the Windows shell</comment>
</data>
<data name="FileExplorerPreview_CopyAsUNC_Enable.Header" xml:space="preserve">
<value>Copy as UNC</value>
<comment>Copy as UNC is the name of the utility; do not loc</comment>
</data>
<data name="FileLocksmith.ModuleDescription" xml:space="preserve">
<value>A Windows shell extension to find out which processes are using the selected files and directories.</value>
<comment>{Locked="Windows"}</comment>

View File

@@ -225,6 +225,17 @@ namespace Microsoft.PowerToys.Settings.UI.ViewModels
_stlThumbnailColor = Settings.Properties.StlThumbnailColor.Value;
_isCopyAsUNCEnabled = GeneralSettingsConfig.Enabled.CopyAsUNC;
_copyAsUNCEnabledGpoRuleConfiguration = GPOWrapper.GetConfiguredCopyAsUNCEnabledValue();
if (_copyAsUNCEnabledGpoRuleConfiguration == GpoRuleConfigured.Disabled || _copyAsUNCEnabledGpoRuleConfiguration == GpoRuleConfigured.Enabled)
{
// Get the enabled state from GPO.
_copyAsUNCEnabledStateIsGPOConfigured = true;
_isCopyAsUNCEnabled = _copyAsUNCEnabledGpoRuleConfiguration == GpoRuleConfigured.Enabled;
_copyAsUNCIsGpoEnabled = _copyAsUNCEnabledGpoRuleConfiguration == GpoRuleConfigured.Enabled;
_copyAsUNCIsGpoDisabled = _copyAsUNCEnabledGpoRuleConfiguration == GpoRuleConfigured.Disabled;
}
_qoiThumbnailEnabledGpoRuleConfiguration = GPOWrapper.GetConfiguredQoiThumbnailsEnabledValue();
if (_qoiThumbnailEnabledGpoRuleConfiguration == GpoRuleConfigured.Disabled || _qoiThumbnailEnabledGpoRuleConfiguration == GpoRuleConfigured.Enabled)
{
@@ -1102,6 +1113,56 @@ namespace Microsoft.PowerToys.Settings.UI.ViewModels
}
}
private GpoRuleConfigured _copyAsUNCEnabledGpoRuleConfiguration;
private bool _copyAsUNCEnabledStateIsGPOConfigured;
private bool _copyAsUNCIsGpoEnabled;
private bool _copyAsUNCIsGpoDisabled;
private bool _isCopyAsUNCEnabled;
public bool IsCopyAsUNCEnabled
{
get => _isCopyAsUNCEnabled;
set
{
if (_copyAsUNCEnabledStateIsGPOConfigured)
{
return;
}
if (_isCopyAsUNCEnabled != value)
{
_isCopyAsUNCEnabled = value;
GeneralSettingsConfig.Enabled.CopyAsUNC = value;
OnPropertyChanged(nameof(IsCopyAsUNCEnabled));
OutGoingGeneralSettings outgoing = new OutGoingGeneralSettings(GeneralSettingsConfig);
SendConfigMSG(outgoing.ToString());
}
}
}
public bool IsCopyAsUNCEnabledGpoConfigured
{
get => _copyAsUNCEnabledStateIsGPOConfigured;
}
public bool CopyAsUNCIsGpoEnabled
{
get
{
return _copyAsUNCIsGpoEnabled;
}
}
// Used to disable the settings card on forced disabled state.
public bool CopyAsUNCIsGpoDisabled
{
get
{
return _copyAsUNCIsGpoDisabled;
}
}
private void RaisePropertyChanged([CallerMemberName] string propertyName = null)
{
// Notify UI of property change