Open cjee21 opened 1 week ago
Note: Open source code licensed under GPL and MIT from Microsoft, NanaZip and Npp were referenced in the making of this PR. Although code in this PR is not identical to any of the referenced code, it should be ensured that there are no licensing issues. I am not a legal expert.
MSVC2019 to MSVC2022 stuff
A question, the project files for the new DLLs are only in MSVC2022. In that case how to go about in the installer script?
Then for this PR: PNG should go in
\Source\Resource\Image\Assets
.
I put it there so that is is easier to re-generate the .pri file because everything has to be in the correct folder structure as what is in a MSIX. Do you still want to move it?
Manifest.rc/xml deletion (not used?)
It is not currently used by C++Builder, a default manifest from C++Builder's directory is used. I deleted it in the same commit as adding Manifest.manifest
so that there remains only the in-use manifest to prevent confusion.
$(BDS)
to..\..
This is replacing the default manifest from C++Builder's directory with the new Manifest.manifest
for package identity.
Done most of the changes discussed. I've totally removed changes with the GUI. I still have no clear idea how to go about it so you can give it a look/try.
I deleted it in the same commit as adding Manifest.manifest so that there remains only the in-use manifest to prevent confusion.
If I understand correctly this is independent from the Win11 context menu and useful as standalone. If so please a separate PR.
A question, the project files for the new DLLs are only in MSVC2022. In that case how to go about in the installer script?
It seems that we have a coherency problem, we should go with MSVC2022 everywhere, we check. cc @g-maxime.
I put it there so that is is easier to re-generate the .pri file because everything has to be in the correct folder structure as what is in a MSIX. Do you still want to move it?
I prefer to have all MediaInfo logs at the same place when not to complicated, and also I don't like to have the .pri (a binary file?) if not source in the source code. How is built the .pri? Would it make sense to have the logo files in the Source\Resource\Image\Assets
and have a cmd (referenced in the project) which copy the file to the expected place and build the .pri?
Not a big deal if you prefer to keep it as is, we will check later if we can improve the build if you prefer to keep as is.
I deleted it in the same commit as adding Manifest.manifest so that there remains only the in-use manifest to prevent confusion.
If I understand correctly this is independent from the Win11 context menu and useful as standalone. If so please a separate PR.
The manifest is for granting package identity to MediaInfo GUI. It goes along with the sparse package.
Would it make sense to have the logo files in the
Source\Resource\Image\Assets
and have a cmd (referenced in the project) which copy the file to the expected place and build the .pri? Not a big deal if you prefer to keep it as is, we will check later if we can improve the build if you prefer to keep as is.
The .pri only needs to be rebuilt when there is a change to the resources. If you prefer to rebuild it everytime, I will let you make the change. Guide: https://learn.microsoft.com/en-us/windows/msix/desktop/desktop-to-uwp-manual-conversion#generate-a-package-resource-index-pri-file-using-makepri
The manifest is for granting package identity to MediaInfo GUI. It goes along with the sparse package.
OK.
The .pri only needs to be rebuilt when there is a change to the resources. If you prefer to rebuild it everytime, I will let you make the change.
OK, let's keep as is for the moment, You already do a lot and we'll manage the rebuild on our side (no need to be automatic, usually it is done by a check if the source files are younger than the binary, anyway we'll manage that).
I remark only now that we still build with MSVC2019 on our build farm, we'll migrate in order to be able to test this PR.
The manifest is for granting package identity to MediaInfo GUI. It goes along with the sparse package.
I change my mind: my understanding now is that it does not hurt to switch to this manifest even without building the sparse package. If so, please a separate PR with the BCB project modification + manifest, and I merge and build with this change, so this part is ready without waiting for the merge of this PR.
Okay, tested the current state of this branch:
* = effect of updated manifest ^ = effect of removing the GUI changes
The old context menu is still shown so duplicate.^ The GUI Preferences only controls the old context menu.^
Theses ones were not expected.
I see code in WindowsShellExtension
handling the registry key. Isn't it possible to just launch WindowsShellExtension
when the preference window is closed?
My concern is to avoid creating more registry keys and touch as few things as possible, not to remove everything.
Theses ones were not expected. I see code in
WindowsShellExtension
handling the registry key. Isn't it possible to just launchWindowsShellExtension
when the preference window is closed? My concern is to avoid creating more registry keys and touch as few things as possible, not to remove everything.
Let me try to explain in simple way how it works.
The new DLL for shell extension needs to be registered as a context menu handler.
Once registered, when files are right-clicked in Explorer, Explorer will check list of registered handlers for that file extension. It will load the DLL in COM Surrogate / DLLHost (because it does not trust third party DLLs that may crash). This can be observed using Process Explorer from Sysinternals.
Then it calls the functions in our DLLMain.cpp after calling the entrypoint to get the COM interface.
When we click on the menu entry, Invoke function is called by Explorer.
About 10 seconds after the context menu is dismissed, our DLL will be unloaded by File Explorer from DLLHost. This can be observed using Process Explorer from Sysinternals.
So what else needs to be done in this PR? For the Qt version, there is no other shell extensions to deal with and the Qt GUI already writes all its Preferences settings to the registry. So all is well and working properly. We can ignore Qt one now. For the VCL one, this is where things have to be done. What needs to be done that I not yet do is...
Software\\MediaArea\\MediaInfo - ShellExtension DWORD = 0
when Preferences for shell is disabled by user and delete ShellExtension DWORD
if enabled. Delete instead of setting to 1 since it is enabled by default so most people likely have it enabled so we avoid leaving registry keys behind since this is per user and can't be removed by uninstaller.Took a look at the codes for handling old context menu again and came up with a better solution. Appears to work properly on Windows 11 now. No duplicate entries and can control appearance of the new shell extension. Just need to test on Windows 10 and portable to ensure there is no change to existing behaviour there.
Note: we should consider adding notifying Windows Shell to refresh list of context menu upon installation/uninstallation. Else both the new and old menu entries will not appear after installation until Windows refreshes itself or something triggers a refresh althoough they are enabled by default. It will prevent issues like: https://sourceforge.net/p/mediainfo/support-requests/51/
Also, this bug: https://sourceforge.net/p/mediainfo/bugs/1161/ is reproducible and is now causing duplicate entries in 'classic' context menu for mp3 files etc.
UPDATE: Seems this is caused by MediaInfo still associated with audio
and video
in registry. Something in the old codes is not deleting properly. So basically, all these years, the existing context menu actually cannot be disabled completely. It is weird that it affects only some files like mp3 though because others like flac is also classified as audio in Windows.
Seems there is some registry left behind for some file extensions even after uninstall
There are issues with existing (old) context menu implementation. In Preferences.cpp ShellExtension there are 144 extensions listed. In Preferences.cpp InfoTip there are 114 extensions listed. In MediaInfo_Extensions_Install there are 145 extensions listed. In MediaInfo_Extensions_Uninstall there are 141 extensions listed.
Force push adds avif, avs, heic, heif, iamf, ico, jxl and webp to extensions list in manifest and changes webm to lower case.
Took a look at the codes for handling old context menu again and came up with a better solution.
Thank you, it seems less complicated than the previous proposal.
Also, this bug: https://sourceforge.net/p/mediainfo/bugs/1161/ is reproducible and is now causing duplicate entries in 'classic' context menu for mp3 files etc. UPDATE: Seems this is caused by MediaInfo still associated with audio and video in registry. Something in the old codes is not deleting properly. So basically, all these years, the existing context menu actually cannot be disabled completely. It is weird that it affects only some files like mp3 though because others like flac is also classified as audio in Windows.
Ha, I see! But so weird, indeed. I don't see an easy solution... Maybe just removing video
& audio
if it does not work well enough, and we manage our own list completely.
I don't see an easy solution... Maybe just removing
video
&audio
if it does not work well enough, and we manage our own list completely.
I agree with this. But issue now is making sure all unwanted registry entries are correctly removed on uninstall or upgrade of MediaInfo.
But issue now is making sure all unwanted registry entries are correctly removed on uninstall or upgrade of MediaInfo.
Would you mind to add a PR about it? It seems that you see better than me the issue there.
But issue now is making sure all unwanted registry entries are correctly removed on uninstall or upgrade of MediaInfo.
Would you mind to add a PR about it? It seems that you see better than me the issue there.
Looks like the GUI is trying the wrong key that's why fail to disable for audio
and video
. There is no such thing as HKCU\SystemFileAssociations
Also I think the old shell will be re-enabled everytime MediaInfo is updated for those who disabled it until they open MediaInfo.
@JeromeMartinez I merged all my currently open PRs to a branch and made a test build. Everything seems to be in order now. Both context menu entry appears automatically after install, old one gets disabled on first launch of MediaInfo, no duplicate entries after that, can enable/disable shell extension and after uninstall, no registry entries that are written by MediaInfo are left behind.
Just a rebase, so that can test properly without the other bugs.
If we were to use the same DLL shell extension for older Windows versions, this is probably the way to do it: https://learn.microsoft.com/en-us/windows/win32/shell/reg-shell-exts#example-of-an-extension-handler-registration
If we were to use the same DLL shell extension for older Windows versions, this is probably the way to do it:
Thank you. I am not sure I want to spend the time on that but I would be happy to get an update if you wish to do so. For the moment, the important part is Win11 integration (including the tooltip), it is less important for older versions.
Thank you. I am not sure I want to spend the time on that but I would be happy to get an update if you wish to do so.
I do not want to spend time on Windows versions that will soon be end-of-support too and risk breaking things. The only benefit for older Windows versions is opening multiple files in the same instance and maybe some simplification of old codes.
For the moment, the important part is Win11 integration (including the tooltip), it is less important for older versions.
Context menu is working fine so far and can now be independently controlled for folders as well after the last commit. ToolTip is already working when I tested after seeing issue 809 that day.
PS No idea how Windows decides the order to show menu items in the modern context menu but MediaInfo seems to always be the first entry on my PC.
btw it is possible to sign the NSIS uninstaller too to prevent yellow Windows warning when executing uninstall https://nsis.sourceforge.io/Docs/Chapter5.html#uninstfinalize
There's also a note at https://nsis.sourceforge.io/Signing_an_Uninstaller that says:
Note 2: Running a dummy command with !uninstfinalize may also be useful if only the installer will be signed. This could prevent bogus header fields in the uninstaller, see feature request ticket #577
btw it is possible to sign the NSIS uninstaller too to prevent yellow Windows warning when executing uninstall
It was the case several years ago and at some point it disappeared, I was too lazy for finding the reason :(.
btw it is possible to sign the NSIS uninstaller too to prevent yellow Windows warning when executing uninstall
It was the case several years ago and at some point it disappeared, I was too lazy for finding the reason :(.
I mean currently, the uninstaller is not signed so when user execute uninstall, this appears instead of what we see during install:
If we sign it and add MediaInfo icon then the same UAC window should appear like the one during install with publisher name and icon.
I mean currently, the uninstaller is not signed so when user execute uninstall
I was speaking about that too :).
I mean currently, the uninstaller is not signed so when user execute uninstall
I was speaking about that too :).
So from what I read, to sign it we need use macro (https://nsis.sourceforge.io/Docs/Chapter5.html#uninstfinalize) to execute the signing script. This will make NSIS call the signing script after it generate uninstaller then script signs the uninstaller before NSIS package it into the installer. Can also use MUI_UNICON to change the uninstaller exe icon.
@JeromeMartinez managed to get a signed uninstaller.
Just need to add this to the .nsi
files:
!define MUI_UNICON "..\..\Source\Resource\Image\MediaInfo.ico"
; Sign uninstaller
!uninstfinalize 'sign.cmd "%1" "MediaInfo Uninstaller"'
Then create a bat/cmd file named sign
with the following:
set /P CodeSigningCertificatePass= < %USERPROFILE%\CodeSigningCertificate.pass
if "%NOSIGN%"=="" (
signtool sign /f %USERPROFILE%\CodeSigningCertificate.p12 /p %CodeSigningCertificatePass% /fd sha256 /v /tr http://ts.ssl.com /td sha256 /d %2 /du http://mediaarea.net %1
)
set CodeSigningCertificatePass=
After that just build as usual and the uninstaller should be signed. When user uninstalls, UAC will show MediaInfo Uninstaller with MediaInfo logo and verified publisher instead of uninst.exe with unknown publisher.
If want to sign the installer here instead of from build script, can also do:
; Sign installer
!finalize 'sign.cmd "%1" "MediaInfo Installer"'
Rebased to master.
NSIS needs to be updated to 3.10 (at least 3.09) to support the ${AtLeastWin11}
check used in this PR. Should consider updating the 8-year-old 7-Zip while at it. Maybe update libcurl too if there are security fixes.
https://github.com/MediaArea/MediaArea-Utils-Binaries/tree/master/Windows
Integrate with Windows 11 File Explorer modern context menu by implementing required items:
New shell extension also has the benefit of opening multiple selected files in the same MediaInfo instance instead of in multiple windows.
Resolves #671
Explanation of approach chosen for this new context menu implementation
The sparse package is provisioned for all users by the installer during install and removed for all users during uninstall using a helper dll. This should ensure all users will have the context menu on login after install and a clean removal after uninstall.
The 'Assets' folder and
resources.pri
file are needed because when the app runs with app identity, the assets referenced by the sparse package manifest is used for the app icon. Since it is a sparse package, it itself does not contain assets and instead references the assets that are in the declared external location. Theresources.pri
is needed for the 'unplated' icons which are needed to prevent the icon from having accent-coloured plating as the background.In order to minimize the size of the DLL while ensuring it runs on clean Windows installations without Microsoft Visual C++ Redistributable installed,
vcruntime
is statically linked whileucrt
is dynamically linked. This results in something between using/MT
and/MD
. It is known as Hybrid CRT and is supported according to the CRT maintainer./PDBALTPATH:%_PDB%
is added to linker in release mode so that the PDB file path is not contained in the DLL. This ensures no path information leakage and reduces the size of DLL slightly while still enabling analysis that requires PDB files to be done, for example SizeBench.The shell extension is re-written from WRL to C++/WinRT. See 'Note' at https://learn.microsoft.com/en-us/cpp/cppcx/wrl/windows-runtime-cpp-template-library-wrl?view=msvc-170 for details on why.
Enabled security mitigations for new context menu
The following are enabled in the project file for the Explorer context menu shell extension DLL.
GS (Buffer Security Check), sdl (Additional Security Checks), NXCOMPAT (Data Execution Prevention), DYNAMICBASE (Address space layout randomization), HIGHENTROPYVA (64-Bit ASLR), guard:cf (Control Flow Guard), guard:ehcont (EH Continuation Metadata), Qspectre (Spectre variant 1 mitigation), CETCOMPAT (CET Shadow Stack)
References
Todo for MediaInfo team:
Update version update script for:
Source\GUI\VCL\Manifest.manifest
Source\WindowsSparsePackage\MSIX\AppxManifest.xml
Source\WindowsShellExtension\Resource.rc
Source\WindowsPackageHelper\Resource.rc
Update build script
make sparse package
makeappx pack /d "Source\WindowsSparsePackage\MSIX" /p "Project\MSVC2022\x64\Release\MediaInfo_SparsePackage.msix" /nv
build DLLs
sign sparse package MSIX and DLLs generated by above
Test on other system configurations besides Windows 11 Home single account.