├── OpenGlass ├── pch.cpp ├── reflection.png ├── AeroColorizationEffect.cso ├── pch.h ├── module.def ├── OpenGlass.hpp ├── ButtonGlowHandler.hpp ├── AccentOverrider.hpp ├── GlassFrameHandler.hpp ├── GlassReflectionHandler.hpp ├── CaptionTextHandler.hpp ├── GlassIntegrity.hpp ├── GlassRenderer.hpp ├── module.hpp ├── wil.hpp ├── GlassReflectionBrush.hpp ├── AeroColorizationEffect.hlsl ├── Common.hlsli ├── GlassService.hpp ├── GlassSafetyZoneLayer.hpp ├── RenderingEffect.hpp ├── ReflectionRealizer.hpp ├── TaskHandler.hpp ├── packages.config ├── GlassRealizer.hpp ├── dcompPrivates.hpp ├── SymbolParser.hpp ├── CustomThemeAtlasLoader.hpp ├── BlurEffect.hpp ├── resource.h ├── GlassCoverageSet.hpp ├── AeroEffect.hpp ├── TaskHandler.cpp ├── cpprt.hpp ├── CustomBlurEffect.hpp ├── framework.hpp ├── GlassKernel.hpp ├── BlurShaders.hpp ├── GlassEngine.hpp ├── GlassReflectionBrush.cpp ├── BlurEffect.cpp ├── AeroColorizationEffect.hpp ├── AeroEffect.cpp ├── GlassEngine.cpp ├── D2DPrivates.hpp ├── D3DGlassRealizer.hpp ├── Shared.hpp ├── D2DBuffer.hpp ├── SymbolParser.cpp ├── HookHelper.hpp ├── GlassRealizer.cpp ├── GlassCoverageSet.cpp ├── Dwm.hpp ├── ButtonGlowHandler.cpp ├── OSHelper.hpp ├── AccentOverrider.cpp ├── OpenGlass.rc ├── GlassSafetyZoneLayer.cpp ├── AeroColorizationEffect.cpp ├── ProjectionHelper.hpp ├── dllmain.cpp ├── ReflectionRealizer.cpp ├── CustomBlurEffect.cpp ├── module.cpp ├── HookHelper.cpp └── GlassReflectionHandler.cpp ├── banner.png ├── .editorconfig ├── .github └── FUNDING.yml ├── OpenGlass.sln ├── .gitattributes └── .gitignore /OpenGlass/pch.cpp: -------------------------------------------------------------------------------- 1 | #include "pch.h" -------------------------------------------------------------------------------- /banner.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ALTaleX531/OpenGlass/HEAD/banner.png -------------------------------------------------------------------------------- /OpenGlass/reflection.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ALTaleX531/OpenGlass/HEAD/OpenGlass/reflection.png -------------------------------------------------------------------------------- /OpenGlass/AeroColorizationEffect.cso: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ALTaleX531/OpenGlass/HEAD/OpenGlass/AeroColorizationEffect.cso -------------------------------------------------------------------------------- /.editorconfig: -------------------------------------------------------------------------------- 1 | root = true 2 | 3 | [*] 4 | charset = utf-8 5 | end_of_line = crlf 6 | insert_final_newline = true 7 | indent_style = tab -------------------------------------------------------------------------------- /OpenGlass/pch.h: -------------------------------------------------------------------------------- 1 | #ifndef PCH_H 2 | #define PCH_H 3 | 4 | #include "framework.hpp" 5 | #include "cpprt.hpp" 6 | #include "wil.hpp" 7 | #include "detours.h" 8 | 9 | #endif -------------------------------------------------------------------------------- /OpenGlass/module.def: -------------------------------------------------------------------------------- 1 | LIBRARY 2 | EXPORTS 3 | DllGetClassObject PRIVATE 4 | DllCanUnloadNow PRIVATE 5 | DllRegisterServer PRIVATE 6 | DllUnregisterServer PRIVATE 7 | OpenGlass_RunDLL PRIVATE -------------------------------------------------------------------------------- /OpenGlass/OpenGlass.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "framework.hpp" 3 | #include "cpprt.hpp" 4 | 5 | namespace OpenGlass 6 | { 7 | DWORD WINAPI InitializationThreadEntryPoint(PVOID); 8 | DWORD WINAPI UnInitializationThreadEntryPoint(PVOID); 9 | } -------------------------------------------------------------------------------- /OpenGlass/ButtonGlowHandler.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "framework.hpp" 3 | #include "GlassEngine.hpp" 4 | 5 | namespace OpenGlass::ButtonGlowHandler 6 | { 7 | void Update(GlassEngine::UpdateType type); 8 | void Startup(); 9 | void Shutdown(); 10 | } -------------------------------------------------------------------------------- /OpenGlass/AccentOverrider.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "framework.hpp" 3 | #include "cpprt.hpp" 4 | #include "GlassEngine.hpp" 5 | 6 | namespace OpenGlass::AccentOverrider 7 | { 8 | void Update(GlassEngine::UpdateType type); 9 | void Startup(); 10 | void Shutdown(); 11 | } -------------------------------------------------------------------------------- /OpenGlass/GlassFrameHandler.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "framework.hpp" 3 | #include "cpprt.hpp" 4 | #include "GlassEngine.hpp" 5 | 6 | namespace OpenGlass::GlassFrameHandler 7 | { 8 | void Update(GlassEngine::UpdateType type); 9 | void Startup(); 10 | void Shutdown(); 11 | } -------------------------------------------------------------------------------- /OpenGlass/GlassReflectionHandler.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "framework.hpp" 3 | #include "cpprt.hpp" 4 | #include "GlassEngine.hpp" 5 | 6 | namespace OpenGlass::GlassReflectionHandler 7 | { 8 | void Update(GlassEngine::UpdateType type); 9 | void Startup(); 10 | void Shutdown(); 11 | } -------------------------------------------------------------------------------- /OpenGlass/CaptionTextHandler.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "framework.hpp" 3 | #include "GlassEngine.hpp" 4 | 5 | namespace OpenGlass::CaptionTextHandler 6 | { 7 | void DestroyDeviceResources(); 8 | 9 | void Update(GlassEngine::UpdateType type); 10 | void Startup(); 11 | void Shutdown(); 12 | } 13 | -------------------------------------------------------------------------------- /OpenGlass/GlassIntegrity.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "framework.hpp" 3 | #include "cpprt.hpp" 4 | #include "GlassEngine.hpp" 5 | #include "dwmcoreProjection.hpp" 6 | 7 | namespace OpenGlass::GlassIntegrity 8 | { 9 | void DestroyDeviceResources(dwmcore::CD2DContext* d2dContext); 10 | 11 | void Update(GlassEngine::UpdateType type); 12 | void Startup(); 13 | void Shutdown(); 14 | } 15 | -------------------------------------------------------------------------------- /OpenGlass/GlassRenderer.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "framework.hpp" 3 | #include "cpprt.hpp" 4 | #include "GlassEngine.hpp" 5 | #include "dwmcoreProjection.hpp" 6 | 7 | namespace OpenGlass::GlassRenderer 8 | { 9 | void DestroyDeviceResources(dwmcore::CD2DContext* d2dContext); 10 | 11 | void Update(GlassEngine::UpdateType type); 12 | void Startup(); 13 | void Shutdown(); 14 | } 15 | -------------------------------------------------------------------------------- /OpenGlass/module.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "framework.hpp" 3 | 4 | _Use_decl_annotations_ STDAPI DllGetClassObject(REFCLSID rclsid, REFIID riid, LPVOID* ppv); 5 | _Use_decl_annotations_ STDAPI DllCanUnloadNow(); 6 | STDAPI DllRegisterServer(); 7 | STDAPI DllUnregisterServer(); 8 | 9 | STDAPI StartupService() noexcept; 10 | STDAPI ShutdownService() noexcept; 11 | STDAPI InstallApp() noexcept; 12 | STDAPI UninstallApp() noexcept; -------------------------------------------------------------------------------- /OpenGlass/wil.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #ifndef RESULT_DIAGNOSTICS_LEVEL 4 | #if (defined(RESULT_DEBUG) || defined(RESULT_DEBUG_INFO)) && !defined(RESULT_SUPPRESS_DEBUG_INFO) 5 | #define RESULT_DIAGNOSTICS_LEVEL 5 6 | #else 7 | #define RESULT_DIAGNOSTICS_LEVEL 0 8 | #endif 9 | #endif 10 | #include "wil/wrl.h" 11 | #include "wil/common.h" 12 | #include "wil/cppwinrt.h" 13 | #include "wil/filesystem.h" 14 | #include "wil/win32_helpers.h" 15 | #include "wil/result.h" 16 | #include "wil/registry.h" 17 | #include "wil/resource.h" 18 | #include "wil/stl.h" 19 | #include "wil/safecast.h" 20 | #include "wil/com.h" -------------------------------------------------------------------------------- /OpenGlass/GlassReflectionBrush.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "resource.h" 3 | #include "uDWMProjection.hpp" 4 | #include "Shared.hpp" 5 | 6 | namespace OpenGlass::GlassReflectionBrush 7 | { 8 | D2D1_RECT_F CalculateTargetViewport( 9 | const POINT& offset, 10 | float parallaxIntensity = 0.f, 11 | bool mirrored = false, 12 | LONG width = 0, 13 | const DWM::MilSizeD& scale = { 1.0, 1.0 } 14 | ); 15 | 16 | winrt::com_ptr GetOrCreate( 17 | void* resource, 18 | bool createIfNecessary = false 19 | ); 20 | void Remove(void* resource); 21 | void Shutdown(); 22 | } 23 | -------------------------------------------------------------------------------- /OpenGlass/AeroColorizationEffect.hlsl: -------------------------------------------------------------------------------- 1 | #define D2D_INPUT_COUNT 1 2 | #define D2D_INPUT0_SIMPLE 3 | #include 4 | #include "Common.hlsli" 5 | 6 | cbuffer constants : register(b0) 7 | { 8 | minfloat4 afterglow : packoffset(c0); 9 | minfloat4 blurBalance : packoffset(c1); 10 | minfloat4 color : packoffset(c2); 11 | }; 12 | 13 | static const minfloat3 grayFactor = minfloat3(0.2126, 0.7152, 0.0722); 14 | 15 | D2D_PS_ENTRY(AeroColorizationEffect) 16 | { 17 | minfloat4 input = minfloat4(D2DGetInput(0)); 18 | input.w = dot(input.xyz, grayFactor); 19 | input.xyz = mad(input.w, afterglow.xyz, mad(blurBalance.x, input.xyz, color.xyz)); 20 | input.w = 1; 21 | 22 | return input; 23 | } -------------------------------------------------------------------------------- /OpenGlass/Common.hlsli: -------------------------------------------------------------------------------- 1 | #if !defined(COMMON_HLSL) 2 | #define COMMON_HLSL 3 | 4 | #define minp(type) min10##type 5 | #define minfloat minp(float) 6 | #define minfloat2 minp(float2) 7 | #define minfloat3 minp(float3) 8 | #define minfloat4 minp(float4) 9 | #define minfloat2x2 minp(float2x2) 10 | #define minfloat3x2 minp(float3x2) 11 | #define minfloat3x3 minp(float3x3) 12 | #define minfloat4x4 minp(float4x4) 13 | 14 | minfloat4 Premultiply(minfloat4 color) 15 | { 16 | color.rgb *= color.a; 17 | return color; 18 | } 19 | 20 | minfloat4 UnPremultiply(minfloat4 color) 21 | { 22 | color.rgb = (color.a == 0) ? minfloat3(0, 0, 0) : (color.rgb / color.a); 23 | return color; 24 | } 25 | 26 | #endif -------------------------------------------------------------------------------- /OpenGlass/GlassService.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "framework.hpp" 3 | #include "cpprt.hpp" 4 | 5 | namespace OpenGlass::GlassService 6 | { 7 | // client side apis 8 | enum class RequestType : UCHAR 9 | { 10 | OpenUserRegistry 11 | }; 12 | struct RequestBuffer 13 | { 14 | RequestType type; 15 | HKEY dwmKey; 16 | HKEY personalizeKey; 17 | }; 18 | HRESULT SendRequest(RequestBuffer& content); 19 | bool IsRunning(); 20 | 21 | // service side apis 22 | enum class ThreadStatus 23 | { 24 | Paused, 25 | Running, 26 | Stopped 27 | }; 28 | HRESULT ControlThread( 29 | HANDLE threadHandle, 30 | ThreadStatus newStatus 31 | ); 32 | 33 | DWORD WINAPI ServerThreadEntryPoint(PVOID); 34 | DWORD WINAPI InjectionThreadEntryPoint(LPVOID); 35 | } -------------------------------------------------------------------------------- /OpenGlass/GlassSafetyZoneLayer.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "D2DBuffer.hpp" 3 | #include "dwmcoreProjection.hpp" 4 | 5 | namespace OpenGlass 6 | { 7 | class CGlassSafetyZoneLayer 8 | { 9 | CD2DBuffer m_safetyZoneBufferVertical{}; 10 | CD2DBuffer m_safetyZoneBufferHorizontal{}; 11 | D2D1_RECT_U m_safetyZoneBounds[4]{}; 12 | winrt::com_ptr m_renderTargetBitmap{}; 13 | public: 14 | HRESULT Push( 15 | ID2D1DeviceContext* context, 16 | ID2D1Bitmap1* renderTargetBitmap, 17 | const D2D1_MATRIX_3X2_F& deviceTransform, 18 | const D2D1_RECT_F& originalPixelRectangle, 19 | float extendedAmount, 20 | D2D1_RECT_F& extendedPixelRectangle 21 | ); 22 | void Pop(); 23 | ID2D1Bitmap1* GetOwner() const { return m_renderTargetBitmap.get(); } 24 | }; 25 | } 26 | -------------------------------------------------------------------------------- /OpenGlass/RenderingEffect.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "framework.hpp" 3 | #include "cpprt.hpp" 4 | 5 | namespace OpenGlass 6 | { 7 | // [Guid("B83196A0-84DA-4723-B44E-ECCDA0D26B97")] 8 | DECLARE_INTERFACE_IID_(IRenderingEffect, IUnknown, "B83196A0-84DA-4723-B44E-ECCDA0D26B97") 9 | { 10 | virtual HRESULT STDMETHODCALLTYPE Build( 11 | ID2D1DeviceContext * context, 12 | ID2D1Image * inputImage, 13 | const D2D1_RECT_F & imageRectangle, 14 | const void* additionalParams 15 | ) = 0; 16 | virtual D2D1_POINT_2F STDMETHODCALLTYPE GetOutputOffset() const = 0; 17 | virtual D2D1_MATRIX_3X2_F STDMETHODCALLTYPE GetOutputMatrix() const = 0; 18 | virtual void STDMETHODCALLTYPE GetOutput(ID2D1Image **output) const = 0; 19 | virtual void STDMETHODCALLTYPE Reset() = 0; 20 | }; 21 | } -------------------------------------------------------------------------------- /OpenGlass/ReflectionRealizer.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "resource.h" 3 | #include "framework.hpp" 4 | #include "cpprt.hpp" 5 | #include "dwmcoreProjection.hpp" 6 | 7 | namespace OpenGlass 8 | { 9 | struct CReflectionInput 10 | { 11 | float intensity; 12 | const D2D1_RECT_F* viewport; 13 | const dwmcore::CMILMatrix* worldTransform; 14 | 15 | std::span rectangles; 16 | }; 17 | 18 | class CReflectionRealizer 19 | { 20 | winrt::com_ptr m_reflectionBitmap{ nullptr }; 21 | winrt::com_ptr m_spriteBatch{ nullptr }; 22 | 23 | inline HRESULT LoadTexture(ID2D1DeviceContext* context); 24 | public: 25 | HRESULT Render( 26 | ID2D1DeviceContext* context, 27 | const CReflectionInput& input 28 | ); 29 | void Reset() 30 | { 31 | m_reflectionBitmap = nullptr; 32 | } 33 | }; 34 | } 35 | -------------------------------------------------------------------------------- /OpenGlass/TaskHandler.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "framework.hpp" 3 | #include "wil.hpp" 4 | 5 | namespace OpenGlass 6 | { 7 | // {E7C32A02-29E3-42C2-87A1-BE1EFA9C8E7D} 8 | DEFINE_GUID(CLSID_TaskHandler, 9 | 0xe7c32a02, 0x29e3, 0x42c2, 0x87, 0xa1, 0xbe, 0x1e, 0xfa, 0x9c, 0x8e, 0x7d); 10 | constexpr auto CLSID_TaskHandler_STR = L"{E7C32A02-29E3-42C2-87A1-BE1EFA9C8E7D}"; 11 | class CTaskHandler : public winrt::implements 12 | { 13 | wil::unique_handle m_serverThreadHandle{ nullptr }; 14 | wil::unique_handle m_injectionThreadHandle{ nullptr }; 15 | public: 16 | STDMETHODIMP Start( 17 | IUnknown* pHandlerServices, 18 | BSTR data 19 | ) override; 20 | STDMETHODIMP Stop(HRESULT* pRetCode) override; 21 | STDMETHODIMP Pause() override; 22 | STDMETHODIMP Resume() override; 23 | }; 24 | } -------------------------------------------------------------------------------- /OpenGlass/packages.config: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /OpenGlass/GlassRealizer.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "framework.hpp" 3 | #include "cpprt.hpp" 4 | #include "dwmcoreProjection.hpp" 5 | #include "AeroEffect.hpp" 6 | #include "D2DBuffer.hpp" 7 | #include "Shared.hpp" 8 | 9 | namespace OpenGlass 10 | { 11 | struct CGlassInput 12 | { 13 | CAeroParams params; 14 | 15 | const D2D1_RECT_F* drawingWorldBounds; 16 | const D2D1_RECT_F* samplingWorldBoundsShapeClipped; 17 | std::span rectangles; 18 | 19 | CD2DBuffer* buffer; 20 | bool zeroCopyOptimization; 21 | }; 22 | 23 | class CGlassRealizer 24 | { 25 | Shared::GlassType m_glassType{ Shared::GlassType::Invalid }; 26 | winrt::com_ptr m_glassEffect{ nullptr }; 27 | 28 | bool EnsureGlassEffect(Shared::GlassType type); 29 | public: 30 | HRESULT Render( 31 | ID2D1DeviceContext* context, 32 | const CGlassInput& input 33 | ); 34 | }; 35 | } 36 | -------------------------------------------------------------------------------- /.github/FUNDING.yml: -------------------------------------------------------------------------------- 1 | # These are supported funding model platforms 2 | 3 | github: # Replace with up to 4 GitHub Sponsors-enabled usernames e.g., [user1, user2] 4 | patreon: # Replace with a single Patreon username 5 | open_collective: # Replace with a single Open Collective username 6 | ko_fi: altalex531 7 | tidelift: # Replace with a single Tidelift platform-name/package-name e.g., npm/babel 8 | community_bridge: # Replace with a single Community Bridge project-name e.g., cloud-foundry 9 | liberapay: # Replace with a single Liberapay username 10 | issuehunt: # Replace with a single IssueHunt username 11 | lfx_crowdfunding: # Replace with a single LFX Crowdfunding project-name e.g., cloud-foundry 12 | polar: # Replace with a single Polar username 13 | buy_me_a_coffee: # Replace with a single Buy Me a Coffee username 14 | thanks_dev: # Replace with a single thanks.dev username 15 | custom: # Replace with up to 4 custom sponsorship URLs e.g., ['link1', 'link2'] 16 | -------------------------------------------------------------------------------- /OpenGlass/dcompPrivates.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | 12 | namespace abi 13 | { 14 | using namespace ::ABI::Windows::Foundation; 15 | using namespace ::ABI::Windows::Foundation::Numerics; 16 | using namespace ::ABI::Windows::UI::Composition; 17 | using namespace ::ABI::Windows::UI::Composition::Desktop; 18 | using namespace ::ABI::Windows::Graphics; 19 | using namespace ::ABI::Windows::Graphics::DirectX; 20 | } 21 | 22 | namespace OpenGlass 23 | { 24 | DECLARE_INTERFACE_IID_(IDCompositionDesktopDevicePartner, IDCompositionDesktopDevice, "D14B6158-C3FA-4BCE-9C1F-B61D8665EAB0") 25 | { 26 | }; 27 | } 28 | -------------------------------------------------------------------------------- /OpenGlass/SymbolParser.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "pch.h" 3 | #include "HookHelper.hpp" 4 | 5 | namespace OpenGlass 6 | { 7 | using SymbolEventCallback = bool(PIMAGEHLP_CBA_EVENTW event); 8 | using SymbolParserCallback = bool(PSYMBOL_INFO info, ULONG size); 9 | 10 | class CSymbolParser 11 | { 12 | static HMODULE WINAPI MyLoadLibraryExW( 13 | LPCWSTR lpLibFileName, 14 | HANDLE hFile, 15 | DWORD dwFlags 16 | ); 17 | static BOOL CALLBACK EnumSymbolsCallback( 18 | PSYMBOL_INFO pSymInfo, 19 | ULONG SymbolSize, 20 | PVOID UserContext 21 | ); 22 | static BOOL CALLBACK SymCallback( 23 | HANDLE hProcess, 24 | ULONG ActionCode, 25 | ULONG64 CallbackData, 26 | ULONG64 UserContext 27 | ); 28 | 29 | PVOID m_LoadLibraryExW_Org{ nullptr }; 30 | SymbolEventCallback* m_eventCallback{ nullptr }; 31 | public: 32 | CSymbolParser(SymbolEventCallback* callback); 33 | ~CSymbolParser() noexcept; 34 | 35 | HRESULT LoadAndParse(PCWSTR moduleName, SymbolParserCallback* callback); 36 | }; 37 | } -------------------------------------------------------------------------------- /OpenGlass.sln: -------------------------------------------------------------------------------- 1 | 2 | Microsoft Visual Studio Solution File, Format Version 12.00 3 | # Visual Studio Version 17 4 | VisualStudioVersion = 17.8.34511.84 5 | MinimumVisualStudioVersion = 10.0.40219.1 6 | Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "OpenGlass", "OpenGlass\OpenGlass.vcxproj", "{80009307-7B06-4785-AF83-3F5D6DB7DEB6}" 7 | EndProject 8 | Global 9 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 10 | Debug|x64 = Debug|x64 11 | Release|x64 = Release|x64 12 | EndGlobalSection 13 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 14 | {80009307-7B06-4785-AF83-3F5D6DB7DEB6}.Debug|x64.ActiveCfg = Debug|x64 15 | {80009307-7B06-4785-AF83-3F5D6DB7DEB6}.Debug|x64.Build.0 = Debug|x64 16 | {80009307-7B06-4785-AF83-3F5D6DB7DEB6}.Release|x64.ActiveCfg = Release|x64 17 | {80009307-7B06-4785-AF83-3F5D6DB7DEB6}.Release|x64.Build.0 = Release|x64 18 | EndGlobalSection 19 | GlobalSection(SolutionProperties) = preSolution 20 | HideSolutionNode = FALSE 21 | EndGlobalSection 22 | GlobalSection(ExtensibilityGlobals) = postSolution 23 | SolutionGuid = {96842AA8-7104-4767-BA0D-11FEDDA7E642} 24 | EndGlobalSection 25 | EndGlobal 26 | -------------------------------------------------------------------------------- /OpenGlass/CustomThemeAtlasLoader.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "framework.hpp" 3 | #include "cpprt.hpp" 4 | #include "GlassEngine.hpp" 5 | 6 | namespace OpenGlass::CustomThemeAtlasLoader 7 | { 8 | HRESULT STDMETHODCALLTYPE MyGetThemeStream( 9 | HTHEME hTheme, 10 | int iPartId, 11 | int iStateId, 12 | int iPropId, 13 | VOID** ppvStream, 14 | DWORD* pcbStream, 15 | HINSTANCE hInst 16 | ); 17 | HRESULT STDMETHODCALLTYPE MyGetThemeMargins( 18 | HTHEME hTheme, 19 | HDC hdc, 20 | int iPartId, 21 | int iStateId, 22 | int iPropId, 23 | LPCRECT prc, 24 | MARGINS* pMargins 25 | ); 26 | HRESULT STDMETHODCALLTYPE MyGetThemeRect( 27 | HTHEME hTheme, 28 | int iPartId, 29 | int iStateId, 30 | int iPropId, 31 | LPRECT pRect 32 | ); 33 | HRESULT STDMETHODCALLTYPE MyGetThemeInt( 34 | HTHEME hTheme, 35 | int iPartId, 36 | int iStateId, 37 | int iPropId, 38 | int* piVal 39 | ); 40 | HRESULT STDMETHODCALLTYPE MyGetThemeColor( 41 | HTHEME hTheme, 42 | int iPartId, 43 | int iStateId, 44 | int iPropId, 45 | COLORREF* pColor 46 | ); 47 | HTHEME GetThemeHandle(); 48 | 49 | void Update(GlassEngine::UpdateType type); 50 | void Startup(); 51 | void Shutdown(); 52 | } 53 | -------------------------------------------------------------------------------- /OpenGlass/BlurEffect.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "CustomBlurEffect.hpp" 3 | 4 | namespace OpenGlass 5 | { 6 | struct CBlurParams : CCustomBlurParams 7 | { 8 | D2D1_COLOR_F color; 9 | float colorBalance; 10 | }; 11 | 12 | class CBlurEffect : public winrt::implements 13 | { 14 | bool m_initialized{ false }; 15 | 16 | winrt::com_ptr m_customBlurEffect{}; 17 | 18 | winrt::com_ptr m_compositeEffect{}; 19 | winrt::com_ptr m_colorEffect{}; 20 | winrt::com_ptr m_outputEffect{}; 21 | 22 | HRESULT Initialize(ID2D1DeviceContext* context); 23 | public: 24 | HRESULT STDMETHODCALLTYPE Build( 25 | ID2D1DeviceContext* context, 26 | ID2D1Image* inputImage, 27 | const D2D1_RECT_F& imageRectangle, 28 | const void* additionalParams 29 | ) override; 30 | D2D1_POINT_2F STDMETHODCALLTYPE GetOutputOffset() const override { return m_customBlurEffect->GetOutputOffset(); } 31 | D2D1_MATRIX_3X2_F STDMETHODCALLTYPE GetOutputMatrix() const override; 32 | void STDMETHODCALLTYPE GetOutput(ID2D1Image** output) const override; 33 | void STDMETHODCALLTYPE Reset() override; 34 | }; 35 | } 36 | -------------------------------------------------------------------------------- /OpenGlass/resource.h: -------------------------------------------------------------------------------- 1 | //{{NO_DEPENDENCIES}} 2 | // Microsoft Visual C++ generated include file. 3 | // Used by OpenGlass.rc 4 | // 5 | #define IDS_STRING101 101 6 | #define IDS_STRING102 102 7 | #define IDB_REFLECTION 102 8 | #define IDS_STRING103 103 9 | #define IDS_STRING104 104 10 | #define IDS_STRING105 105 11 | #define IDS_STRING106 106 12 | #define IDR_RCDATA1 106 13 | #define IDS_STRING107 107 14 | #define IDS_STRING108 108 15 | #define IDS_STRING109 109 16 | #define IDS_STRING110 110 17 | #define IDS_STRING111 111 18 | #define IDS_STRING112 112 19 | #define IDS_STRING113 113 20 | #define IDS_STRING114 114 21 | #define IDS_STRING115 115 22 | 23 | // Next default values for new objects 24 | // 25 | #ifdef APSTUDIO_INVOKED 26 | #ifndef APSTUDIO_READONLY_SYMBOLS 27 | #define _APS_NEXT_RESOURCE_VALUE 107 28 | #define _APS_NEXT_COMMAND_VALUE 40001 29 | #define _APS_NEXT_CONTROL_VALUE 1001 30 | #define _APS_NEXT_SYMED_VALUE 101 31 | #endif 32 | #endif 33 | -------------------------------------------------------------------------------- /OpenGlass/GlassCoverageSet.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "framework.hpp" 3 | #include "cpprt.hpp" 4 | #include "dwmcoreProjection.hpp" 5 | 6 | namespace OpenGlass 7 | { 8 | // [Guid("5258B8F9-28D5-4F90-A2D9-5E716239DD57")] 9 | DECLARE_INTERFACE_IID_(IGlassCoverageSet, IUnknown, "5258B8F9-28D5-4F90-A2D9-5E716239DD57") 10 | { 11 | virtual void STDMETHODCALLTYPE SetDeviceTransform(const dwmcore::CMILMatrix * matrix) = 0; 12 | virtual HRESULT STDMETHODCALLTYPE Add( 13 | const D2D1_RECT_F& coverage, 14 | int depth, 15 | const dwmcore::CMILMatrix* matrix 16 | ) = 0; 17 | virtual void STDMETHODCALLTYPE Clear() = 0; 18 | virtual std::span STDMETHODCALLTYPE GetViews() const = 0; 19 | virtual bool STDMETHODCALLTYPE IsFullyCovered( 20 | const D2D1_RECT_F & coverage, 21 | int depth 22 | ) const = 0; 23 | virtual bool STDMETHODCALLTYPE IsPartiallyCovered( 24 | const D2D1_RECT_F& coverage, 25 | int depth 26 | ) const = 0; 27 | virtual bool STDMETHODCALLTYPE IsVisible( 28 | const D2D1_RECT_F& coverage, 29 | const dwmcore::CArrayBasedCoverageSet* occlusionCoverageSet 30 | ) const = 0; 31 | }; 32 | 33 | namespace GlassCoverageSetFactory 34 | { 35 | winrt::com_ptr GetOrCreate( 36 | dwmcore::COcclusionContext* occlusionContext, 37 | bool createIfNecessary = false 38 | ); 39 | void Remove(dwmcore::COcclusionContext* occlusionContext); 40 | void Shutdown(); 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /OpenGlass/AeroEffect.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "CustomBlurEffect.hpp" 3 | #include "BlurEffect.hpp" 4 | #include "AeroColorizationEffect.hpp" 5 | 6 | namespace OpenGlass 7 | { 8 | struct CAeroParams : CBlurParams 9 | { 10 | D2D1_COLOR_F afterglow; 11 | float afterglowBalance; 12 | float blurBalance; 13 | }; 14 | 15 | class CAeroEffect : public winrt::implements 16 | { 17 | bool m_initialized{ false }; 18 | 19 | winrt::com_ptr m_customBlurEffect{}; 20 | winrt::com_ptr m_colorizationEffect{}; 21 | winrt::com_ptr m_outputEffect{}; 22 | inline static winrt::com_ptr s_factory{}; 23 | inline static const auto s_customEffectScope = wil::scope_exit([] static 24 | { 25 | if (s_factory) 26 | { 27 | LOG_IF_FAILED(CAeroColorizationEffect::UnRegister(s_factory.get())); 28 | } 29 | }); 30 | 31 | HRESULT Initialize(ID2D1DeviceContext* context); 32 | public: 33 | HRESULT STDMETHODCALLTYPE Build( 34 | ID2D1DeviceContext* context, 35 | ID2D1Image* inputImage, 36 | const D2D1_RECT_F& imageRectangle, 37 | const void* additionalParams 38 | ) override; 39 | D2D1_POINT_2F STDMETHODCALLTYPE GetOutputOffset() const override { return m_customBlurEffect->GetOutputOffset(); } 40 | D2D1_MATRIX_3X2_F STDMETHODCALLTYPE GetOutputMatrix() const override; 41 | void STDMETHODCALLTYPE GetOutput(ID2D1Image** output) const override; 42 | void STDMETHODCALLTYPE Reset() override; 43 | }; 44 | } 45 | -------------------------------------------------------------------------------- /OpenGlass/TaskHandler.cpp: -------------------------------------------------------------------------------- 1 | #include "pch.h" 2 | #include "TaskHandler.hpp" 3 | #include "GlassService.hpp" 4 | 5 | using namespace OpenGlass; 6 | 7 | STDMETHODIMP CTaskHandler::Start( 8 | [[maybe_unused]] IUnknown* pHandlerServices, 9 | [[maybe_unused]] BSTR data 10 | ) 11 | { 12 | m_serverThreadHandle.reset( 13 | CreateThread( 14 | nullptr, 15 | 0, 16 | GlassService::ServerThreadEntryPoint, 17 | nullptr, 18 | 0, 19 | nullptr 20 | ) 21 | ); 22 | RETURN_LAST_ERROR_IF_NULL(m_serverThreadHandle); 23 | m_injectionThreadHandle.reset( 24 | CreateThread( 25 | nullptr, 26 | 0, 27 | GlassService::InjectionThreadEntryPoint, 28 | nullptr, 29 | 0, 30 | nullptr 31 | ) 32 | ); 33 | RETURN_LAST_ERROR_IF_NULL(m_injectionThreadHandle); 34 | return S_OK; 35 | } 36 | 37 | STDMETHODIMP CTaskHandler::Stop(HRESULT* pRetCode) 38 | { 39 | RETURN_IF_FAILED( 40 | GlassService::ControlThread( 41 | m_injectionThreadHandle.get(), 42 | GlassService::ThreadStatus::Stopped 43 | ) 44 | ); 45 | RETURN_IF_FAILED( 46 | GlassService::ControlThread( 47 | m_serverThreadHandle.get(), 48 | GlassService::ThreadStatus::Stopped 49 | ) 50 | ); 51 | RETURN_LAST_ERROR_IF(WaitForSingleObject(m_injectionThreadHandle.get(), INFINITE) != WAIT_OBJECT_0); 52 | RETURN_LAST_ERROR_IF(WaitForSingleObject(m_serverThreadHandle.get(), INFINITE) != WAIT_OBJECT_0); 53 | 54 | RETURN_IF_WIN32_BOOL_FALSE(GetExitCodeThread(m_injectionThreadHandle.get(), reinterpret_cast(pRetCode))); 55 | m_serverThreadHandle.reset(); 56 | m_injectionThreadHandle.reset(); 57 | return S_OK; 58 | } 59 | 60 | STDMETHODIMP CTaskHandler::Pause() 61 | { 62 | return GlassService::ControlThread( 63 | m_injectionThreadHandle.get(), 64 | GlassService::ThreadStatus::Paused 65 | ); 66 | } 67 | 68 | STDMETHODIMP CTaskHandler::Resume() 69 | { 70 | return GlassService::ControlThread( 71 | m_injectionThreadHandle.get(), 72 | GlassService::ThreadStatus::Running 73 | ); 74 | } -------------------------------------------------------------------------------- /OpenGlass/cpprt.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | // C (C++ 11) 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | // C++ 11 | #include 12 | #include 13 | #include 14 | #include 15 | #include 16 | #include 17 | #include 18 | #include 19 | #include 20 | #include 21 | #include 22 | #include 23 | #include 24 | #include 25 | #include 26 | #include 27 | #include 28 | #include 29 | #include 30 | #include 31 | #include 32 | #include 33 | #include 34 | #include 35 | #include 36 | #include 37 | #include 38 | #include 39 | #include 40 | #include 41 | #include 42 | #include 43 | // C++ 11 44 | #include 45 | #include 46 | #include 47 | #include 48 | #include 49 | #include 50 | #include 51 | #include 52 | #include 53 | #include 54 | #include 55 | #include 56 | #include 57 | #include 58 | #include 59 | #include 60 | #include 61 | #include 62 | #include 63 | #include 64 | // C++ 14 65 | #include 66 | // C++ 17 67 | #include 68 | #include 69 | #include 70 | #include 71 | #include 72 | #include 73 | #include 74 | #include 75 | #include 76 | #include 77 | // C++ 20 78 | #include 79 | #include 80 | #include 81 | #include 82 | #include 83 | #include 84 | #include 85 | #include 86 | #include 87 | #include 88 | #include -------------------------------------------------------------------------------- /OpenGlass/CustomBlurEffect.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "RenderingEffect.hpp" 3 | 4 | // this is actually a full mirror implementation of dwmcore!CCustomBlur, 5 | // in order to produce a high performance blur effect than raw direct2d gaussian blur effect 6 | // no reason for touching it 7 | 8 | // i have to apologize to all other contributors since i completely refactor this part of the code 9 | namespace OpenGlass 10 | { 11 | struct CCustomBlurParams 12 | { 13 | float blurAmount; 14 | D2D1_GAUSSIANBLUR_OPTIMIZATION optimization; 15 | bool cachePrescaledImage; 16 | }; 17 | 18 | class CCustomBlurEffect : public winrt::implements 19 | { 20 | bool m_initialized{ false }; 21 | 22 | float m_blurAmount{ 0.f }; 23 | D2D1_GAUSSIANBLUR_OPTIMIZATION m_optimization{ D2D1_GAUSSIANBLUR_OPTIMIZATION_BALANCED }; 24 | D2D1_VECTOR_2F m_prescaleAmount{}; 25 | D2D1_POINT_2F m_offset{}; 26 | 27 | winrt::com_ptr m_cropInputEffect{}; 28 | winrt::com_ptr m_scaleDownEffect{}; 29 | winrt::com_ptr m_cropAlignEffect{}; 30 | winrt::com_ptr m_borderEffect{}; 31 | winrt::com_ptr m_directionalBlurXEffect{}; 32 | winrt::com_ptr m_directionalBlurYEffect{}; 33 | 34 | static const float k_optimizations[16]; 35 | float DetermineOutputScale( 36 | float size 37 | ); 38 | HRESULT Initialize(ID2D1DeviceContext* context); 39 | HRESULT CalculateAndSetEffectParams(const D2D1_RECT_F& imageRectangle); 40 | public: 41 | HRESULT STDMETHODCALLTYPE Build( 42 | ID2D1DeviceContext* context, 43 | ID2D1Image* inputImage, 44 | const D2D1_RECT_F& imageRectangle, 45 | const void* additionalParams 46 | ) override; 47 | D2D1_MATRIX_3X2_F STDMETHODCALLTYPE GetOutputMatrix() const override; 48 | D2D1_POINT_2F STDMETHODCALLTYPE GetOutputOffset() const override { return m_offset; } 49 | void STDMETHODCALLTYPE GetOutput(ID2D1Image** output) const override; 50 | void STDMETHODCALLTYPE Reset() override; 51 | }; 52 | } 53 | -------------------------------------------------------------------------------- /OpenGlass/framework.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #define WIN32_LEAN_AND_MEAN 4 | #ifndef NOMINMAX 5 | #define NOMINMAX 6 | #endif 7 | #include 8 | #include 9 | #include 10 | 11 | #include 12 | #include 13 | #include 14 | #include 15 | #include 16 | #include 17 | #include 18 | #include 19 | #include 20 | 21 | #include 22 | #include 23 | #include 24 | #include 25 | #include 26 | #include 27 | #include 28 | #include 29 | #include 30 | #include 31 | #include 32 | #include 33 | #include 34 | #include 35 | 36 | #include 37 | #include 38 | #include 39 | #include 40 | #include 41 | 42 | #include 43 | #include 44 | #include 45 | #include 46 | #include 47 | #include 48 | #include 49 | #include 50 | 51 | #pragma comment(lib, "powrprof.lib") 52 | #pragma comment(lib, "version.lib") 53 | 54 | #pragma comment(lib, "delayimp.lib") 55 | #pragma comment(lib, "DbgHelp.lib") 56 | #pragma comment(lib, "Imagehlp.lib") 57 | #pragma comment(lib, "Psapi.lib") 58 | #pragma comment(lib, "Wtsapi32.lib") 59 | 60 | #pragma comment(lib, "Oleacc.lib") 61 | #pragma comment(lib, "taskschd.lib") 62 | #pragma comment(lib, "comsuppw.lib") 63 | #pragma comment(lib, "Shlwapi.lib") 64 | #pragma comment(lib, "PathCch.lib") 65 | 66 | #pragma comment(lib, "comctl32.lib") 67 | #pragma comment(lib, "dwmapi.lib") 68 | #pragma comment(lib, "uxtheme.lib") 69 | 70 | #pragma comment(lib, "dxgi.lib") 71 | #pragma comment(lib, "d2d1.lib") 72 | #pragma comment(lib, "d3d11.lib") 73 | #pragma comment(lib, "dcomp.lib") 74 | #pragma comment(lib, "dwrite.lib") 75 | #pragma comment(lib, "dxguid.lib") 76 | #pragma comment(lib, "d3dcompiler.lib") 77 | 78 | #pragma comment(lib, "onecore.lib") 79 | -------------------------------------------------------------------------------- /OpenGlass/GlassKernel.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "framework.hpp" 3 | #include "cpprt.hpp" 4 | #include "GlassEngine.hpp" 5 | 6 | namespace OpenGlass::GlassKernel 7 | { 8 | class AlphaChannelReinterpreter 9 | { 10 | std::bitset<16> m_flag{}; 11 | public: 12 | bool GetIsValid() const 13 | { 14 | return m_flag.test(0); 15 | } 16 | bool GetIsActive() const 17 | { 18 | return m_flag.test(1); 19 | } 20 | bool GetIsMaximized() const 21 | { 22 | return m_flag.test(2); 23 | } 24 | void SetIsActive(bool value) 25 | { 26 | m_flag.set(1, value); 27 | } 28 | void SetIsMaximized(bool value) 29 | { 30 | m_flag.set(2, value); 31 | } 32 | 33 | float ToFloat() const 34 | { 35 | const auto value = ((m_flag.to_ulong() << 8) | 0x3F000001); 36 | return *reinterpret_cast(&value); 37 | } 38 | AlphaChannelReinterpreter(float value) 39 | { 40 | if ((*reinterpret_cast(&value) & 0xFF0000FF) == 0x3F000001) 41 | { 42 | m_flag = (*reinterpret_cast(&value) & 0x00FFFF00) >> 8; 43 | m_flag.set(0); 44 | } 45 | } 46 | AlphaChannelReinterpreter( 47 | bool active, 48 | bool maximized 49 | ) 50 | { 51 | SetIsActive(active); 52 | SetIsMaximized(maximized); 53 | } 54 | }; 55 | 56 | void RedrawAllTopLevelWindow(); 57 | float GetBlurExtendedAmount(); 58 | 59 | struct CRealizedGlassColorizationParameters 60 | { 61 | D2D1_COLOR_F color; 62 | D2D1_COLOR_F afterglow; 63 | float colorBalance; 64 | float afterglowBalance; 65 | float blurBalance; 66 | 67 | D2D1_COLOR_F effectiveBlendColor; 68 | }; 69 | float GetColorizationBlendingOpacity(bool active, bool maximized); 70 | D2D1_COLOR_F GetBlendingBaseColor(bool opaque, bool opaqueByMaximization); 71 | D2D1_COLOR_F GetBlendingSourceColor(bool active); 72 | CRealizedGlassColorizationParameters RealizeWindowColorization( 73 | const D2D1_COLOR_F& baseColor, 74 | const D2D1_COLOR_F& srcColor, 75 | float colorizationOpacity, 76 | bool opaque, 77 | bool livePreview 78 | ); 79 | 80 | bool IsCurrentCVIFullyTransparent(); 81 | 82 | void Update(GlassEngine::UpdateType type); 83 | void Startup(); 84 | void Shutdown(); 85 | } 86 | -------------------------------------------------------------------------------- /OpenGlass/BlurShaders.hpp: -------------------------------------------------------------------------------- 1 | R"(cbuffer BlurConstants : register(b0) 2 | { 3 | float2 viewportSize; 4 | float2 texelSize; 5 | float4 afterglow; 6 | float4 blurBalance; 7 | float4 color; 8 | }; 9 | 10 | Texture2D texture0 : register(t0); 11 | SamplerState sampler0 : register(s0); 12 | 13 | struct VS_INPUT 14 | { 15 | float4 pos : POSITION; 16 | float2 tex0 : TEXCOORD0; 17 | }; 18 | 19 | struct PS_INPUT 20 | { 21 | float4 pos : SV_POSITION; 22 | float2 tex0 : TEXCOORD0; 23 | }; 24 | 25 | PS_INPUT VS(VS_INPUT input) 26 | { 27 | PS_INPUT output = (PS_INPUT) 0; 28 | 29 | output.pos.x = (input.pos.x / viewportSize.x) * 2.0f - 1.0f; 30 | output.pos.y = 1.0f - (input.pos.y / viewportSize.y) * 2.0f; 31 | output.pos.z = 0.5f; 32 | output.pos.w = 1.0f; 33 | 34 | output.tex0 = input.tex0; 35 | 36 | return output; 37 | } 38 | 39 | static const int taps = 8; 40 | static const min10float weights[taps] = { 0.02706f, 0.08890f, 0.18942f, 0.26192f, 0.23510f, 0.13697f, 0.05178f, 0.00885f }; 41 | static const min10float offsets[taps] = { -3.1635f, -2.1888f, -1.2155f, -0.2431f, 0.7292f, 1.7020f, 2.6759f, 3.5000f }; 42 | static const min10float3 grayFactor = min10float3(0.2126f, 0.7152f, 0.0722f); 43 | 44 | min10float4 PS_BlurH(PS_INPUT input) : SV_Target 45 | { 46 | min10float4 finalColor = 0; 47 | 48 | [unroll] 49 | for (int i = 0; i < taps; i++) 50 | { 51 | finalColor += (min10float4)texture0.Sample(sampler0, input.tex0 + float2(offsets[i] * texelSize.x, 0)) * weights[i]; 52 | } 53 | 54 | finalColor.w = 1; 55 | 56 | return finalColor; 57 | } 58 | 59 | min10float4 PS_BlurV(PS_INPUT input) : SV_Target 60 | { 61 | min10float4 finalColor = 0; 62 | 63 | [unroll] 64 | for (int i = 0; i < taps; i++) 65 | { 66 | finalColor += (min10float4)texture0.Sample(sampler0, input.tex0 + float2(0, offsets[i] * texelSize.y)) * weights[i]; 67 | } 68 | 69 | finalColor.w = dot(finalColor.xyz, grayFactor); 70 | finalColor.xyz = (min10float3)mad(finalColor.w, afterglow.xyz, mad(blurBalance.x, finalColor.xyz, color.xyz)); 71 | finalColor.w = 1; 72 | 73 | return finalColor; 74 | } 75 | 76 | min10float4 PS_Passthrough(PS_INPUT input) : SV_Target 77 | { 78 | min10float4 finalColor = (min10float4)texture0.Sample(sampler0, input.tex0); 79 | 80 | return finalColor; 81 | })" 82 | -------------------------------------------------------------------------------- /OpenGlass/GlassEngine.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "framework.hpp" 3 | #include "cpprt.hpp" 4 | #include "uDWMProjection.hpp" 5 | 6 | namespace OpenGlass::GlassEngine 7 | { 8 | enum UpdateType : UCHAR 9 | { 10 | None = 0, 11 | Framework = 1 << 0, 12 | Backdrop = 1 << 1, 13 | Theme = 1 << 2, 14 | Hook = 1 << 3, 15 | All = Backdrop | Framework 16 | }; 17 | 18 | HKEY GetDwmKey(); 19 | HKEY GetPersonalizeKey(); 20 | HKEY GetDwmLocalMachineKey(); 21 | 22 | FORCEINLINE std::optional TryGetDwordFromRegistry(PCWSTR keyName) 23 | { 24 | HRESULT hr{ S_OK }; 25 | DWORD value{}; 26 | hr = wil::reg::get_value_dword_nothrow( 27 | GetDwmKey(), 28 | keyName, 29 | &value 30 | ); 31 | if (hr == HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND)) 32 | { 33 | hr = wil::reg::get_value_dword_nothrow( 34 | HKEY_LOCAL_MACHINE, 35 | L"Software\\Microsoft\\Windows\\DWM", 36 | keyName, 37 | &value 38 | ); 39 | } 40 | if (FAILED(hr)) 41 | { 42 | return std::nullopt; 43 | } 44 | 45 | return value; 46 | } 47 | 48 | FORCEINLINE DWORD GetDwordFromRegistry(PCWSTR keyName, DWORD defaultValue = 0) 49 | { 50 | HRESULT hr{ S_OK }; 51 | DWORD value{ defaultValue }; 52 | hr = wil::reg::get_value_dword_nothrow( 53 | GetDwmKey(), 54 | keyName, 55 | &value 56 | ); 57 | if (hr == HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND)) 58 | { 59 | hr = wil::reg::get_value_dword_nothrow( 60 | HKEY_LOCAL_MACHINE, 61 | L"Software\\Microsoft\\Windows\\DWM", 62 | keyName, 63 | &value 64 | ); 65 | } 66 | 67 | return value; 68 | } 69 | template 70 | FORCEINLINE void GetStringFromRegistry(PCWSTR keyName, WCHAR(&returnValue)[Length]) 71 | { 72 | HRESULT hr{ S_OK }; 73 | hr = wil::reg::get_value_string_nothrow( 74 | GetDwmKey(), 75 | keyName, 76 | returnValue 77 | ); 78 | if (hr == HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND)) 79 | { 80 | hr = wil::reg::get_value_string_nothrow( 81 | HKEY_LOCAL_MACHINE, 82 | L"Software\\Microsoft\\Windows\\DWM", 83 | keyName, 84 | returnValue 85 | ); 86 | } 87 | } 88 | 89 | void LoadRegistry(bool redrawNow = true); 90 | void UnloadRegistry(); 91 | 92 | void RedrawAll(); 93 | void Update(UpdateType type, bool redrawNow = true); 94 | void Startup(); 95 | void Shutdown(); 96 | } 97 | -------------------------------------------------------------------------------- /OpenGlass/GlassReflectionBrush.cpp: -------------------------------------------------------------------------------- 1 | #include "pch.h" 2 | #include "GlassReflectionBrush.hpp" 3 | 4 | using namespace OpenGlass; 5 | namespace OpenGlass::GlassReflectionBrush 6 | { 7 | std::unordered_map> g_glassReflectionBrushMap{}; 8 | } 9 | 10 | D2D1_RECT_F GlassReflectionBrush::CalculateTargetViewport( 11 | const POINT& offset, 12 | float parallaxIntensity, 13 | bool mirrored, 14 | LONG width, 15 | const DWM::MilSizeD& scale 16 | ) 17 | { 18 | D2D1_RECT_F viewport 19 | { 20 | -1.f * 21 | ( 22 | mirrored ? 23 | ( 24 | static_cast(GetSystemMetrics(SM_XVIRTUALSCREEN)) + 25 | static_cast(GetSystemMetrics(SM_CXVIRTUALSCREEN)) 26 | 27 | - 28 | 29 | ( 30 | static_cast(offset.x) + 31 | static_cast(width) 32 | ) 33 | 34 | ) : 35 | static_cast( 36 | offset.x - 37 | GetSystemMetrics(SM_XVIRTUALSCREEN) 38 | ) 39 | ) * 40 | ( 41 | 1.f - 42 | parallaxIntensity 43 | ), 44 | 45 | -static_cast( 46 | offset.y - 47 | GetSystemMetrics(SM_YVIRTUALSCREEN) 48 | ) 49 | }; 50 | viewport.right = viewport.left + static_cast(GetSystemMetrics(SM_CXVIRTUALSCREEN)); 51 | viewport.bottom = viewport.top + static_cast(GetSystemMetrics(SM_CYVIRTUALSCREEN)); 52 | 53 | viewport.left /= static_cast(scale.width); 54 | viewport.top /= static_cast(scale.height); 55 | viewport.right /= static_cast(scale.width); 56 | viewport.bottom /= static_cast(scale.height); 57 | 58 | return viewport; 59 | } 60 | 61 | winrt::com_ptr GlassReflectionBrush::GetOrCreate(void* resource, bool createIfNecessary) 62 | { 63 | auto it = g_glassReflectionBrushMap.find(resource); 64 | 65 | if (createIfNecessary) 66 | { 67 | if (it == g_glassReflectionBrushMap.end()) 68 | { 69 | winrt::com_ptr brush{ nullptr }; 70 | THROW_IF_FAILED( 71 | uDWM::CDesktopManager::GetInstance()->GetCompositor()->CreateImageLegacyMilBrushProxy( 72 | brush.put() 73 | ) 74 | ); 75 | auto result = g_glassReflectionBrushMap.emplace(resource, brush); 76 | if (result.second == true) 77 | { 78 | it = result.first; 79 | } 80 | } 81 | } 82 | 83 | return it == g_glassReflectionBrushMap.end() ? nullptr : it->second; 84 | } 85 | void GlassReflectionBrush::Remove(void* resource) 86 | { 87 | auto it = g_glassReflectionBrushMap.find(resource); 88 | 89 | if (it != g_glassReflectionBrushMap.end()) 90 | { 91 | g_glassReflectionBrushMap.erase(it); 92 | } 93 | } 94 | void GlassReflectionBrush::Shutdown() 95 | { 96 | g_glassReflectionBrushMap.clear(); 97 | } 98 | -------------------------------------------------------------------------------- /OpenGlass/BlurEffect.cpp: -------------------------------------------------------------------------------- 1 | #include "pch.h" 2 | #include "BlurEffect.hpp" 3 | 4 | using namespace OpenGlass; 5 | 6 | HRESULT CBlurEffect::Initialize(ID2D1DeviceContext* context) 7 | { 8 | m_customBlurEffect = winrt::make(); 9 | 10 | RETURN_IF_FAILED( 11 | context->CreateEffect( 12 | CLSID_D2D1Flood, 13 | m_colorEffect.put() 14 | ) 15 | ); 16 | RETURN_IF_FAILED( 17 | context->CreateEffect( 18 | CLSID_D2D1Composite, 19 | m_compositeEffect.put() 20 | ) 21 | ); 22 | 23 | RETURN_IF_FAILED( 24 | m_compositeEffect->SetValue( 25 | D2D1_COMPOSITE_PROP_MODE, 26 | D2D1_COMPOSITE_MODE_SOURCE_OVER 27 | ) 28 | ); 29 | m_compositeEffect->SetInputEffect(1, m_colorEffect.get()); 30 | 31 | m_initialized = true; 32 | 33 | return S_OK; 34 | } 35 | 36 | HRESULT STDMETHODCALLTYPE CBlurEffect::Build( 37 | ID2D1DeviceContext* context, 38 | ID2D1Image* inputImage, 39 | const D2D1_RECT_F& imageRectangle, 40 | const void* additionalParams 41 | ) 42 | { 43 | if (!m_initialized) 44 | { 45 | RETURN_IF_FAILED(Initialize(context)); 46 | } 47 | const auto params = static_cast(additionalParams); 48 | 49 | RETURN_IF_FAILED( 50 | m_customBlurEffect->Build( 51 | context, 52 | inputImage, 53 | imageRectangle, 54 | additionalParams 55 | ) 56 | ); 57 | const auto fullyTransparent = params->colorBalance == 0.f; 58 | if (!fullyTransparent) 59 | { 60 | RETURN_IF_FAILED( 61 | m_colorEffect->SetValue( 62 | D2D1_FLOOD_PROP_COLOR, 63 | D2D1::Vector4F( 64 | params->color.r * params->colorBalance, 65 | params->color.g * params->colorBalance, 66 | params->color.b * params->colorBalance, 67 | params->colorBalance 68 | ) 69 | ) 70 | ); 71 | 72 | winrt::com_ptr image{}; 73 | m_customBlurEffect->GetOutput(image.put()); 74 | m_compositeEffect->SetInput(0, image.get()); 75 | m_outputEffect = m_compositeEffect; 76 | } 77 | else 78 | { 79 | m_outputEffect = nullptr; 80 | } 81 | 82 | return S_OK; 83 | } 84 | 85 | D2D1_MATRIX_3X2_F STDMETHODCALLTYPE CBlurEffect::GetOutputMatrix() const 86 | { 87 | return m_customBlurEffect->GetOutputMatrix(); 88 | } 89 | 90 | void STDMETHODCALLTYPE CBlurEffect::GetOutput(ID2D1Image** output) const 91 | { 92 | if (m_outputEffect) 93 | { 94 | m_outputEffect->GetOutput(output); 95 | } 96 | else 97 | { 98 | m_customBlurEffect->GetOutput(output); 99 | } 100 | } 101 | 102 | void STDMETHODCALLTYPE CBlurEffect::Reset() 103 | { 104 | if (m_customBlurEffect) 105 | { 106 | m_customBlurEffect->Reset(); 107 | } 108 | if (m_compositeEffect) 109 | { 110 | m_compositeEffect->SetInput(0, nullptr); 111 | } 112 | } 113 | -------------------------------------------------------------------------------- /.gitattributes: -------------------------------------------------------------------------------- 1 | ############################################################################### 2 | # Set default behavior to automatically normalize line endings. 3 | ############################################################################### 4 | * text=auto 5 | 6 | ############################################################################### 7 | # Set default behavior for command prompt diff. 8 | # 9 | # This is need for earlier builds of msysgit that does not have it on by 10 | # default for csharp files. 11 | # Note: This is only used by command line 12 | ############################################################################### 13 | #*.cs diff=csharp 14 | 15 | ############################################################################### 16 | # Set the merge driver for project and solution files 17 | # 18 | # Merging from the command prompt will add diff markers to the files if there 19 | # are conflicts (Merging from VS is not affected by the settings below, in VS 20 | # the diff markers are never inserted). Diff markers may cause the following 21 | # file extensions to fail to load in VS. An alternative would be to treat 22 | # these files as binary and thus will always conflict and require user 23 | # intervention with every merge. To do so, just uncomment the entries below 24 | ############################################################################### 25 | #*.sln merge=binary 26 | #*.csproj merge=binary 27 | #*.vbproj merge=binary 28 | #*.vcxproj merge=binary 29 | #*.vcproj merge=binary 30 | #*.dbproj merge=binary 31 | #*.fsproj merge=binary 32 | #*.lsproj merge=binary 33 | #*.wixproj merge=binary 34 | #*.modelproj merge=binary 35 | #*.sqlproj merge=binary 36 | #*.wwaproj merge=binary 37 | 38 | ############################################################################### 39 | # behavior for image files 40 | # 41 | # image files are treated as binary by default. 42 | ############################################################################### 43 | #*.jpg binary 44 | #*.png binary 45 | #*.gif binary 46 | 47 | ############################################################################### 48 | # diff behavior for common document formats 49 | # 50 | # Convert binary document formats to text before diffing them. This feature 51 | # is only available from the command line. Turn it on by uncommenting the 52 | # entries below. 53 | ############################################################################### 54 | #*.doc diff=astextplain 55 | #*.DOC diff=astextplain 56 | #*.docx diff=astextplain 57 | #*.DOCX diff=astextplain 58 | #*.dot diff=astextplain 59 | #*.DOT diff=astextplain 60 | #*.pdf diff=astextplain 61 | #*.PDF diff=astextplain 62 | #*.rtf diff=astextplain 63 | #*.RTF diff=astextplain 64 | -------------------------------------------------------------------------------- /OpenGlass/AeroColorizationEffect.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "framework.hpp" 3 | #include "wil.hpp" 4 | 5 | namespace OpenGlass 6 | { 7 | // {24CAD609-0A10-4CFF-AF35-BE2A5BE07790} 8 | DEFINE_GUID(CLSID_AeroColorizationEffectPixelShader, 0x24cad609, 0xa10, 0x4cff, 0xaf, 0x35, 0xbe, 0x2a, 0x5b, 0xe0, 0x77, 0x90); 9 | // {0A46CDF3-F10E-4B71-8BAA-FEF8B0351016} 10 | DEFINE_GUID(CLSID_AeroColorizationEffect, 0xa46cdf3, 0xf10e, 0x4b71, 0x8b, 0xaa, 0xfe, 0xf8, 0xb0, 0x35, 0x10, 0x16); 11 | 12 | enum AEROCOLORIZATION_PROP 13 | { 14 | AEROCOLORIZATION_PROP_AFTERGLOW, 15 | AEROCOLORIZATION_PROP_BLURBALANCE, 16 | AEROCOLORIZATION_PROP_COLOR, 17 | }; 18 | 19 | class CAeroColorizationEffect : public ID2D1EffectImpl, public ID2D1DrawTransform 20 | { 21 | public: 22 | static STDMETHODIMP Register(ID2D1Factory1* factory); 23 | static STDMETHODIMP UnRegister(ID2D1Factory1* factory); 24 | static STDMETHODIMP Create(IUnknown** effect) noexcept; 25 | 26 | HRESULT SetAfterglow(D2D1_VECTOR_4F afterglow); 27 | D2D1_VECTOR_4F GetAfterglow() const; 28 | HRESULT SetBlurBalance(D2D1_VECTOR_4F blurBalance); 29 | D2D1_VECTOR_4F GetBlurBalance() const; 30 | HRESULT SetColor(D2D1_VECTOR_4F color); 31 | D2D1_VECTOR_4F GetColor() const; 32 | 33 | IFACEMETHODIMP Initialize( 34 | ID2D1EffectContext* effectContext, 35 | ID2D1TransformGraph* transformGraph 36 | ) override; 37 | IFACEMETHODIMP PrepareForRender(D2D1_CHANGE_TYPE changeType) override; 38 | IFACEMETHODIMP SetGraph(ID2D1TransformGraph* graph) override; 39 | IFACEMETHODIMP SetDrawInfo(ID2D1DrawInfo* drawInfo) override; 40 | IFACEMETHODIMP MapOutputRectToInputRects( 41 | const D2D1_RECT_L* outputRect, 42 | D2D1_RECT_L* inputRects, 43 | UINT32 inputRectCount 44 | ) const override; 45 | IFACEMETHODIMP MapInputRectsToOutputRect( 46 | CONST D2D1_RECT_L* inputRects, 47 | CONST D2D1_RECT_L* inputOpaqueSubRects, 48 | UINT32 inputRectCount, 49 | D2D1_RECT_L* outputRect, 50 | D2D1_RECT_L* outputOpaqueSubRect 51 | ) override; 52 | IFACEMETHODIMP MapInvalidRect( 53 | UINT32 inputIndex, 54 | D2D1_RECT_L invalidInputRect, 55 | D2D1_RECT_L* invalidOutputRect 56 | ) const override; 57 | IFACEMETHODIMP_(UINT32) GetInputCount() const override; 58 | 59 | // Declare IUnknown implementation methods. 60 | IFACEMETHODIMP_(ULONG) AddRef() override; 61 | IFACEMETHODIMP_(ULONG) Release() override; 62 | IFACEMETHODIMP QueryInterface(REFIID riid, void** output) override; 63 | private: 64 | HRESULT UpdateConstants(); 65 | 66 | struct Constants 67 | { 68 | D2D1_VECTOR_4F afterglow; 69 | D2D1_VECTOR_4F blurBalance; 70 | D2D1_VECTOR_4F color; 71 | }; 72 | 73 | ULONG m_refCount{ 1ul }; 74 | Constants m_constants{}; 75 | winrt::com_ptr m_drawInfo{}; 76 | winrt::com_ptr m_effectContext{}; 77 | }; 78 | } -------------------------------------------------------------------------------- /OpenGlass/AeroEffect.cpp: -------------------------------------------------------------------------------- 1 | #include "pch.h" 2 | #include "AeroEffect.hpp" 3 | 4 | using namespace OpenGlass; 5 | 6 | HRESULT CAeroEffect::Initialize(ID2D1DeviceContext* context) 7 | { 8 | m_customBlurEffect = winrt::make(); 9 | 10 | if (!s_factory) 11 | { 12 | winrt::com_ptr factory{}; 13 | context->GetFactory(factory.put()); 14 | RETURN_IF_FAILED(factory->QueryInterface(s_factory.put())); 15 | RETURN_IF_FAILED(CAeroColorizationEffect::Register(s_factory.get())); 16 | } 17 | RETURN_IF_FAILED( 18 | context->CreateEffect( 19 | CLSID_AeroColorizationEffect, 20 | m_colorizationEffect.put() 21 | ) 22 | ); 23 | 24 | m_initialized = true; 25 | 26 | return S_OK; 27 | } 28 | 29 | HRESULT STDMETHODCALLTYPE CAeroEffect::Build( 30 | ID2D1DeviceContext* context, 31 | ID2D1Image* inputImage, 32 | const D2D1_RECT_F& imageRectangle, 33 | const void* additionalParams 34 | ) 35 | { 36 | if (!m_initialized) 37 | { 38 | RETURN_IF_FAILED(Initialize(context)); 39 | } 40 | const auto params = static_cast(additionalParams); 41 | 42 | RETURN_IF_FAILED( 43 | m_customBlurEffect->Build( 44 | context, 45 | inputImage, 46 | imageRectangle, 47 | additionalParams 48 | ) 49 | ); 50 | const auto fullyTransparent = 51 | params->afterglowBalance == 0.f && 52 | params->colorBalance == 0.f && 53 | params->blurBalance == 1.f; 54 | if (!fullyTransparent) 55 | { 56 | RETURN_IF_FAILED( 57 | m_colorizationEffect->SetValue( 58 | AEROCOLORIZATION_PROP_AFTERGLOW, 59 | D2D1::Vector4F( 60 | params->afterglow.r * params->afterglowBalance, 61 | params->afterglow.g * params->afterglowBalance, 62 | params->afterglow.b * params->afterglowBalance, 63 | 1.f 64 | ) 65 | ) 66 | ); 67 | RETURN_IF_FAILED( 68 | m_colorizationEffect->SetValue( 69 | AEROCOLORIZATION_PROP_BLURBALANCE, 70 | D2D1::Vector4F( 71 | params->blurBalance 72 | ) 73 | ) 74 | ); 75 | RETURN_IF_FAILED( 76 | m_colorizationEffect->SetValue( 77 | AEROCOLORIZATION_PROP_COLOR, 78 | D2D1::Vector4F( 79 | params->color.r * params->colorBalance, 80 | params->color.g * params->colorBalance, 81 | params->color.b * params->colorBalance, 82 | 1.f 83 | ) 84 | ) 85 | ); 86 | 87 | winrt::com_ptr image{}; 88 | m_customBlurEffect->GetOutput(image.put()); 89 | m_colorizationEffect->SetInput(0, image.get()); 90 | m_outputEffect = m_colorizationEffect; 91 | } 92 | else 93 | { 94 | m_outputEffect = nullptr; 95 | } 96 | 97 | return S_OK; 98 | } 99 | 100 | D2D1_MATRIX_3X2_F STDMETHODCALLTYPE CAeroEffect::GetOutputMatrix() const 101 | { 102 | return m_customBlurEffect->GetOutputMatrix(); 103 | } 104 | 105 | void STDMETHODCALLTYPE CAeroEffect::GetOutput(ID2D1Image** output) const 106 | { 107 | if (m_outputEffect) 108 | { 109 | m_outputEffect->GetOutput(output); 110 | } 111 | else 112 | { 113 | m_customBlurEffect->GetOutput(output); 114 | } 115 | } 116 | 117 | void STDMETHODCALLTYPE CAeroEffect::Reset() 118 | { 119 | if (m_customBlurEffect) 120 | { 121 | m_customBlurEffect->Reset(); 122 | } 123 | if (m_colorizationEffect) 124 | { 125 | m_colorizationEffect->SetInput(0, nullptr); 126 | } 127 | } 128 | -------------------------------------------------------------------------------- /OpenGlass/GlassEngine.cpp: -------------------------------------------------------------------------------- 1 | #include "pch.h" 2 | #include "GlassEngine.hpp" 3 | #include "CaptionTextHandler.hpp" 4 | #include "ButtonGlowHandler.hpp" 5 | #include "GlassKernel.hpp" 6 | #include "AccentOverrider.hpp" 7 | #include "GlassFrameHandler.hpp" 8 | #include "GlassReflectionHandler.hpp" 9 | #include "GlassRenderer.hpp" 10 | #include "GlassIntegrity.hpp" 11 | #include "CustomThemeAtlasLoader.hpp" 12 | #include "GlassService.hpp" 13 | 14 | using namespace OpenGlass; 15 | namespace OpenGlass::GlassEngine 16 | { 17 | wil::unique_hkey g_dwmKey{ nullptr }; 18 | wil::unique_hkey g_personalizeKey{ nullptr }; 19 | wil::unique_hkey g_dwmLocalMachineKey{ nullptr }; 20 | } 21 | 22 | HKEY GlassEngine::GetDwmKey() 23 | { 24 | return g_dwmKey.get(); 25 | } 26 | 27 | HKEY GlassEngine::GetPersonalizeKey() 28 | { 29 | return g_personalizeKey.get(); 30 | } 31 | 32 | HKEY GlassEngine::GetDwmLocalMachineKey() 33 | { 34 | return g_dwmLocalMachineKey.get(); 35 | } 36 | 37 | void GlassEngine::LoadRegistry(bool redrawNow) 38 | { 39 | UnloadRegistry(); 40 | 41 | GlassService::RequestBuffer content{ GlassService::RequestType::OpenUserRegistry }; 42 | const auto hr = GlassService::SendRequest(content); 43 | if (SUCCEEDED(hr)) 44 | { 45 | if (content.dwmKey) 46 | { 47 | g_dwmKey.reset(content.dwmKey); 48 | } 49 | if (content.personalizeKey) 50 | { 51 | g_personalizeKey.reset(content.personalizeKey); 52 | } 53 | Update(UpdateType::All, redrawNow); 54 | } 55 | wil::reg::open_unique_key_nothrow(HKEY_LOCAL_MACHINE, L"Software\\Microsoft\\Windows\\DWM", g_dwmLocalMachineKey); 56 | } 57 | void GlassEngine::UnloadRegistry() 58 | { 59 | wil::reg::open_unique_key_nothrow(HKEY_LOCAL_MACHINE, L"Software\\Microsoft\\Windows\\DWM", g_dwmKey); 60 | wil::reg::open_unique_key_nothrow(HKEY_LOCAL_MACHINE, L"SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Themes\\Personalize", g_personalizeKey); 61 | wil::reg::open_unique_key_nothrow(HKEY_LOCAL_MACHINE, L"Software\\Microsoft\\Windows\\DWM", g_dwmLocalMachineKey); 62 | } 63 | 64 | void GlassEngine::RedrawAll() 65 | { 66 | GlassKernel::RedrawAllTopLevelWindow(); 67 | } 68 | 69 | void GlassEngine::Update(UpdateType type, bool redrawNow) 70 | { 71 | { 72 | const auto lock = wil::EnterCriticalSection(uDWM::CDesktopManager::s_csDwmInstance); 73 | GlassKernel::Update(type); 74 | CustomThemeAtlasLoader::Update(type); 75 | CaptionTextHandler::Update(type); 76 | ButtonGlowHandler::Update(type); 77 | AccentOverrider::Update(type); 78 | GlassFrameHandler::Update(type); 79 | GlassReflectionHandler::Update(type); 80 | GlassRenderer::Update(type); 81 | GlassIntegrity::Update(type); 82 | } 83 | if (redrawNow) 84 | { 85 | GlassKernel::RedrawAllTopLevelWindow(); 86 | //DwmFlush(); 87 | } 88 | } 89 | 90 | void GlassEngine::Startup() 91 | { 92 | const auto lock = wil::EnterCriticalSection(uDWM::CDesktopManager::s_csDwmInstance); 93 | GlassKernel::Startup(); 94 | CustomThemeAtlasLoader::Startup(); 95 | CaptionTextHandler::Startup(); 96 | ButtonGlowHandler::Startup(); 97 | AccentOverrider::Startup(); 98 | GlassFrameHandler::Startup(); 99 | GlassReflectionHandler::Startup(); 100 | GlassRenderer::Startup(); 101 | GlassIntegrity::Startup(); 102 | } 103 | void GlassEngine::Shutdown() 104 | { 105 | const auto lock = wil::EnterCriticalSection(uDWM::CDesktopManager::s_csDwmInstance); 106 | GlassIntegrity::Shutdown(); 107 | GlassRenderer::Shutdown(); 108 | GlassReflectionHandler::Shutdown(); 109 | GlassFrameHandler::Shutdown(); 110 | AccentOverrider::Shutdown(); 111 | ButtonGlowHandler::Shutdown(); 112 | CaptionTextHandler::Shutdown(); 113 | CustomThemeAtlasLoader::Shutdown(); 114 | GlassKernel::Shutdown(); 115 | } 116 | -------------------------------------------------------------------------------- /OpenGlass/D2DPrivates.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "framework.hpp" 3 | 4 | namespace OpenGlass 5 | { 6 | const GUID CLSID_D2D1DirectionalBlurKernel{ 0x58EB6E2A, 0x0D779, 0x4B7D, { 0x0AD, 0x39, 0x6F, 0x5A, 0x9F, 0x0C9, 0x0D2, 0x88} }; 7 | enum D2D1_DIRECTIONALBLURKERNEL_PROP 8 | { 9 | D2D1_DIRECTIONALBLURKERNEL_PROP_STANDARD_DEVIATION, 10 | D2D1_DIRECTIONALBLURKERNEL_PROP_DIRECTION, 11 | D2D1_DIRECTIONALBLURKERNEL_PROP_KERNEL_RANGE_FACTOR, 12 | D2D1_DIRECTIONALBLURKERNEL_PROP_OPTIMIZATION_TRANSFORM 13 | }; 14 | enum D2D1_DIRECTIONALBLURKERNEL_DIRECTION 15 | { 16 | D2D1_DIRECTIONALBLURKERNEL_DIRECTION_X, 17 | D2D1_DIRECTIONALBLURKERNEL_DIRECTION_Y 18 | }; 19 | enum D2D1_DIRECTIONALBLURKERNEL_OPTIMIZATION_TRANSFORM 20 | { 21 | D2D1_DIRECTIONALBLURKERNEL_OPTIMIZATION_TRANSFORM_IDENDITY, 22 | D2D1_DIRECTIONALBLURKERNEL_OPTIMIZATION_TRANSFORM_SCALE 23 | }; 24 | 25 | struct ID2D1PrivateCompositorBuffer : IUnknown {}; 26 | struct ID2D1PrivateCompositorCommandList : IUnknown {}; 27 | struct ID2D1PrivateCompositorPrimitiveProperties : IUnknown {}; 28 | struct ID2D1PrivateDepthBuffer : IUnknown {}; 29 | struct IDXGISwapChainDWM1 : IUnknown {}; 30 | struct ID2D1PrivateCompositorRenderer : IUnknown {}; 31 | struct DXGI_PRESENT_MULTIPLANE_OVERLAY; 32 | enum D2D1_DRAW_COMPOSITOR_COMMAND_LIST_OPTIONS : UINT {}; 33 | enum D2D1_DEVICE_CONTEXT_BATCHING_STATE : UINT {}; 34 | enum D2D1_INK_RENDERING_HINT : UINT {}; 35 | 36 | DECLARE_INTERFACE_IID_(ID2D1PrivateCompositorDeviceContext, IUnknown, "2ea67ed7-d42e-4c07-9dd5-a91ea23e01d2") 37 | { 38 | STDMETHODV(CreateCompositorCommandList)(ID2D1PrivateCompositorBuffer*, ID2D1PrivateCompositorBuffer*, ID2D1Bitmap**, UINT, ID2D1Bitmap**, UINT, ID2D1PrivateCompositorPrimitiveProperties**, UINT, ID2D1PrivateCompositorCommandList**) PURE; 39 | STDMETHODV(DrawCompositorCommandList)(ID2D1PrivateCompositorCommandList*, float, D2D_MATRIX_4X4_F const*, D2D1_DRAW_COMPOSITOR_COMMAND_LIST_OPTIONS, UINT) PURE; 40 | STDMETHODV(CreatePrimitiveProperties)(ID2D1PrivateCompositorPrimitiveProperties**)PURE; 41 | STDMETHODV(SetPrimitiveColor)(ID2D1PrivateCompositorPrimitiveProperties*, D2D1_COLOR_F const*) PURE; 42 | STDMETHODV(SetTargetAndDepthBuffer)(ID2D1Image*, ID2D1PrivateDepthBuffer*) PURE; 43 | STDMETHODV(GetDepthBuffer)(ID2D1PrivateDepthBuffer**) PURE; 44 | STDMETHODV(SetGuardRect)(ID2D1Bitmap*, RECT const*) PURE; 45 | STDMETHODV(SetPrimitiveClip)(D2D1_RECT_F const*, D2D1_ANTIALIAS_MODE) PURE; 46 | STDMETHODV(QueryBatchingState)(D2D1_DEVICE_CONTEXT_BATCHING_STATE*) PURE; 47 | STDMETHODV(CreateSharedAtlasBitmap)(ID2D1Bitmap1 const*, D2D1_BITMAP_PROPERTIES1 const*, ID2D1Bitmap1**) PURE; 48 | STDMETHODV(PresentDWM)(IDXGISwapChainDWM1*, UINT, UINT, RECT const*, UINT, DXGI_PRESENT_MULTIPLANE_OVERLAY const*, UINT, IDXGIResource*, UINT) PURE; 49 | STDMETHODV(PresentMultiplaneOverlay)(IDXGISwapChainDWM1*, UINT, UINT, DXGI_HDR_METADATA_TYPE, void const*, DXGI_PRESENT_MULTIPLANE_OVERLAY const*, UINT) PURE; 50 | STDMETHODV(DrawCompositorPrimitives)(ID2D1PrivateCompositorRenderer*) PURE; 51 | STDMETHODV(CreateCompositorCommandListWithBounds)(ID2D1PrivateCompositorBuffer*, ID2D1PrivateCompositorBuffer*, ID2D1Bitmap**, UINT, ID2D1Bitmap**, UINT, ID2D1PrivateCompositorPrimitiveProperties**, UINT, D2D1_RECT_F const*, ID2D1PrivateCompositorCommandList**) PURE; 52 | STDMETHODV(SetInkRenderingHint)(D2D1_INK_RENDERING_HINT) PURE; 53 | STDMETHODV(GetInkRenderingHint)(void) PURE; 54 | STDMETHODV(SignalFence)(ID3D11Fence*, UINT64) PURE; 55 | }; 56 | 57 | interface DX_DECLARE_INTERFACE("e7fda62a-6a94-4f17-9f7c-26a950c74010") ID2D1RegionGeometry : public ID2D1Geometry 58 | { 59 | virtual UINT STDMETHODCALLTYPE GetRectanglesCount() const = 0; 60 | virtual void STDMETHODCALLTYPE GetRectangles(RECT* buffer, UINT count) const = 0; 61 | }; 62 | } 63 | -------------------------------------------------------------------------------- /OpenGlass/D3DGlassRealizer.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "framework.hpp" 3 | #include "cpprt.hpp" 4 | #include "dwmcoreProjection.hpp" 5 | #include "AeroEffect.hpp" 6 | #include "Shared.hpp" 7 | 8 | namespace OpenGlass 9 | { 10 | struct CConstantBuffer 11 | { 12 | D2D1_VECTOR_2F viewportSize; 13 | D2D1_VECTOR_2F texelSize; 14 | D2D1_VECTOR_4F afterglow; 15 | D2D1_VECTOR_4F blurBalance; 16 | D2D1_VECTOR_4F color; 17 | }; 18 | 19 | class CD3DGlassRealizer 20 | { 21 | bool m_initialized{ false }; 22 | 23 | UINT m_backBufferWidth{}; 24 | UINT m_backBufferHeight{}; 25 | DXGI_FORMAT m_dxgiFormat{}; 26 | CConstantBuffer m_cb{}; 27 | winrt::com_ptr m_vertexShader{ nullptr }; 28 | winrt::com_ptr m_pixelShaderBlurH{ nullptr }; 29 | winrt::com_ptr m_pixelShaderBlurV{ nullptr }; 30 | winrt::com_ptr m_pixelShaderPassthrough{ nullptr }; 31 | winrt::com_ptr m_vertexLayout{ nullptr }; 32 | winrt::com_ptr m_vertexBuffer{ nullptr }; 33 | winrt::com_ptr m_indexBuffer{ nullptr }; 34 | // Dedicated buffers: blur passes use m_vertexBuffer/m_indexBuffer; compose pass uses the following 35 | winrt::com_ptr m_vertexBufferCompose{ nullptr }; 36 | winrt::com_ptr m_indexBufferCompose{ nullptr }; 37 | 38 | // Dynamic capacities (counts, not bytes) 39 | size_t m_vertexCapacityBlur{ 128 }; 40 | size_t m_indexCapacityBlur{ 128 }; 41 | size_t m_vertexCapacityCompose{ 128 }; 42 | size_t m_indexCapacityCompose{ 128 }; 43 | winrt::com_ptr m_constantBuffer{ nullptr }; 44 | winrt::com_ptr m_samplerLinear{ nullptr }; 45 | 46 | winrt::com_ptr m_texHalfRes1{ nullptr }; 47 | winrt::com_ptr m_rtvHalfRes1{ nullptr }; 48 | winrt::com_ptr m_srvHalfRes1{ nullptr }; 49 | 50 | winrt::com_ptr m_texHalfRes2{ nullptr }; 51 | winrt::com_ptr m_rtvHalfRes2{ nullptr }; 52 | winrt::com_ptr m_srvHalfRes2{ nullptr }; 53 | 54 | winrt::com_ptr m_rasterizerStateScissor{ nullptr }; 55 | 56 | static HRESULT CompileShader( 57 | LPCSTR sourceData, 58 | SIZE_T sourceSize, 59 | LPCSTR entryPoint, 60 | LPCSTR shaderModel, 61 | ID3DBlob** blob 62 | ); 63 | 64 | HRESULT CreateDeviceResources(ID3D11Device* device); 65 | HRESULT CreateSizeDependentResources(ID3D11Device* device); 66 | HRESULT Initialize(ID3D11Device* device); 67 | HRESULT EnsureMeshBuffersCapacity( 68 | ID3D11Device* device, 69 | size_t requiredVertexCount, 70 | size_t requiredIndexCount, 71 | winrt::com_ptr& vb, 72 | winrt::com_ptr& ib, 73 | size_t& vertexCapacity, 74 | size_t& indexCapacity 75 | ); 76 | HRESULT Tessellate( 77 | ID2D1Geometry* geometry, 78 | std::vector& vertices, 79 | std::vector& indices 80 | ); 81 | public: 82 | HRESULT Render( 83 | ID3D11Device* device, 84 | ID3D11DeviceContext* context1, 85 | ID3D11Texture2D* backBuffer, 86 | ID3D11RenderTargetView* backBufferRTV, 87 | ID3D11ShaderResourceView* backBufferSRV, 88 | ID2D1Geometry* geometry, 89 | const D2D1_RECT_F& drawingWorldbounds, 90 | const D2D1_RECT_F& samplingWorldbounds, 91 | const CAeroParams& params, 92 | bool shapeIsRectangles 93 | ); 94 | }; 95 | } 96 | -------------------------------------------------------------------------------- /OpenGlass/Shared.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "framework.hpp" 3 | #include "cpprt.hpp" 4 | 5 | namespace OpenGlass::Shared 6 | { 7 | inline bool g_xxSaver{ false }; 8 | inline bool g_transparencyEnabled{ true }; 9 | 10 | inline enum class GlassType : UINT 11 | { 12 | Blur, 13 | Aero, 14 | 15 | Invalid = 0xFF 16 | } g_type{ 0 }; 17 | inline enum ReflectionPolicy : UINT 18 | { 19 | NonClient = 1 << 0, 20 | LivePreview = 1 << 2, 21 | AnimatedGlassSheet = 1 << 3, 22 | } g_reflectionPolicy{ 0 }; 23 | 24 | inline bool g_disableOnBattery{ true }; 25 | inline bool g_overrideAccent{ false }; 26 | inline bool g_disableModernBorders{ false }; 27 | inline int g_roundRectRadius{}; 28 | inline float g_blurAmount{}; 29 | inline D2D1_GAUSSIANBLUR_OPTIMIZATION g_blurOptimization{}; 30 | inline float g_glassOpacity{}; 31 | inline float g_glassOpacityInactive{}; 32 | inline bool g_useD3DRendering{}; 33 | 34 | inline D2D1_COLOR_F g_color{}; 35 | inline D2D1_COLOR_F g_colorInactive{}; 36 | 37 | // vista: 1.f 38 | // w7: 1.f 39 | inline float g_colorizationBlendingOpacity{}; 40 | // vista: 0.55f 41 | // w7: 0.4f 42 | inline float g_colorizationBlendingOpacityInactive{}; 43 | // vista: 0.75f 44 | // w7: 1.f 45 | inline float g_colorizationBlendingOpacityMaximized{}; 46 | // vista: 0.75f 47 | // w7: 0.4f 48 | inline float g_colorizationBlendingOpacityInactiveMaximized{}; 49 | 50 | inline float g_captionOpacity{}; 51 | inline float g_captionOpacityInactive{}; 52 | inline float g_captionOpacityMaximized{}; 53 | inline float g_captionOpacityInactiveMaximized{}; 54 | 55 | inline enum OpaqueBlendPriority : UINT 56 | { 57 | Vista, 58 | Win7 59 | } g_opaqueBlendPriority{ 0 }; 60 | inline bool g_opaqueBlend{}; 61 | inline D2D1_COLOR_F g_opaqueBlendColor{}; 62 | inline D2D1_COLOR_F g_opaqueBlendColorMaximized{}; 63 | 64 | inline float g_colorBalance{}; 65 | inline float g_afterglowBalance{}; 66 | inline float g_blurBalance{}; 67 | inline D2D1_COLOR_F g_afterglow{}; 68 | 69 | inline BITMAPINFO g_textGlowBitmapInfo{}; 70 | inline PVOID g_textGlowBitmapPixels{}; 71 | inline wil::unique_hbitmap g_textGlowBitmap{}; 72 | inline int g_textGlowMode{}; 73 | inline bool g_dontDeflateInactiveFrameGeometry{ true }; 74 | inline std::optional g_captionHeight{}; 75 | 76 | inline float g_reflectionIntensity{}; 77 | inline float g_reflectionIntensityInactive{}; 78 | inline float g_reflectionIntensityMaximized{}; 79 | inline float g_reflectionIntensityInactiveMaximized{}; 80 | 81 | inline float g_reflectionParallaxIntensity{}; 82 | inline std::wstring g_reflectionTexturePath{}; 83 | 84 | inline float g_materialIntensity{}; 85 | inline std::wstring g_materialTexturePath{}; 86 | 87 | FORCEINLINE bool IsTransparencyDisabled() 88 | { 89 | if (g_opaqueBlend) 90 | { 91 | return true; 92 | } 93 | if (g_xxSaver && g_disableOnBattery) 94 | { 95 | return true; 96 | } 97 | if (!g_transparencyEnabled) 98 | { 99 | return true; 100 | } 101 | 102 | return false; 103 | } 104 | FORCEINLINE bool IsOpaqueOnMaximized(bool maximized) 105 | { 106 | return maximized && g_opaqueBlendColorMaximized.a != 0.f; 107 | } 108 | FORCEINLINE bool IsGlassFullyOpaque( 109 | float alpha, 110 | float blurBalance, 111 | float afterglowBalance 112 | ) 113 | { 114 | if ( 115 | g_type == GlassType::Blur && 116 | alpha == 1.f 117 | ) 118 | { 119 | return true; 120 | } 121 | // uDWM!CCapturedGlassColorizationParameters::IsGlassFullyOpaque (Windows 7) 122 | if ( 123 | #pragma warning(suppress:26813) 124 | g_type == GlassType::Aero && 125 | blurBalance == 0.f && 126 | afterglowBalance == 0.f 127 | ) 128 | { 129 | return true; 130 | } 131 | 132 | return false; 133 | } 134 | } 135 | -------------------------------------------------------------------------------- /OpenGlass/D2DBuffer.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "framework.hpp" 3 | #include "wil.hpp" 4 | #include "D2DPrivates.hpp" 5 | 6 | namespace OpenGlass 7 | { 8 | class CD2DBuffer 9 | { 10 | D2D1_SIZE_U m_size{}; 11 | winrt::com_ptr m_buffer{}; 12 | winrt::com_ptr m_bufferAlphaPremultiplied{}; 13 | 14 | HRESULT EnsureBitmapAndCompatibility(ID2D1DeviceContext* context, ID2D1Bitmap1* bitmap) 15 | { 16 | winrt::com_ptr colorContext; 17 | const auto pixelFormat = bitmap->GetPixelFormat(); 18 | bitmap->GetColorContext(colorContext.put()); 19 | 20 | if (m_buffer) 21 | { 22 | winrt::com_ptr bufferColorContext; 23 | const auto bufferPixelFormat = m_buffer->GetPixelFormat(); 24 | m_buffer->GetColorContext(colorContext.put()); 25 | 26 | if ( 27 | bufferPixelFormat.format != pixelFormat.format || 28 | bufferColorContext != colorContext 29 | ) 30 | { 31 | Reset(); 32 | } 33 | } 34 | 35 | auto bitmapProperties = D2D1::BitmapProperties1( 36 | D2D1_BITMAP_OPTIONS_NONE, 37 | D2D1::PixelFormat( 38 | pixelFormat.format, 39 | D2D1_ALPHA_MODE_IGNORE 40 | ) 41 | ); 42 | if (!m_buffer) 43 | { 44 | RETURN_IF_FAILED( 45 | context->CreateBitmap( 46 | m_size, 47 | nullptr, 48 | 0, 49 | bitmapProperties, 50 | m_buffer.put() 51 | ) 52 | ); 53 | } 54 | if (!m_bufferAlphaPremultiplied) 55 | { 56 | winrt::com_ptr compositorDeviceContext{}; 57 | if ( 58 | bitmapProperties.pixelFormat.alphaMode = D2D1_ALPHA_MODE_PREMULTIPLIED; 59 | FAILED(context->QueryInterface(compositorDeviceContext.put())) || 60 | FAILED( 61 | compositorDeviceContext->CreateSharedAtlasBitmap( 62 | m_buffer.get(), 63 | &bitmapProperties, 64 | m_bufferAlphaPremultiplied.put() 65 | ) 66 | ) 67 | ) 68 | { 69 | winrt::com_ptr sharedBitmap{}; 70 | context->CreateSharedBitmap( 71 | IID_ID2D1Bitmap, 72 | m_buffer.get(), 73 | reinterpret_cast(&bitmapProperties), 74 | sharedBitmap.put() 75 | ); 76 | RETURN_IF_FAILED(sharedBitmap->QueryInterface(m_bufferAlphaPremultiplied.put())); 77 | } 78 | } 79 | 80 | return S_OK; 81 | } 82 | public: 83 | void Reset() 84 | { 85 | m_size = {}; 86 | m_buffer = nullptr; 87 | m_bufferAlphaPremultiplied = nullptr; 88 | } 89 | void Resize(const D2D1_SIZE_U& size) 90 | { 91 | if ( 92 | m_size.width != size.width || 93 | m_size.height != size.height 94 | ) 95 | { 96 | Reset(); 97 | m_size = size; 98 | } 99 | } 100 | void Reserve(const D2D1_SIZE_U& size) 101 | { 102 | if ( 103 | m_size.width < size.width || 104 | m_size.height < size.height 105 | ) 106 | { 107 | Reset(); 108 | m_size = size; 109 | } 110 | } 111 | HRESULT CopyFrom( 112 | ID2D1DeviceContext* context, 113 | const D2D1_POINT_2U& destPoint, 114 | ID2D1Bitmap1* bitmap, 115 | const D2D1_RECT_U& srcRect 116 | ) 117 | { 118 | RETURN_IF_FAILED(EnsureBitmapAndCompatibility(context, bitmap)); 119 | RETURN_IF_FAILED( 120 | (bitmap->GetPixelFormat().alphaMode == D2D1_ALPHA_MODE_IGNORE ? m_buffer : m_bufferAlphaPremultiplied)->CopyFromBitmap( 121 | &destPoint, 122 | bitmap, 123 | &srcRect 124 | ) 125 | ); 126 | 127 | return S_OK; 128 | } 129 | HRESULT CopyTo( 130 | const D2D1_POINT_2U& destPoint, 131 | ID2D1Bitmap* bitmap, 132 | const D2D1_RECT_U& srcRect 133 | ) 134 | { 135 | return bitmap->CopyFromBitmap( 136 | &destPoint, 137 | (bitmap->GetPixelFormat().alphaMode == D2D1_ALPHA_MODE_IGNORE ? m_buffer : m_bufferAlphaPremultiplied).get(), 138 | &srcRect 139 | ); 140 | } 141 | ID2D1Bitmap* GetCompatibleD2DBitmap(ID2D1DeviceContext* context, ID2D1Bitmap1* bitmap) 142 | { 143 | EnsureBitmapAndCompatibility(context, bitmap); 144 | return (bitmap->GetPixelFormat().alphaMode == D2D1_ALPHA_MODE_IGNORE ? m_buffer : m_bufferAlphaPremultiplied).get(); 145 | } 146 | }; 147 | } 148 | -------------------------------------------------------------------------------- /OpenGlass/SymbolParser.cpp: -------------------------------------------------------------------------------- 1 | #include "pch.h" 2 | #include "Util.hpp" 3 | #include "HookHelper.hpp" 4 | #include "SymbolParser.hpp" 5 | 6 | using namespace OpenGlass; 7 | 8 | BOOL CALLBACK CSymbolParser::EnumSymbolsCallback( 9 | PSYMBOL_INFO pSymInfo, 10 | ULONG SymbolSize, 11 | PVOID UserContext 12 | ) 13 | { 14 | return static_cast(reinterpret_cast(UserContext)(pSymInfo, SymbolSize)); 15 | } 16 | 17 | BOOL CALLBACK CSymbolParser::SymCallback( 18 | [[maybe_unused]] HANDLE hProcess, 19 | ULONG ActionCode, 20 | ULONG64 CallbackData, 21 | ULONG64 UserContext 22 | ) 23 | { 24 | if (ActionCode == CBA_EVENT) 25 | { 26 | auto& symbolParser = *reinterpret_cast(UserContext); 27 | auto event = reinterpret_cast(CallbackData); 28 | 29 | return static_cast(symbolParser.m_eventCallback(event)); 30 | } 31 | return FALSE; 32 | } 33 | 34 | HMODULE WINAPI CSymbolParser::MyLoadLibraryExW( 35 | LPCWSTR lpLibFileName, 36 | HANDLE hFile, 37 | DWORD dwFlags 38 | ) 39 | { 40 | if (std::wstring loweredLibFileName{ lpLibFileName }; wcsstr(CharLowerW(loweredLibFileName.data()), L"symsrv.dll")) [[likely]] 41 | { 42 | const auto symsrvFilePath = Util::make_current_folder_file(L"symsrv.dll"); 43 | return LoadLibraryW(symsrvFilePath.get()); 44 | } 45 | 46 | return LoadLibraryExW(lpLibFileName, hFile, dwFlags); 47 | } 48 | 49 | CSymbolParser::CSymbolParser(SymbolEventCallback* callback) : m_eventCallback{ callback } 50 | { 51 | m_LoadLibraryExW_Org = HookHelper::WriteIAT(GetModuleHandleW(L"dbghelp.dll"), "api-ms-win-core-libraryloader-l1-1-0.dll", "LoadLibraryExW", MyLoadLibraryExW); 52 | THROW_IF_WIN32_BOOL_FALSE( 53 | SymInitializeW( 54 | GetCurrentProcess(), 55 | ( 56 | std::wstring{ L"SRV*" } + 57 | Util::make_current_folder_file(L"symbols").get() + 58 | L"*https://msdl.microsoft.com/download/symbols" 59 | ).c_str(), 60 | FALSE 61 | ) 62 | ); 63 | 64 | // SYMOPT_PUBLICS_ONLY is required for ensuring all retrived function names are decorated 65 | // before calling UnDecorateSymbolName 66 | SymSetOptions( 67 | SYMOPT_DEBUG | 68 | SYMOPT_PUBLICS_ONLY | 69 | SYMOPT_NO_PROMPTS 70 | ); 71 | THROW_IF_WIN32_BOOL_FALSE( 72 | SymRegisterCallbackW64( 73 | GetCurrentProcess(), 74 | SymCallback, 75 | reinterpret_cast(this) 76 | ) 77 | ); 78 | } 79 | 80 | CSymbolParser::~CSymbolParser() noexcept 81 | { 82 | THROW_IF_WIN32_BOOL_FALSE(SymCleanup(GetCurrentProcess())); 83 | m_LoadLibraryExW_Org = HookHelper::WriteIAT(GetModuleHandleW(L"dbghelp.dll"), "api-ms-win-core-libraryloader-l1-1-0.dll", "LoadLibraryExW", m_LoadLibraryExW_Org); 84 | } 85 | 86 | HRESULT CSymbolParser::LoadAndParse(PCWSTR moduleName, SymbolParserCallback* callback) try 87 | { 88 | std::wstring filePath{}; 89 | { 90 | wil::unique_hmodule moduleHandle 91 | { 92 | LoadLibraryExW( 93 | moduleName, 94 | nullptr, 95 | DONT_RESOLVE_DLL_REFERENCES 96 | ) 97 | }; 98 | THROW_LAST_ERROR_IF_NULL(moduleHandle); 99 | THROW_IF_FAILED((wil::GetModuleFileNameW(moduleHandle.get(), filePath))); 100 | } 101 | 102 | const auto moduleBase = SymLoadModuleExW( 103 | GetCurrentProcess(), 104 | nullptr, 105 | filePath.data(), 106 | nullptr, 107 | 0, 108 | 0, 109 | nullptr, 110 | 0 111 | ); 112 | THROW_LAST_ERROR_IF(moduleBase == 0); 113 | const auto symCleanUp = wil::scope_exit([=] 114 | { 115 | if (moduleBase != 0) 116 | { 117 | SymUnloadModule64(GetCurrentProcess(), moduleBase); 118 | } 119 | }); 120 | 121 | IMAGEHLP_MODULEW64 moduleInfo{ sizeof(moduleInfo) }; 122 | THROW_IF_WIN32_BOOL_FALSE( 123 | SymGetModuleInfoW64( 124 | GetCurrentProcess(), 125 | moduleBase, 126 | &moduleInfo 127 | ) 128 | ); 129 | THROW_WIN32_IF_MSG( 130 | ERROR_FILE_NOT_FOUND, 131 | *moduleInfo.LoadedPdbName == L'\0', 132 | "Symbols NOT loaded for %ls\n", 133 | moduleName 134 | ); 135 | THROW_WIN32_IF_MSG( 136 | ERROR_FILE_CORRUPT, 137 | (moduleInfo.SymType & 0xFFFFFFFB) == 0, 138 | "Invalid symbol type %d for module %ls\n", 139 | moduleInfo.SymType, 140 | moduleName 141 | ); 142 | 143 | THROW_IF_WIN32_BOOL_FALSE( 144 | SymEnumSymbols( 145 | GetCurrentProcess(), 146 | moduleBase, 147 | nullptr, 148 | EnumSymbolsCallback, 149 | callback 150 | ) 151 | ); 152 | 153 | return S_OK; 154 | } 155 | CATCH_RETURN() -------------------------------------------------------------------------------- /OpenGlass/HookHelper.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "framework.hpp" 3 | #include "cpprt.hpp" 4 | #include "wil.hpp" 5 | 6 | namespace OpenGlass::HookHelper 7 | { 8 | struct pss_snapshot 9 | { 10 | static void close(HPSS snapshot) WI_NOEXCEPT 11 | { 12 | ::PssFreeSnapshot(GetCurrentProcess(), snapshot); 13 | } 14 | }; 15 | typedef wil::unique_any unique_pss_snapshot_local; 16 | typedef wil::unique_any unique_pss_walk_marker; 17 | 18 | FORCEINLINE auto unprotect(PVOID address, SIZE_T size) 19 | { 20 | THROW_HR_IF_NULL(E_INVALIDARG, address); 21 | DWORD oldProtect{ 0 }; 22 | THROW_IF_WIN32_BOOL_FALSE( 23 | VirtualProtect( 24 | address, 25 | size, 26 | PAGE_EXECUTE_READWRITE, 27 | &oldProtect 28 | ) 29 | ); 30 | return wil::scope_exit([=] 31 | { 32 | auto unused = 0ul; 33 | THROW_IF_WIN32_BOOL_FALSE( 34 | VirtualProtect( 35 | address, 36 | size, 37 | oldProtect, 38 | &unused 39 | ) 40 | ); 41 | }); 42 | } 43 | void PatchInstructions(void* memory, const UCHAR* data, size_t length); 44 | void WritePointerInternal(PVOID* pointerAddress, PVOID value, PVOID* originalValue = nullptr); 45 | template FORCEINLINE void WritePointer(T1 address, T2 value, T2* originalValue = nullptr) { WritePointerInternal(reinterpret_cast(address), reinterpret_cast(value), reinterpret_cast(originalValue)); } 46 | 47 | HMODULE GetProcessModule(HANDLE processHandle, std::wstring_view dllPath); 48 | 49 | void WalkIAT(PVOID baseAddress, std::string_view dllName, std::function callback); 50 | void WalkDelayloadIAT(PVOID baseAddress, std::string_view dllName, std::function callback); 51 | 52 | PVOID* GetIAT(PVOID baseAddress, std::string_view dllName, LPCSTR targetFunctionNameOrOrdinal); 53 | std::pair GetDelayloadIAT(PVOID baseAddress, std::string_view dllName, LPCSTR targetFunctionNameOrOrdinal, bool resolveAPI = false); 54 | PVOID WriteIAT(PVOID baseAddress, std::string_view dllName, LPCSTR targetFunctionNameOrOrdinal, PVOID detourFunction); 55 | std::pair WriteDelayloadIAT(PVOID baseAddress, std::string_view dllName, LPCSTR targetFunctionNameOrOrdinal, PVOID detourFunction, std::optional newModuleHandle = std::nullopt); 56 | void ResolveDelayloadIAT(const std::pair& info, PVOID baseAddress, std::string_view dllName, LPCSTR targetFunctionNameOrOrdinal); 57 | 58 | template 59 | FORCEINLINE T* vftbl_of(const void* This) 60 | { 61 | return reinterpret_cast(*reinterpret_cast(const_cast(This))); 62 | } 63 | 64 | struct OffsetStorage 65 | { 66 | LONGLONG value{ 0 }; 67 | 68 | FORCEINLINE bool IsValid() const { return value != 0; } 69 | template 70 | FORCEINLINE T To(T2 baseAddress) const { if (baseAddress == 0 || !IsValid()) { return 0; } return reinterpret_cast(RVA_TO_ADDR(baseAddress, value)); } 71 | template 72 | FORCEINLINE void To(PVOID baseAddress, T& value) const { value = To(baseAddress); } 73 | template 74 | static FORCEINLINE auto From(T baseAddress, T targetAddress) { return OffsetStorage{ LONGLONG(targetAddress) - LONGLONG(baseAddress) }; } 75 | static FORCEINLINE auto From(PVOID baseAddress, PVOID targetAddress) { if (!baseAddress || !targetAddress) { return OffsetStorage{ 0 }; } return OffsetStorage{ reinterpret_cast(targetAddress) - reinterpret_cast(baseAddress) }; } 76 | }; 77 | 78 | namespace Detours 79 | { 80 | // Call single or multiple Attach/Detach in the callback 81 | HRESULT Write(const std::function&& callback); 82 | // Install an inline hook using Detours 83 | void Attach(PVOID* realFuncAddr, PVOID hookFuncAddr) noexcept(false); 84 | // Uninstall an inline hook using Detours 85 | void Detach(PVOID* realFuncAddr, PVOID hookFuncAddr) noexcept(false); 86 | 87 | template 88 | FORCEINLINE void Attach(T* org, T detour) 89 | { 90 | Attach(reinterpret_cast(org), reinterpret_cast(detour)); 91 | } 92 | template 93 | FORCEINLINE void Detach(T* org, T detour) 94 | { 95 | Detach(reinterpret_cast(org), reinterpret_cast(detour)); 96 | } 97 | } 98 | } 99 | -------------------------------------------------------------------------------- /OpenGlass/GlassRealizer.cpp: -------------------------------------------------------------------------------- 1 | #include "pch.h" 2 | #include "Util.hpp" 3 | #include "uDWMProjection.hpp" 4 | #include "GlassRealizer.hpp" 5 | #include "AeroEffect.hpp" 6 | #include "BlurEffect.hpp" 7 | #include "Shared.hpp" 8 | 9 | using namespace OpenGlass; 10 | 11 | bool CGlassRealizer::EnsureGlassEffect(Shared::GlassType type) 12 | { 13 | if (m_glassType != type) 14 | { 15 | m_glassType = type; 16 | switch (m_glassType) 17 | { 18 | case Shared::GlassType::Blur: 19 | { 20 | m_glassEffect = winrt::make(); 21 | break; 22 | } 23 | case Shared::GlassType::Aero: 24 | { 25 | m_glassEffect = winrt::make(); 26 | break; 27 | } 28 | default: 29 | m_glassEffect = nullptr; 30 | break; 31 | } 32 | } 33 | if (!m_glassEffect) 34 | { 35 | return false; 36 | } 37 | 38 | return true; 39 | } 40 | 41 | HRESULT CGlassRealizer::Render( 42 | ID2D1DeviceContext* context, 43 | const CGlassInput& input 44 | ) 45 | { 46 | if (!EnsureGlassEffect(Shared::g_type)) 47 | { 48 | return S_OK; 49 | } 50 | 51 | const auto renderTargetBitmap = Util::GetTargetBitmapFromDeviceContext(context); 52 | if (!renderTargetBitmap) 53 | { 54 | return S_OK; 55 | } 56 | 57 | const D2D1_RECT_F alignedSamplingWorldBounds 58 | { 59 | std::floor(input.samplingWorldBoundsShapeClipped->left), 60 | std::floor(input.samplingWorldBoundsShapeClipped->top), 61 | std::ceil(input.samplingWorldBoundsShapeClipped->right), 62 | std::ceil(input.samplingWorldBoundsShapeClipped->bottom) 63 | }; 64 | const D2D1_RECT_F alignedDrawingWorldBounds 65 | { 66 | std::floor(input.drawingWorldBounds->left), 67 | std::floor(input.drawingWorldBounds->top), 68 | std::ceil(input.drawingWorldBounds->right), 69 | std::ceil(input.drawingWorldBounds->bottom) 70 | }; 71 | 72 | winrt::com_ptr compositorDeviceContext{}; 73 | winrt::com_ptr sharedAtlasBitmap{}; 74 | 75 | if ( 76 | const auto bitmapProperties = D2D1::BitmapProperties1( 77 | renderTargetBitmap->GetOptions(), 78 | renderTargetBitmap->GetPixelFormat() 79 | ); 80 | input.zeroCopyOptimization && 81 | SUCCEEDED(context->QueryInterface(compositorDeviceContext.put())) 82 | ) 83 | { 84 | LOG_IF_FAILED( 85 | compositorDeviceContext->CreateSharedAtlasBitmap( 86 | renderTargetBitmap.get(), 87 | &bitmapProperties, 88 | sharedAtlasBitmap.put() 89 | ) 90 | ); 91 | } 92 | 93 | const auto buffer = input.buffer; 94 | if (!sharedAtlasBitmap) 95 | { 96 | buffer->Reserve(renderTargetBitmap->GetPixelSize()); 97 | RETURN_IF_FAILED( 98 | buffer->CopyFrom( 99 | context, 100 | D2D1::Point2U( 101 | static_cast(alignedSamplingWorldBounds.left), 102 | static_cast(alignedSamplingWorldBounds.top) 103 | ), 104 | renderTargetBitmap.get(), 105 | D2D1::RectU( 106 | static_cast(alignedSamplingWorldBounds.left), 107 | static_cast(alignedSamplingWorldBounds.top), 108 | static_cast(alignedSamplingWorldBounds.right), 109 | static_cast(alignedSamplingWorldBounds.bottom) 110 | ) 111 | ) 112 | ); 113 | } 114 | 115 | const auto cleanupCustomEffect = wil::scope_exit([this] 116 | { 117 | m_glassEffect->Reset(); 118 | }); 119 | 120 | RETURN_IF_FAILED( 121 | m_glassEffect->Build( 122 | context, 123 | sharedAtlasBitmap ? sharedAtlasBitmap.get() : buffer->GetCompatibleD2DBitmap(context, renderTargetBitmap.get()), 124 | alignedSamplingWorldBounds, 125 | static_cast(&input.params) 126 | ) 127 | ); 128 | winrt::com_ptr outputImage{}; 129 | m_glassEffect->GetOutput(outputImage.put()); 130 | 131 | RETURN_HR_IF_NULL(D2DERR_UNSUPPORTED_PIXEL_FORMAT, outputImage); 132 | 133 | D2D1_MATRIX_3X2_F originalMatrix, outputMatrix = m_glassEffect->GetOutputMatrix(); 134 | context->GetTransform(&originalMatrix); 135 | context->SetTransform(outputMatrix); 136 | 137 | D2D1InvertMatrix(&outputMatrix); 138 | 139 | const auto offset = m_glassEffect->GetOutputOffset(); 140 | for (auto subRectangle : input.rectangles) 141 | { 142 | if (RectF::IntersectUnsafe(subRectangle, alignedDrawingWorldBounds)) 143 | { 144 | auto transformedSubRectangle = RectF::TransformRect(subRectangle, outputMatrix); 145 | 146 | context->DrawImage( 147 | outputImage.get(), 148 | D2D1::Point2F( 149 | transformedSubRectangle.left, 150 | transformedSubRectangle.top 151 | ), 152 | D2D1::RectF( 153 | transformedSubRectangle.left + offset.x, 154 | transformedSubRectangle.top + offset.y, 155 | transformedSubRectangle.right + offset.x, 156 | transformedSubRectangle.bottom + offset.y 157 | ), 158 | D2D1_INTERPOLATION_MODE_LINEAR, 159 | D2D1_COMPOSITE_MODE_BOUNDED_SOURCE_COPY 160 | ); 161 | } 162 | } 163 | 164 | context->SetTransform(originalMatrix); 165 | 166 | return S_OK; 167 | } 168 | -------------------------------------------------------------------------------- /OpenGlass/GlassCoverageSet.cpp: -------------------------------------------------------------------------------- 1 | #include "pch.h" 2 | #include "GlassCoverageSet.hpp" 3 | 4 | using namespace OpenGlass; 5 | namespace OpenGlass::GlassCoverageSetFactory 6 | { 7 | std::unordered_map> g_glassCoverageSetMap{}; 8 | 9 | class CArrayBasedGlassCoverageSet : public winrt::implements 10 | { 11 | DWM::MyDynArrayImpl m_array{}; 12 | public: 13 | void STDMETHODCALLTYPE SetDeviceTransform(const dwmcore::CMILMatrix* matrix) override; 14 | HRESULT STDMETHODCALLTYPE Add( 15 | const D2D1_RECT_F& coverage, 16 | int depth, 17 | const dwmcore::CMILMatrix* matrix 18 | ) override; 19 | void STDMETHODCALLTYPE Clear() override { m_array.Clear(); } 20 | std::span STDMETHODCALLTYPE GetViews() const override { return m_array.views(); } 21 | bool STDMETHODCALLTYPE IsFullyCovered( 22 | const D2D1_RECT_F& coverage, 23 | int depth 24 | ) const override; 25 | bool STDMETHODCALLTYPE IsPartiallyCovered( 26 | const D2D1_RECT_F& coverage, 27 | int depth 28 | ) const override; 29 | bool STDMETHODCALLTYPE IsVisible( 30 | const D2D1_RECT_F& coverage, 31 | const dwmcore::CArrayBasedCoverageSet* occlusionCoverageSet 32 | ) const override; 33 | }; 34 | } 35 | 36 | void STDMETHODCALLTYPE GlassCoverageSetFactory::CArrayBasedGlassCoverageSet::SetDeviceTransform(const dwmcore::CMILMatrix* matrix) 37 | { 38 | for (auto& zorderedRect : m_array.views()) 39 | { 40 | zorderedRect.UpdateDeviceRect(matrix); 41 | } 42 | } 43 | HRESULT STDMETHODCALLTYPE GlassCoverageSetFactory::CArrayBasedGlassCoverageSet::Add( 44 | const D2D1_RECT_F& coverage, 45 | int depth, 46 | const dwmcore::CMILMatrix* matrix 47 | ) 48 | { 49 | m_array.AddInPlace(coverage, depth, matrix); 50 | return S_OK; 51 | } 52 | 53 | bool STDMETHODCALLTYPE GlassCoverageSetFactory::CArrayBasedGlassCoverageSet::IsFullyCovered( 54 | const D2D1_RECT_F& coverage, 55 | int depth 56 | ) const 57 | { 58 | for (const auto& zorderedRect : m_array.views()) 59 | { 60 | if (zorderedRect.m_depth >= depth) 61 | { 62 | break; 63 | } 64 | 65 | if ( 66 | !wil::rect_is_empty(zorderedRect.m_transformedRect) && 67 | std::abs(wil::rect_height(zorderedRect.m_transformedRect) * wil::rect_width(zorderedRect.m_transformedRect)) > 1.f && 68 | 69 | coverage.left >= zorderedRect.m_transformedRect.left && 70 | coverage.top >= zorderedRect.m_transformedRect.top && 71 | coverage.right <= zorderedRect.m_transformedRect.right && 72 | coverage.bottom <= zorderedRect.m_transformedRect.bottom 73 | ) 74 | { 75 | return true; 76 | } 77 | } 78 | 79 | return false; 80 | } 81 | 82 | bool STDMETHODCALLTYPE GlassCoverageSetFactory::CArrayBasedGlassCoverageSet::IsPartiallyCovered( 83 | const D2D1_RECT_F& coverage, 84 | int depth 85 | ) const 86 | { 87 | for (const auto& zorderedRect : m_array.views()) 88 | { 89 | if (zorderedRect.m_depth >= depth) 90 | { 91 | break; 92 | } 93 | 94 | if ( 95 | !wil::rect_is_empty(zorderedRect.m_transformedRect) && 96 | std::abs(wil::rect_height(zorderedRect.m_transformedRect) * wil::rect_width(zorderedRect.m_transformedRect)) > 1.f && 97 | 98 | RectF::DoesIntersectUnsafe(zorderedRect.m_transformedRect, coverage) 99 | ) 100 | { 101 | return true; 102 | } 103 | } 104 | 105 | return false; 106 | } 107 | 108 | bool STDMETHODCALLTYPE GlassCoverageSetFactory::CArrayBasedGlassCoverageSet::IsVisible( 109 | const D2D1_RECT_F& coverage, 110 | const dwmcore::CArrayBasedCoverageSet* occlusionCoverageSet 111 | ) const 112 | { 113 | for (const auto& zorderedRect : m_array.views()) 114 | { 115 | if ( 116 | D2D1_RECT_F intersectedRect = zorderedRect.m_transformedRect; 117 | !wil::rect_is_empty(zorderedRect.m_transformedRect) && 118 | std::abs(wil::rect_height(zorderedRect.m_transformedRect) * wil::rect_width(zorderedRect.m_transformedRect)) > 1.f && 119 | 120 | RectF::IntersectUnsafe(intersectedRect, coverage) && 121 | !occlusionCoverageSet->IsCovered(intersectedRect, zorderedRect.m_depth) 122 | ) 123 | { 124 | return true; 125 | } 126 | } 127 | 128 | return false; 129 | } 130 | 131 | winrt::com_ptr GlassCoverageSetFactory::GetOrCreate(dwmcore::COcclusionContext* occlusionContext, bool createIfNecessary) 132 | { 133 | auto it = g_glassCoverageSetMap.find(occlusionContext); 134 | 135 | if (createIfNecessary) 136 | { 137 | if (it == g_glassCoverageSetMap.end()) 138 | { 139 | auto result = g_glassCoverageSetMap.emplace(occlusionContext, winrt::make()); 140 | if (result.second == true) 141 | { 142 | it = result.first; 143 | } 144 | } 145 | } 146 | 147 | return it == g_glassCoverageSetMap.end() ? nullptr : it->second; 148 | } 149 | void GlassCoverageSetFactory::Remove(dwmcore::COcclusionContext* occlusionContext) 150 | { 151 | auto it = g_glassCoverageSetMap.find(occlusionContext); 152 | 153 | if (it != g_glassCoverageSetMap.end()) 154 | { 155 | g_glassCoverageSetMap.erase(it); 156 | } 157 | } 158 | void GlassCoverageSetFactory::Shutdown() 159 | { 160 | g_glassCoverageSetMap.clear(); 161 | } 162 | -------------------------------------------------------------------------------- /OpenGlass/Dwm.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "framework.hpp" 3 | #include "cpprt.hpp" 4 | 5 | namespace OpenGlass::DWM 6 | { 7 | // actually gsl::span 8 | template 9 | struct span 10 | { 11 | size_t length; 12 | T* data; 13 | 14 | auto views() const 15 | { 16 | return std::span(data, length); 17 | } 18 | }; 19 | 20 | template 21 | struct DynArray 22 | { 23 | T* data; 24 | T* buffer; 25 | UINT bufferCapacity; 26 | UINT capacity; 27 | UINT size; 28 | 29 | auto views() const 30 | { 31 | return std::span(data, size); 32 | } 33 | }; 34 | 35 | template 36 | struct MyDynArrayImpl : DynArray 37 | { 38 | [[nodiscard]] void* operator new[]( 39 | size_t size 40 | ) 41 | { 42 | auto memory = HeapAlloc(OpenGlass::Util::g_processHeap, 0, size); 43 | THROW_LAST_ERROR_IF_NULL(memory); 44 | return memory; 45 | } 46 | void operator delete[]( 47 | void* ptr 48 | ) noexcept 49 | { 50 | FAIL_FAST_IF_NULL(ptr); 51 | HeapFree(OpenGlass::Util::g_processHeap, 0, ptr); 52 | } 53 | 54 | MyDynArrayImpl() 55 | { 56 | this->capacity = 8; 57 | this->data = new T[this->capacity]; 58 | this->size = 0; 59 | } 60 | ~MyDynArrayImpl() 61 | { 62 | delete[] this->data; 63 | this->data = nullptr; 64 | this->capacity = this->size = 0; 65 | } 66 | 67 | void Clear() 68 | { 69 | if (this->size != 0) 70 | { 71 | this->capacity = 8; 72 | delete[] this->data; 73 | this->data = new T[this->capacity]; 74 | this->size = 0; 75 | } 76 | } 77 | void Add(const T& object) 78 | { 79 | auto newSize = this->size + 1u; 80 | if (newSize < this->size) 81 | { 82 | FAIL_FAST_HR(static_cast(0x80070216ul)); 83 | } 84 | else 85 | { 86 | auto bufferSize = this->size * sizeof(T); 87 | if (newSize > this->capacity) 88 | { 89 | auto tmp = std::unique_ptr(this->data); 90 | 91 | this->capacity *= 2; 92 | this->data = new T[this->capacity]; 93 | memcpy_s(this->data, bufferSize, tmp.get(), bufferSize); 94 | } 95 | 96 | *reinterpret_cast(reinterpret_cast(this->data) + bufferSize) = object; 97 | this->size = newSize; 98 | } 99 | } 100 | template 101 | void AddInPlace(Args&&... args) 102 | { 103 | auto newSize = this->size + 1u; 104 | if (newSize < this->size) 105 | { 106 | FAIL_FAST_HR(static_cast(0x80070216ul)); 107 | } 108 | else 109 | { 110 | auto bufferSize = this->size * sizeof(T); 111 | if (newSize > this->capacity) 112 | { 113 | auto tmp = std::unique_ptr(this->data); 114 | 115 | this->capacity *= 2; 116 | this->data = new T[this->capacity]; 117 | memcpy_s(this->data, bufferSize, tmp.get(), bufferSize); 118 | } 119 | 120 | *reinterpret_cast(reinterpret_cast(this->data) + bufferSize) = T{ std::forward(args)... }; 121 | this->size = newSize; 122 | } 123 | } 124 | }; 125 | 126 | struct MilPoint2D 127 | { 128 | double x; 129 | double y; 130 | }; 131 | struct MilRectF 132 | { 133 | float x; 134 | float y; 135 | float width; 136 | float height; 137 | }; 138 | struct MilRectD 139 | { 140 | double left; 141 | double top; 142 | double right; 143 | double bottom; 144 | }; 145 | struct MilSizeD 146 | { 147 | double width; 148 | double height; 149 | }; 150 | enum MIL_RESOURCE_TYPE : UINT {}; 151 | enum class MilBrushMappingMode 152 | { 153 | Absolute, 154 | RelativeToBoundingBox 155 | }; 156 | enum class MilBitmapInterpolationMode 157 | { 158 | NearestNeighbor, 159 | Linear, 160 | Cubic, 161 | Fant, 162 | TriLinear, 163 | Anisotropic, 164 | SuperSample 165 | }; 166 | enum class MilStretch 167 | { 168 | None, 169 | Fill, 170 | Uniform, 171 | UniformToFill 172 | }; 173 | enum class MilTileMode 174 | { 175 | Extend 176 | }; 177 | enum class MilHorizontalAlignment 178 | { 179 | Left, 180 | Center, 181 | Right 182 | }; 183 | enum class MilVerticalAlignment 184 | { 185 | Top, 186 | Center, 187 | Bottom 188 | }; 189 | struct MilColorTransform 190 | { 191 | union 192 | #pragma warning(suppress : 4201) 193 | { 194 | struct 195 | #pragma warning(suppress : 4201) 196 | { 197 | FLOAT _11, _12, _13, _14, _15; 198 | FLOAT _21, _22, _23, _24, _25; 199 | FLOAT _31, _32, _33, _34, _35; 200 | FLOAT _41, _42, _43, _44, _45; 201 | FLOAT _51, _52, _53, _54, _55; 202 | } DUMMYSTRUCTNAME; 203 | 204 | FLOAT m[5][5]; 205 | } DUMMYUNIONNAME; 206 | }; 207 | using MilTransform = D2D1_MATRIX_3X2_F; 208 | using MilTransform3D = D2D1_MATRIX_4X3_F; 209 | 210 | using HMIL_CONNECTION = HANDLE; 211 | struct IDwmChannel {}; 212 | struct IDwmWindow {}; 213 | // since windows 11 24h2 214 | struct IDwmChannelProvider : IUnknown 215 | { 216 | virtual HRESULT STDMETHODCALLTYPE CreateMilResource(MIL_RESOURCE_TYPE, UINT*, IUnknown**) = 0; 217 | virtual HRESULT STDMETHODCALLTYPE CreateSharedMilResource(MIL_RESOURCE_TYPE, UINT*, void**, IUnknown**) = 0; 218 | virtual HRESULT STDMETHODCALLTYPE DuplicateSharedMilResource(void*, MIL_RESOURCE_TYPE, bool, UINT*, IUnknown**) = 0; 219 | virtual UINT STDMETHODCALLTYPE GetChannelHandle(void) = 0; 220 | virtual void STDMETHODCALLTYPE Lock(void) = 0; 221 | virtual void STDMETHODCALLTYPE ReleaseMilResource(IUnknown*) = 0; 222 | virtual HRESULT STDMETHODCALLTYPE InternalCommit(void*) = 0; 223 | virtual void STDMETHODCALLTYPE Unlock(void) = 0; 224 | }; 225 | } -------------------------------------------------------------------------------- /OpenGlass/ButtonGlowHandler.cpp: -------------------------------------------------------------------------------- 1 | #include "pch.h" 2 | #include "ButtonGlowHandler.hpp" 3 | 4 | using namespace OpenGlass; 5 | namespace OpenGlass::ButtonGlowHandler 6 | { 7 | constexpr int MARGIN_OFFSET = 0x30; //offset is the same as w7, so it shouldnt change 8 | 9 | /* 10 | * https://imgur.com/a/kHFLBON 11 | * To find these offsets, look in CTopLevelWindow::UpdateButtonVisuals in uDWM.dll 12 | * where offset can be found inside, used to get the image to pass into CButton::SetVisualStates 13 | * there will be many calls, but they all get at the same 2 offset, which correspond to these 14 | */ 15 | constexpr int MINMAXBUTTONGLOWIMAGE = 0xD0; 16 | constexpr int CLOSEBUTTONGLOWIMAGE = 0xC8; 17 | 18 | static int MINMAXBUTTONGLOW = 93; //16 in windows 7 19 | static int CLOSEBUTTONGLOW = 92; //11 in windows 7 20 | static int TOOLCLOSEBUTTONGLOW = 94; //47 in windows 7 21 | 22 | bool UpdateCrossfade{ false }; 23 | 24 | void STDMETHODCALLTYPE CVisual_SetDirtyFlags_hook(uDWM::CVisual* This, int flags); 25 | void STDMETHODCALLTYPE CButton_UpdateCrossfade_hook(uDWM::CButton* This); 26 | 27 | decltype(&CVisual_SetDirtyFlags_hook) CVisual_SetDirtyFlags_orig{ nullptr }; 28 | decltype(&CButton_UpdateCrossfade_hook) CButton_UpdateCrossfade_orig{ nullptr }; 29 | 30 | 31 | HRESULT(WINAPI* CTopLevelWindow__CreateBitmapFromAtlas)(HTHEME hTheme, int iPartId, MARGINS* outMargins, void** outBitmapSource); 32 | 33 | void STDMETHODCALLTYPE CButton_UpdateCrossfade_hook(uDWM::CButton* This) 34 | { 35 | UpdateCrossfade = true; 36 | CButton_UpdateCrossfade_orig(This); 37 | UpdateCrossfade = false; 38 | } 39 | 40 | void STDMETHODCALLTYPE CVisual_SetDirtyFlags_hook(uDWM::CVisual* This, int flags) 41 | { 42 | // workaround for button glow cutoff 43 | if (UpdateCrossfade) 44 | { 45 | uDWM::CButton* button = reinterpret_cast(This); 46 | if (flags == 0x8000 && *button->GetButtonState() == 3) 47 | { 48 | return; 49 | } 50 | } 51 | 52 | CVisual_SetDirtyFlags_orig(This, flags); 53 | } 54 | 55 | //not 1 to 1 to the one in windows 7 udwm, however it achieves the same outcome whilst being simpler 56 | HRESULT CTopLevelWindow__CreateButtonGlowsFromAtlas(HTHEME hTheme) 57 | { 58 | MARGINS margins{}; 59 | void* OutBitmapSourceBlue = nullptr; 60 | void* OutBitmapSourceRed = nullptr; 61 | void* OutBitmapSourceTool = nullptr; 62 | 63 | RETURN_IF_FAILED(CTopLevelWindow__CreateBitmapFromAtlas(hTheme, MINMAXBUTTONGLOW, &margins, &OutBitmapSourceBlue)); 64 | *(MARGINS*)(__int64(OutBitmapSourceBlue) + MARGIN_OFFSET) = margins; 65 | 66 | RETURN_IF_FAILED(CTopLevelWindow__CreateBitmapFromAtlas(hTheme, CLOSEBUTTONGLOW, &margins, &OutBitmapSourceRed)); 67 | *(MARGINS*)(__int64(OutBitmapSourceRed) + MARGIN_OFFSET) = margins; 68 | 69 | RETURN_IF_FAILED(CTopLevelWindow__CreateBitmapFromAtlas(hTheme, TOOLCLOSEBUTTONGLOW, &margins, &OutBitmapSourceTool)); 70 | *(MARGINS*)(__int64(OutBitmapSourceTool) + MARGIN_OFFSET) = margins; 71 | 72 | for (int i = 0; i < 4; ++i) 73 | { 74 | auto frame = uDWM::CTopLevelWindow::GetWindowFrames()[i]; 75 | *(void**)(__int64(frame) + MINMAXBUTTONGLOWIMAGE) = OutBitmapSourceBlue; 76 | *(void**)(__int64(frame) + CLOSEBUTTONGLOWIMAGE) = OutBitmapSourceRed; 77 | } 78 | for (int i = 4; i < 6; ++i) 79 | { 80 | auto frame = uDWM::CTopLevelWindow::GetWindowFrames()[i]; 81 | *(void**)(__int64(frame) + MINMAXBUTTONGLOWIMAGE) = OutBitmapSourceTool; 82 | *(void**)(__int64(frame) + CLOSEBUTTONGLOWIMAGE) = OutBitmapSourceTool; 83 | } 84 | return S_OK; 85 | } 86 | 87 | HRESULT (WINAPI* CTopLevelWindow_CreateGlyphsFromAtlas)(HTHEME hTheme); 88 | HRESULT WINAPI CTopLevelWindow_CreateGlyphsFromAtlas_Hook(HTHEME hTheme) 89 | { 90 | CTopLevelWindow__CreateButtonGlowsFromAtlas(hTheme); 91 | return CTopLevelWindow_CreateGlyphsFromAtlas(hTheme); 92 | } 93 | 94 | void Update([[maybe_unused]] GlassEngine::UpdateType type) 95 | { 96 | MINMAXBUTTONGLOW = GlassEngine::GetDwordFromRegistry(L"MINMAXBUTTONGLOWid", 93); 97 | CLOSEBUTTONGLOW = GlassEngine::GetDwordFromRegistry(L"CLOSEBUTTONGLOWid", 92); 98 | TOOLCLOSEBUTTONGLOW = GlassEngine::GetDwordFromRegistry(L"TOOLCLOSEBUTTONGLOWid", 94); 99 | } 100 | 101 | void Startup() 102 | { 103 | if (uDWM::g_versionInfo.build < os::build_w11_21h2) 104 | { 105 | uDWM::g_projectionArray.ApplyToVariable("CVisual::SetDirtyFlags", CVisual_SetDirtyFlags_orig); 106 | uDWM::g_projectionArray.ApplyToVariable("CTopLevelWindow::CreateBitmapFromAtlas", CTopLevelWindow__CreateBitmapFromAtlas); 107 | uDWM::g_projectionArray.ApplyToVariable("CTopLevelWindow::CreateGlyphsFromAtlas", CTopLevelWindow_CreateGlyphsFromAtlas); 108 | uDWM::g_projectionArray.ApplyToVariable("CButton::UpdateCrossfade", CButton_UpdateCrossfade_orig); 109 | 110 | THROW_IF_FAILED( 111 | HookHelper::Detours::Write([]() static 112 | { 113 | HookHelper::Detours::Attach(&CVisual_SetDirtyFlags_orig, CVisual_SetDirtyFlags_hook); 114 | HookHelper::Detours::Attach(&CTopLevelWindow_CreateGlyphsFromAtlas, CTopLevelWindow_CreateGlyphsFromAtlas_Hook); 115 | HookHelper::Detours::Attach(&CButton_UpdateCrossfade_orig, CButton_UpdateCrossfade_hook); 116 | }) 117 | ); 118 | } 119 | } 120 | 121 | void Shutdown() 122 | { 123 | if (uDWM::g_versionInfo.build < os::build_w11_21h2) 124 | { 125 | THROW_IF_FAILED( 126 | HookHelper::Detours::Write([]() static 127 | { 128 | HookHelper::Detours::Detach(&CVisual_SetDirtyFlags_orig, CVisual_SetDirtyFlags_hook); 129 | HookHelper::Detours::Detach(&CTopLevelWindow_CreateGlyphsFromAtlas, CTopLevelWindow_CreateGlyphsFromAtlas_Hook); 130 | HookHelper::Detours::Detach(&CButton_UpdateCrossfade_orig, CButton_UpdateCrossfade_hook); 131 | }) 132 | ); 133 | } 134 | } 135 | } 136 | -------------------------------------------------------------------------------- /OpenGlass/OSHelper.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "framework.hpp" 3 | #pragma warning(push) 4 | #pragma warning(disable : 4201) 5 | 6 | namespace OpenGlass::os 7 | { 8 | struct KSYSTEM_TIME 9 | { 10 | ULONG LowPart; 11 | LONG High1Time; 12 | LONG High2Time; 13 | }; 14 | enum class NT_PRODUCT_TYPE 15 | { 16 | NtProductWinNt = 1, 17 | NtProductLanManNt, 18 | NtProductServer 19 | }; 20 | enum class ALTERNATIVE_ARCHITECTURE_TYPE 21 | { 22 | StandardDesign, 23 | NEC98x86, 24 | EndAlternatives 25 | }; 26 | constexpr UINT PROCESSOR_FEATURE_MAX = 64; 27 | struct KUSER_SHARED_DATA 28 | { 29 | ULONG TickCountLowDeprecated; 30 | ULONG TickCountMultiplier; 31 | KSYSTEM_TIME InterruptTime; 32 | KSYSTEM_TIME SystemTime; 33 | KSYSTEM_TIME TimeZoneBias; 34 | USHORT ImageNumberLow; 35 | USHORT ImageNumberHigh; 36 | WCHAR NtSystemRoot[260]; 37 | ULONG MaxStackTraceDepth; 38 | ULONG CryptoExponent; 39 | ULONG TimeZoneId; 40 | ULONG LargePageMinimum; 41 | ULONG AitSamplingValue; 42 | ULONG AppCompatFlag; 43 | ULONGLONG RNGSeedVersion; 44 | ULONG GlobalValidationRunlevel; 45 | LONG TimeZoneBiasStamp; 46 | ULONG NtBuildNumber; 47 | NT_PRODUCT_TYPE NtProductType; 48 | BOOLEAN ProductTypeIsValid; 49 | BOOLEAN Reserved0[1]; 50 | USHORT NativeProcessorArchitecture; 51 | ULONG NtMajorVersion; 52 | ULONG NtMinorVersion; 53 | BOOLEAN ProcessorFeatures[PROCESSOR_FEATURE_MAX]; 54 | ULONG Reserved1; 55 | ULONG Reserved3; 56 | ULONG TimeSlip; 57 | ALTERNATIVE_ARCHITECTURE_TYPE AlternativeArchitecture; 58 | ULONG BootId; 59 | LARGE_INTEGER SystemExpirationDate; 60 | ULONG SuiteMask; 61 | BOOLEAN KdDebuggerEnabled; 62 | union 63 | { 64 | UCHAR MitigationPolicies; 65 | struct 66 | { 67 | UCHAR NXSupportPolicy : 2; 68 | UCHAR SEHValidationPolicy : 2; 69 | UCHAR CurDirDevicesSkippedForDlls : 2; 70 | UCHAR Reserved : 2; 71 | }; 72 | }; 73 | USHORT CyclesPerYield; 74 | ULONG ActiveConsoleId; 75 | ULONG DismountCount; 76 | ULONG ComPlusPackage; 77 | ULONG LastSystemRITEventTickCount; 78 | ULONG NumberOfPhysicalPages; 79 | BOOLEAN SafeBootMode; 80 | union 81 | { 82 | UCHAR VirtualizationFlags; 83 | struct 84 | { 85 | UCHAR ArchStartedInEl2 : 1; 86 | UCHAR QcSlIsSupported : 1; 87 | }; 88 | }; 89 | UCHAR Reserved12[2]; 90 | union 91 | { 92 | ULONG SharedDataFlags; 93 | struct 94 | { 95 | ULONG DbgErrorPortPresent : 1; 96 | ULONG DbgElevationEnabled : 1; 97 | ULONG DbgVirtEnabled : 1; 98 | ULONG DbgInstallerDetectEnabled : 1; 99 | ULONG DbgLkgEnabled : 1; 100 | ULONG DbgDynProcessorEnabled : 1; 101 | ULONG DbgConsoleBrokerEnabled : 1; 102 | ULONG DbgSecureBootEnabled : 1; 103 | ULONG DbgMultiSessionSku : 1; 104 | ULONG DbgMultiUsersInSessionSku : 1; 105 | ULONG DbgStateSeparationEnabled : 1; 106 | ULONG SpareBits : 21; 107 | } DUMMYSTRUCTNAME2; 108 | } DUMMYUNIONNAME2; 109 | ULONG DataFlagsPad[1]; 110 | ULONGLONG TestRetInstruction; 111 | LONGLONG QpcFrequency; 112 | ULONG SystemCall; 113 | ULONG Reserved2; 114 | ULONGLONG SystemCallPad[2]; 115 | union 116 | { 117 | KSYSTEM_TIME TickCount; 118 | ULONG64 TickCountQuad; 119 | struct 120 | { 121 | ULONG ReservedTickCountOverlay[3]; 122 | ULONG TickCountPad[1]; 123 | } DUMMYSTRUCTNAME; 124 | } DUMMYUNIONNAME3; 125 | ULONG Cookie; 126 | ULONG CookiePad[1]; 127 | LONGLONG ConsoleSessionForegroundProcessId; 128 | ULONGLONG TimeUpdateLock; 129 | ULONGLONG BaselineSystemTimeQpc; 130 | ULONGLONG BaselineInterruptTimeQpc; 131 | ULONGLONG QpcSystemTimeIncrement; 132 | ULONGLONG QpcInterruptTimeIncrement; 133 | UCHAR QpcSystemTimeIncrementShift; 134 | UCHAR QpcInterruptTimeIncrementShift; 135 | USHORT UnparkedProcessorCount; 136 | ULONG EnclaveFeatureMask[4]; 137 | ULONG TelemetryCoverageRound; 138 | USHORT UserModeGlobalLogger[16]; 139 | ULONG ImageFileExecutionOptions; 140 | ULONG LangGenerationCount; 141 | ULONGLONG Reserved4; 142 | ULONGLONG InterruptTimeBias; 143 | ULONGLONG QpcBias; 144 | ULONG ActiveProcessorCount; 145 | UCHAR ActiveGroupCount; 146 | UCHAR Reserved9; 147 | union 148 | { 149 | USHORT QpcData; 150 | struct 151 | { 152 | UCHAR QpcBypassEnabled; 153 | UCHAR QpcShift; 154 | }; 155 | }; 156 | LARGE_INTEGER TimeZoneBiasEffectiveStart; 157 | LARGE_INTEGER TimeZoneBiasEffectiveEnd; 158 | XSTATE_CONFIGURATION XState; 159 | KSYSTEM_TIME FeatureConfigurationChangeStamp; 160 | ULONG Spare; 161 | ULONG64 UserPointerAuthMask; 162 | }; 163 | using PKUSER_SHARED_DATA = KUSER_SHARED_DATA* const; 164 | 165 | FORCEINLINE PKUSER_SHARED_DATA GetKernelSharedInfo() 166 | { 167 | return reinterpret_cast(0x7FFE0000); 168 | } 169 | 170 | inline const ULONG buildNumber{ GetKernelSharedInfo()->NtBuildNumber }; 171 | inline const ULONG minorVersion{ GetKernelSharedInfo()->NtMinorVersion }; 172 | inline const ULONG majorVersion{ GetKernelSharedInfo()->NtMajorVersion }; 173 | inline const NT_PRODUCT_TYPE productType{ GetKernelSharedInfo()->NtProductType }; 174 | 175 | enum os_build : ULONG 176 | { 177 | build_w10_1507 = 10240, 178 | build_w10_1511 = 10586, 179 | build_w10_1607 = 14393, 180 | build_w10_1703 = 15063, 181 | build_w10_1709 = 16299, 182 | build_w10_1803 = 17134, 183 | build_w10_1809 = 17763, 184 | build_w10_1903 = 18362, 185 | build_w10_1909 = 18363, 186 | build_w10_2004 = 19041, 187 | build_w10_20h2 = 19042, 188 | build_w10_21h1 = 19043, 189 | build_w10_21h2 = 19044, 190 | build_w10_22h2 = 19045, 191 | build_w11_21h2 = 22000, 192 | build_w11_22h2 = 22621, 193 | build_w11_23h2 = 22631, 194 | build_w11_24h2 = 26100, 195 | build_w11_25h2 = 26200, 196 | }; 197 | enum os_revision : ULONG 198 | { 199 | revision_24h2_rtm_1 = 2454, 200 | revision_24h2_with_25h2_code_staged = 4484 201 | }; 202 | } 203 | 204 | #pragma warning(pop) 205 | -------------------------------------------------------------------------------- /OpenGlass/AccentOverrider.cpp: -------------------------------------------------------------------------------- 1 | #include "pch.h" 2 | #include "AccentOverrider.hpp" 3 | #include "GlassKernel.hpp" 4 | #include "uDWMProjection.hpp" 5 | #include "Shared.hpp" 6 | #include "GlassReflectionBrush.hpp" 7 | 8 | using namespace OpenGlass; 9 | namespace OpenGlass::AccentOverrider 10 | { 11 | HRESULT STDMETHODCALLTYPE MyCAccent_UpdateAccentPolicy( 12 | uDWM::CAccent* This, 13 | LPCRECT rect, 14 | uDWM::ACCENT_POLICY* policy, 15 | uDWM::CBaseGeometryProxy* geometry 16 | ); 17 | HRESULT STDMETHODCALLTYPE MyCAccent__UpdateSolidFill( 18 | uDWM::CAccent* This, 19 | uDWM::CRenderDataVisual* visual, 20 | UINT color, 21 | const D2D1_RECT_F& rect, 22 | float opacity 23 | ); 24 | bool STDMETHODCALLTYPE MyCAccentBlurBehind_IsBlurBehindDirty( 25 | uDWM::CAccentBlurBehind* This, 26 | const uDWM::CWindowData* data, 27 | LPCRECT rectangle, 28 | ULONG_PTR desktopId, 29 | HWND hwnd 30 | ); 31 | decltype(&MyCAccent_UpdateAccentPolicy) g_CAccent_UpdateAccentPolicy_Org{ nullptr }; 32 | decltype(&MyCAccent__UpdateSolidFill) g_CAccent__UpdateSolidFill_Org{ nullptr }; 33 | decltype(&MyCAccentBlurBehind_IsBlurBehindDirty) g_CAccentBlurBehind_IsBlurBehindDirty_Org{ nullptr }; 34 | 35 | bool g_disableGlassHooks{ false }; 36 | } 37 | 38 | HRESULT STDMETHODCALLTYPE AccentOverrider::MyCAccent_UpdateAccentPolicy( 39 | uDWM::CAccent* This, 40 | LPCRECT rect, 41 | uDWM::ACCENT_POLICY* policy, 42 | uDWM::CBaseGeometryProxy* geometry 43 | ) 44 | { 45 | if ( 46 | policy->AccentState != 1 && 47 | policy->AccentState != 3 && 48 | policy->AccentState != 4 49 | ) 50 | { 51 | return g_CAccent_UpdateAccentPolicy_Org(This, rect, policy, geometry); 52 | } 53 | 54 | HRESULT hr{ S_OK }; 55 | if (!Shared::g_overrideAccent) 56 | { 57 | hr = g_CAccent_UpdateAccentPolicy_Org(This, rect, policy, geometry); 58 | } 59 | else 60 | { 61 | auto accentPolicy = *policy; 62 | accentPolicy.AccentState = 1; 63 | accentPolicy.dwGradientColor = 0; 64 | hr = g_CAccent_UpdateAccentPolicy_Org(This, rect, &accentPolicy, geometry); 65 | } 66 | 67 | return hr; 68 | } 69 | HRESULT STDMETHODCALLTYPE AccentOverrider::MyCAccent__UpdateSolidFill( 70 | uDWM::CAccent* This, 71 | uDWM::CRenderDataVisual* visual, 72 | UINT color, 73 | const D2D1_RECT_F& rect, 74 | float opacity 75 | ) 76 | { 77 | if (!Shared::g_overrideAccent) 78 | { 79 | return g_CAccent__UpdateSolidFill_Org( 80 | This, 81 | visual, 82 | color, 83 | rect, 84 | opacity 85 | ); 86 | } 87 | 88 | RETURN_IF_FAILED(visual->ClearInstructions()); 89 | winrt::com_ptr geometry{ nullptr }; 90 | RETURN_IF_FAILED( 91 | uDWM::ResourceHelper::CreateGeometryFromHRGN( 92 | wil::unique_hrgn 93 | { 94 | CreateRectRgn( 95 | static_cast(rect.left), 96 | static_cast(rect.top), 97 | static_cast(rect.right), 98 | static_cast(rect.bottom) 99 | ) 100 | }.get(), 101 | geometry.put() 102 | ) 103 | ); 104 | 105 | const auto window = uDWM::TryGetWindowFromVisual(This); 106 | { 107 | winrt::com_ptr brush{ nullptr }; 108 | RETURN_IF_FAILED( 109 | uDWM::CDesktopManager::GetInstance()->GetCompositor()->CreateSolidColorLegacyMilBrushProxy( 110 | brush.put() 111 | ) 112 | ); 113 | 114 | const auto opaque = Shared::IsTransparencyDisabled(); 115 | auto glassColor = GlassKernel::RealizeWindowColorization( 116 | GlassKernel::GetBlendingBaseColor(opaque, false), 117 | GlassKernel::GetBlendingSourceColor(true), 118 | GlassKernel::GetColorizationBlendingOpacity(true, false), 119 | opaque, 120 | false 121 | ).effectiveBlendColor; 122 | glassColor.a = GlassKernel::AlphaChannelReinterpreter(true, false).ToFloat(); 123 | RETURN_IF_FAILED(brush->Update(1.0, glassColor)); 124 | winrt::com_ptr instruction{ nullptr }; 125 | RETURN_IF_FAILED( 126 | uDWM::CDrawGeometryInstruction::Create( 127 | brush.get(), 128 | geometry.get(), 129 | instruction.put() 130 | ) 131 | ); 132 | RETURN_IF_FAILED(visual->AddInstruction(instruction.get())); 133 | } 134 | 135 | if (window) 136 | { 137 | if ( 138 | const auto brush = GlassReflectionBrush::GetOrCreate( 139 | window, 140 | true 141 | ); 142 | brush 143 | ) 144 | { 145 | RETURN_IF_FAILED( 146 | brush->Update( 147 | (Shared::g_reflectionPolicy & Shared::ReflectionPolicy::NonClient) ? 148 | Shared::g_reflectionIntensity : 149 | 0.f, 150 | GlassReflectionBrush::CalculateTargetViewport( 151 | visual->GetLocalToParentVisualOffset(window->GetTransformParent()), 152 | Shared::g_reflectionParallaxIntensity, 153 | window->IsRTLMirrored(), 154 | visual->GetWidth(), 155 | visual->GetScale() 156 | ), 157 | D2D1::RectF(), 158 | nullptr, 159 | DWM::MilBrushMappingMode::Absolute, 160 | DWM::MilBrushMappingMode::Absolute, 161 | nullptr, 162 | nullptr, 163 | DWM::MilStretch::None, 164 | DWM::MilTileMode::Extend, 165 | DWM::MilHorizontalAlignment::Left, 166 | DWM::MilVerticalAlignment::Top, 167 | nullptr 168 | ) 169 | ); 170 | winrt::com_ptr instruction{ nullptr }; 171 | RETURN_IF_FAILED( 172 | uDWM::CDrawGeometryInstruction::Create( 173 | brush.get(), 174 | geometry.get(), 175 | instruction.put() 176 | ) 177 | ); 178 | RETURN_IF_FAILED(visual->AddInstruction(instruction.get())); 179 | } 180 | } 181 | return S_OK; 182 | } 183 | bool STDMETHODCALLTYPE AccentOverrider::MyCAccentBlurBehind_IsBlurBehindDirty( 184 | [[maybe_unused]] uDWM::CAccentBlurBehind* This, 185 | [[maybe_unused]] const uDWM::CWindowData* data, 186 | [[maybe_unused]] LPCRECT rectangle, 187 | [[maybe_unused]] ULONG_PTR desktopId, 188 | [[maybe_unused]] HWND hwnd 189 | ) 190 | { 191 | return false; 192 | } 193 | 194 | void AccentOverrider::Update(GlassEngine::UpdateType type) 195 | { 196 | if (type & GlassEngine::UpdateType::Backdrop) 197 | { 198 | Shared::g_overrideAccent = static_cast(GlassEngine::GetDwordFromRegistry(L"GlassOverrideAccent")); 199 | } 200 | } 201 | 202 | void AccentOverrider::Startup() 203 | { 204 | DWORD value{ 0ul }; 205 | wil::reg::get_value_dword_nothrow( 206 | GlassEngine::GetDwmLocalMachineKey(), 207 | L"DisabledHooks", 208 | &value 209 | ); 210 | g_disableGlassHooks = (value & 2) != 0; 211 | 212 | if (g_disableGlassHooks) 213 | { 214 | return; 215 | } 216 | 217 | uDWM::g_projectionArray.ApplyToVariable("CAccent::UpdateAccentPolicy", g_CAccent_UpdateAccentPolicy_Org); 218 | uDWM::g_projectionArray.ApplyToVariable("CAccent::_UpdateSolidFill", g_CAccent__UpdateSolidFill_Org); 219 | uDWM::g_projectionArray.ApplyToVariable("CAccentBlurBehind::IsBlurBehindDirty", g_CAccentBlurBehind_IsBlurBehindDirty_Org); 220 | 221 | THROW_IF_FAILED( 222 | HookHelper::Detours::Write([]() static 223 | { 224 | HookHelper::Detours::Attach(&g_CAccent_UpdateAccentPolicy_Org, MyCAccent_UpdateAccentPolicy); 225 | HookHelper::Detours::Attach(&g_CAccent__UpdateSolidFill_Org, MyCAccent__UpdateSolidFill); 226 | if (uDWM::g_versionInfo.build < os::build_w11_22h2) 227 | { 228 | HookHelper::Detours::Attach(&g_CAccentBlurBehind_IsBlurBehindDirty_Org, MyCAccentBlurBehind_IsBlurBehindDirty); 229 | } 230 | }) 231 | ); 232 | } 233 | 234 | void AccentOverrider::Shutdown() 235 | { 236 | if (g_disableGlassHooks) 237 | { 238 | return; 239 | } 240 | 241 | THROW_IF_FAILED( 242 | HookHelper::Detours::Write([]() static 243 | { 244 | HookHelper::Detours::Detach(&g_CAccent_UpdateAccentPolicy_Org, MyCAccent_UpdateAccentPolicy); 245 | HookHelper::Detours::Detach(&g_CAccent__UpdateSolidFill_Org, MyCAccent__UpdateSolidFill); 246 | if (uDWM::g_versionInfo.build < os::build_w11_22h2) 247 | { 248 | HookHelper::Detours::Detach(&g_CAccentBlurBehind_IsBlurBehindDirty_Org, MyCAccentBlurBehind_IsBlurBehindDirty); 249 | } 250 | }) 251 | ); 252 | } 253 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | ## Ignore Visual Studio temporary files, build results, and 2 | ## files generated by popular Visual Studio add-ons. 3 | ## 4 | ## Get latest from https://github.com/github/gitignore/blob/master/VisualStudio.gitignore 5 | 6 | # User-specific files 7 | *.rsuser 8 | *.suo 9 | *.user 10 | *.vcxproj.user 11 | *.userosscache 12 | *.sln.docstates 13 | *.filters 14 | 15 | # User-specific files (MonoDevelop/Xamarin Studio) 16 | *.userprefs 17 | 18 | # Mono auto generated files 19 | mono_crash.* 20 | 21 | # Build results 22 | [Dd]ebug/ 23 | [Dd]ebugPublic/ 24 | [Rr]elease/ 25 | [Rr]eleases/ 26 | x64/ 27 | x86/ 28 | [Aa][Rr][Mm]/ 29 | [Aa][Rr][Mm]64/ 30 | bld/ 31 | [Bb]in/ 32 | [Oo]bj/ 33 | [Ll]og/ 34 | [Ll]ogs/ 35 | 36 | # Visual Studio 2015/2017 cache/options directory 37 | .vs/ 38 | # Uncomment if you have tasks that create the project's static files in wwwroot 39 | #wwwroot/ 40 | 41 | # Visual Studio 2017 auto generated files 42 | Generated\ Files/ 43 | 44 | # MSTest test Results 45 | [Tt]est[Rr]esult*/ 46 | [Bb]uild[Ll]og.* 47 | 48 | # NUnit 49 | *.VisualState.xml 50 | TestResult.xml 51 | nunit-*.xml 52 | 53 | # Build Results of an ATL Project 54 | [Dd]ebugPS/ 55 | [Rr]eleasePS/ 56 | dlldata.c 57 | 58 | # Benchmark Results 59 | BenchmarkDotNet.Artifacts/ 60 | 61 | # .NET Core 62 | project.lock.json 63 | project.fragment.lock.json 64 | artifacts/ 65 | 66 | # StyleCop 67 | StyleCopReport.xml 68 | 69 | # Files built by Visual Studio 70 | *_i.c 71 | *_p.c 72 | *_h.h 73 | *.ilk 74 | *.meta 75 | *.obj 76 | *.iobj 77 | *.pch 78 | *.pdb 79 | *.ipdb 80 | *.pgc 81 | *.pgd 82 | *.rsp 83 | *.sbr 84 | *.tlb 85 | *.tli 86 | *.tlh 87 | *.tmp 88 | *.tmp_proj 89 | *_wpftmp.csproj 90 | *.log 91 | *.vspscc 92 | *.vssscc 93 | .builds 94 | *.pidb 95 | *.svclog 96 | *.scc 97 | 98 | # Chutzpah Test files 99 | _Chutzpah* 100 | 101 | # Visual C++ cache files 102 | ipch/ 103 | *.aps 104 | *.ncb 105 | *.opendb 106 | *.opensdf 107 | *.sdf 108 | *.cachefile 109 | *.VC.db 110 | *.VC.VC.opendb 111 | 112 | # Visual Studio profiler 113 | *.psess 114 | *.vsp 115 | *.vspx 116 | *.sap 117 | 118 | # Visual Studio Trace Files 119 | *.e2e 120 | 121 | # TFS 2012 Local Workspace 122 | $tf/ 123 | 124 | # Guidance Automation Toolkit 125 | *.gpState 126 | 127 | # ReSharper is a .NET coding add-in 128 | _ReSharper*/ 129 | *.[Rr]e[Ss]harper 130 | *.DotSettings.user 131 | 132 | # TeamCity is a build add-in 133 | _TeamCity* 134 | 135 | # DotCover is a Code Coverage Tool 136 | *.dotCover 137 | 138 | # AxoCover is a Code Coverage Tool 139 | .axoCover/* 140 | !.axoCover/settings.json 141 | 142 | # Visual Studio code coverage results 143 | *.coverage 144 | *.coveragexml 145 | 146 | # NCrunch 147 | _NCrunch_* 148 | .*crunch*.local.xml 149 | nCrunchTemp_* 150 | 151 | # MightyMoose 152 | *.mm.* 153 | AutoTest.Net/ 154 | 155 | # Web workbench (sass) 156 | .sass-cache/ 157 | 158 | # Installshield output folder 159 | [Ee]xpress/ 160 | 161 | # DocProject is a documentation generator add-in 162 | DocProject/buildhelp/ 163 | DocProject/Help/*.HxT 164 | DocProject/Help/*.HxC 165 | DocProject/Help/*.hhc 166 | DocProject/Help/*.hhk 167 | DocProject/Help/*.hhp 168 | DocProject/Help/Html2 169 | DocProject/Help/html 170 | 171 | # Click-Once directory 172 | publish/ 173 | 174 | # Publish Web Output 175 | *.[Pp]ublish.xml 176 | *.azurePubxml 177 | # Note: Comment the next line if you want to checkin your web deploy settings, 178 | # but database connection strings (with potential passwords) will be unencrypted 179 | *.pubxml 180 | *.publishproj 181 | 182 | # Microsoft Azure Web App publish settings. Comment the next line if you want to 183 | # checkin your Azure Web App publish settings, but sensitive information contained 184 | # in these scripts will be unencrypted 185 | PublishScripts/ 186 | 187 | # NuGet Packages 188 | *.nupkg 189 | # NuGet Symbol Packages 190 | *.snupkg 191 | # The packages folder can be ignored because of Package Restore 192 | **/[Pp]ackages/* 193 | # except build/, which is used as an MSBuild target. 194 | !**/[Pp]ackages/build/ 195 | # Uncomment if necessary however generally it will be regenerated when needed 196 | #!**/[Pp]ackages/repositories.config 197 | # NuGet v3's project.json files produces more ignorable files 198 | *.nuget.props 199 | *.nuget.targets 200 | 201 | # Microsoft Azure Build Output 202 | csx/ 203 | *.build.csdef 204 | 205 | # Microsoft Azure Emulator 206 | ecf/ 207 | rcf/ 208 | 209 | # Windows Store app package directories and files 210 | AppPackages/ 211 | BundleArtifacts/ 212 | Package.StoreAssociation.xml 213 | _pkginfo.txt 214 | *.appx 215 | *.appxbundle 216 | *.appxupload 217 | 218 | # Visual Studio cache files 219 | # files ending in .cache can be ignored 220 | *.[Cc]ache 221 | # but keep track of directories ending in .cache 222 | !?*.[Cc]ache/ 223 | 224 | # Others 225 | ClientBin/ 226 | ~$* 227 | *~ 228 | *.dbmdl 229 | *.dbproj.schemaview 230 | *.jfm 231 | *.pfx 232 | *.publishsettings 233 | orleans.codegen.cs 234 | 235 | # Including strong name files can present a security risk 236 | # (https://github.com/github/gitignore/pull/2483#issue-259490424) 237 | #*.snk 238 | 239 | # Since there are multiple workflows, uncomment next line to ignore bower_components 240 | # (https://github.com/github/gitignore/pull/1529#issuecomment-104372622) 241 | #bower_components/ 242 | 243 | # RIA/Silverlight projects 244 | Generated_Code/ 245 | 246 | # Backup & report files from converting an old project file 247 | # to a newer Visual Studio version. Backup files are not needed, 248 | # because we have git ;-) 249 | _UpgradeReport_Files/ 250 | Backup*/ 251 | UpgradeLog*.XML 252 | UpgradeLog*.htm 253 | ServiceFabricBackup/ 254 | *.rptproj.bak 255 | 256 | # SQL Server files 257 | *.mdf 258 | *.ldf 259 | *.ndf 260 | 261 | # Business Intelligence projects 262 | *.rdl.data 263 | *.bim.layout 264 | *.bim_*.settings 265 | *.rptproj.rsuser 266 | *- [Bb]ackup.rdl 267 | *- [Bb]ackup ([0-9]).rdl 268 | *- [Bb]ackup ([0-9][0-9]).rdl 269 | 270 | # Microsoft Fakes 271 | FakesAssemblies/ 272 | 273 | # GhostDoc plugin setting file 274 | *.GhostDoc.xml 275 | 276 | # Node.js Tools for Visual Studio 277 | .ntvs_analysis.dat 278 | node_modules/ 279 | 280 | # Visual Studio 6 build log 281 | *.plg 282 | 283 | # Visual Studio 6 workspace options file 284 | *.opt 285 | 286 | # Visual Studio 6 auto-generated workspace file (contains which files were open etc.) 287 | *.vbw 288 | 289 | # Visual Studio LightSwitch build output 290 | **/*.HTMLClient/GeneratedArtifacts 291 | **/*.DesktopClient/GeneratedArtifacts 292 | **/*.DesktopClient/ModelManifest.xml 293 | **/*.Server/GeneratedArtifacts 294 | **/*.Server/ModelManifest.xml 295 | _Pvt_Extensions 296 | 297 | # Paket dependency manager 298 | .paket/paket.exe 299 | paket-files/ 300 | 301 | # FAKE - F# Make 302 | .fake/ 303 | 304 | # CodeRush personal settings 305 | .cr/personal 306 | 307 | # Python Tools for Visual Studio (PTVS) 308 | __pycache__/ 309 | *.pyc 310 | 311 | # Cake - Uncomment if you are using it 312 | # tools/** 313 | # !tools/packages.config 314 | 315 | # Tabs Studio 316 | *.tss 317 | 318 | # Telerik's JustMock configuration file 319 | *.jmconfig 320 | 321 | # BizTalk build output 322 | *.btp.cs 323 | *.btm.cs 324 | *.odx.cs 325 | *.xsd.cs 326 | 327 | # OpenCover UI analysis results 328 | OpenCover/ 329 | 330 | # Azure Stream Analytics local run output 331 | ASALocalRun/ 332 | 333 | # MSBuild Binary and Structured Log 334 | *.binlog 335 | 336 | # NVidia Nsight GPU debugger configuration file 337 | *.nvuser 338 | 339 | # MFractors (Xamarin productivity tool) working folder 340 | .mfractor/ 341 | 342 | # Local History for Visual Studio 343 | .localhistory/ 344 | 345 | # BeatPulse healthcheck temp database 346 | healthchecksdb 347 | 348 | # Backup folder for Package Reference Convert tool in Visual Studio 2017 349 | MigrationBackup/ 350 | 351 | # Ionide (cross platform F# VS Code tools) working folder 352 | .ionide/ 353 | 354 | # Custom rules 355 | *.rar 356 | *.zip 357 | /OpenGlass/Archieve 358 | /Theme 359 | /OpenGlass/OpenGlass.vcxproj.user -------------------------------------------------------------------------------- /OpenGlass/OpenGlass.rc: -------------------------------------------------------------------------------- 1 | // Microsoft Visual C++ generated resource script. 2 | // 3 | #pragma code_page(65001) 4 | 5 | #include "resource.h" 6 | 7 | #define APSTUDIO_READONLY_SYMBOLS 8 | ///////////////////////////////////////////////////////////////////////////// 9 | // 10 | // Generated from the TEXTINCLUDE 2 resource. 11 | // 12 | #include "winres.h" 13 | 14 | ///////////////////////////////////////////////////////////////////////////// 15 | #undef APSTUDIO_READONLY_SYMBOLS 16 | 17 | ///////////////////////////////////////////////////////////////////////////// 18 | // Neutral (Default) resources 19 | 20 | #if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_NEUD) 21 | LANGUAGE LANG_NEUTRAL, SUBLANG_DEFAULT 22 | 23 | ///////////////////////////////////////////////////////////////////////////// 24 | // 25 | // PNG 26 | // 27 | 28 | IDB_REFLECTION PNG "reflection.png" 29 | 30 | 31 | ///////////////////////////////////////////////////////////////////////////// 32 | // 33 | // Version 34 | // 35 | 36 | VS_VERSION_INFO VERSIONINFO 37 | FILEVERSION 2,4,3,2085 38 | PRODUCTVERSION 2,4,3,2085 39 | FILEFLAGSMASK 0x3fL 40 | #ifdef _DEBUG 41 | FILEFLAGS 0x1L 42 | #else 43 | FILEFLAGS 0x0L 44 | #endif 45 | FILEOS 0x40004L 46 | FILETYPE 0x2L 47 | FILESUBTYPE 0x0L 48 | BEGIN 49 | BLOCK "StringFileInfo" 50 | BEGIN 51 | BLOCK "040004b0" 52 | BEGIN 53 | VALUE "CompanyName", "ALTaleX" 54 | VALUE "FileDescription", "Aero Glass extension for Desktop Window Manager" 55 | VALUE "FileVersion", "2.4.3.2085" 56 | VALUE "InternalName", "Aero Glass for Win10+" 57 | VALUE "LegalCopyright", "Copyright (C) 2024-2025 ALTaleX" 58 | VALUE "OriginalFilename", "OpenGlass.dll" 59 | VALUE "ProductName", "Aero Glass for Win10+" 60 | VALUE "ProductVersion", "2.4.3.2085" 61 | END 62 | END 63 | BLOCK "VarFileInfo" 64 | BEGIN 65 | VALUE "Translation", 0x400, 1200 66 | END 67 | END 68 | 69 | #endif // Neutral (Default) resources 70 | ///////////////////////////////////////////////////////////////////////////// 71 | 72 | 73 | ///////////////////////////////////////////////////////////////////////////// 74 | // Chinese (Simplified, China) resources 75 | 76 | #if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_CHS) 77 | LANGUAGE LANG_CHINESE, SUBLANG_CHINESE_SIMPLIFIED 78 | 79 | #ifdef APSTUDIO_INVOKED 80 | ///////////////////////////////////////////////////////////////////////////// 81 | // 82 | // TEXTINCLUDE 83 | // 84 | 85 | 1 TEXTINCLUDE 86 | BEGIN 87 | "resource.h\0" 88 | END 89 | 90 | 2 TEXTINCLUDE 91 | BEGIN 92 | "#include ""winres.h""\r\n" 93 | "\0" 94 | END 95 | 96 | 3 TEXTINCLUDE 97 | BEGIN 98 | "\r\n" 99 | "\0" 100 | END 101 | 102 | #endif // APSTUDIO_INVOKED 103 | 104 | 105 | ///////////////////////////////////////////////////////////////////////////// 106 | // 107 | // RCDATA 108 | // 109 | 110 | IDR_RCDATA1 RCDATA "AeroColorizationEffect.cso" 111 | 112 | 113 | ///////////////////////////////////////////////////////////////////////////// 114 | // 115 | // String Table 116 | // 117 | 118 | STRINGTABLE 119 | BEGIN 120 | IDS_STRING101 "OpenGlass 兼容性问题" 121 | IDS_STRING102 "OpenGlass API 调用结果" 122 | IDS_STRING103 "显示详细信息" 123 | IDS_STRING104 "隐藏详细信息" 124 | IDS_STRING105 "该版本的 OpenGlass 不支持您的系统。\n仍然继续吗?" 125 | IDS_STRING106 "OpenGlass 不知道如何挂钩您当前系统版本的 DWM (0x%X)。\n\n我们尝试从微软服务器下载合适的符号文件,但是失败了。\n您现在想再试一次吗?\n\n!!! 不要反馈因为这不是BUG !!!" 126 | IDS_STRING107 "OpenGlass 不知道如何挂钩您当前系统版本的 DWM (0x%X)。\n\nDbgHelp API 在解析符号过程中出现错误。\n您现在想再试一次吗?" 127 | IDS_STRING108 "OpenGlass 不知道如何挂钩您当前系统版本的 DWM 因必要符号的缺失。\n\n!!! 这不是BUG而是目前不支持你的系统 !!!" 128 | IDS_STRING109 "DWM 在注入后不到 30 秒崩溃,DLL 注入已暂停。\n\n要中止 OpenGlass 服务进程以结束之后所有的注入,请单击“中止”。\n要再试一次,请单击“重试”。\n要排除这个 DWM 进程,请点击“忽略”。" 129 | IDS_STRING110 "该任务会为您将 DLL 注入 DWM,并确保 OpenGlass 能正确加载用户配置。" 130 | IDS_STRING111 "正在下载符号文件..." 131 | END 132 | 133 | #endif // Chinese (Simplified, China) resources 134 | ///////////////////////////////////////////////////////////////////////////// 135 | 136 | 137 | ///////////////////////////////////////////////////////////////////////////// 138 | // Chinese (Traditional, Taiwan) resources 139 | 140 | #if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_CHT) 141 | LANGUAGE LANG_CHINESE, SUBLANG_CHINESE_TRADITIONAL 142 | 143 | ///////////////////////////////////////////////////////////////////////////// 144 | // 145 | // String Table 146 | // 147 | 148 | STRINGTABLE 149 | BEGIN 150 | IDS_STRING101 "OpenGlass 相容性問題" 151 | IDS_STRING102 "OpenGlass API 呼叫結果" 152 | IDS_STRING103 "顯示詳細資訊" 153 | IDS_STRING104 "隱藏詳細資訊" 154 | IDS_STRING105 "該版本的 OpenGlass 不支援閣下的系統。\n仍然繼續嗎?" 155 | IDS_STRING106 "OpenGlass 不知道如何鈎住閣下當前系統版本的 DWM (0x%X)。\n\n我們嘗試從 Microsoft 伺服器下載合適的符號檔案,但是失敗了。\n閣下現在想再試一次嗎?\n\n!!! 不要報告因爲這不是BUG !!!" 156 | IDS_STRING107 "OpenGlass 不知道如何鈎住閣下當前系統版本的 DWM (0x%X)。\n\nDbgHelp API 在解析符號過程中出現錯誤。\n閣下現在想再試一次嗎?" 157 | IDS_STRING108 "OpenGlass 不知道如何鈎住閣下當前系統版本的 DWM 因必要符號之缺失。\n\n!!! 這不是BUG而是目前不支援你的系統 !!!" 158 | IDS_STRING109 "DWM 在注入后不到 30 秒崩潰,DLL 注入已暫停。\n\n要中止 OpenGlass 服務進程以結束過後一切之注入,請按一下“中止”。\n要再試一次,請按一下“重試”。\n要排除這個 DWM 進程,請按一下“忽略”。" 159 | IDS_STRING110 "該任務會為閣下將 DLL 注入 DWM,並確保 OpenGlass 能正確加載用戶設定。" 160 | IDS_STRING111 "正在下載符號檔案..." 161 | END 162 | 163 | #endif // Chinese (Traditional, Taiwan) resources 164 | ///////////////////////////////////////////////////////////////////////////// 165 | 166 | 167 | ///////////////////////////////////////////////////////////////////////////// 168 | // English (Neutral) resources 169 | 170 | #if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU) 171 | LANGUAGE LANG_ENGLISH, SUBLANG_NEUTRAL 172 | 173 | ///////////////////////////////////////////////////////////////////////////// 174 | // 175 | // String Table 176 | // 177 | 178 | STRINGTABLE 179 | BEGIN 180 | IDS_STRING101 "OpenGlass Incompatibility issue" 181 | IDS_STRING102 "OpenGlass API result" 182 | IDS_STRING103 "Show details" 183 | IDS_STRING104 "Hide details" 184 | IDS_STRING105 "Your system version is NOT supported by this version of OpenGlass. \nContinue anyway?" 185 | IDS_STRING106 "OpenGlass does not know how to hook your version of DWM (0x%X).\n\nWe tried to download appropriate symbols files from Microsoft server but it failed.\nDo you want to retry it now?\n\n!!! DO NOT REPORT THIS BECAUSE THIS IS NOT A BUG !!!" 186 | IDS_STRING107 "OpenGlass does not know how to hook your version of DWM (0x%X).\n\nThe DbgHelp API fails during symbol parsing.\nDo you want to retry it now?" 187 | IDS_STRING108 "OpenGlass does not know how to hook your version of DWM due to missing required symbols.\n\n!!! THIS IS NOT A BUG BUT YOUR SYSTEM IS NOT YET SUPPORTED !!!" 188 | IDS_STRING109 "DWM crashed less than 30 seconds after injection, DLL injection has been suspended.\n\nClick ""Abort"" to shut down the OpenGlass service process and end all subsequent injections.\nClick ""Retry"" to inject again.\nClick ""Ignore"" to exclude this DWM process." 189 | IDS_STRING110 "This task injects DLL into DWM for you and also maintains that user settings are correctly loaded." 190 | IDS_STRING111 "Downloading symbol files..." 191 | END 192 | 193 | #endif // English (Neutral) resources 194 | ///////////////////////////////////////////////////////////////////////////// 195 | 196 | 197 | 198 | #ifndef APSTUDIO_INVOKED 199 | ///////////////////////////////////////////////////////////////////////////// 200 | // 201 | // Generated from the TEXTINCLUDE 3 resource. 202 | // 203 | 204 | 205 | ///////////////////////////////////////////////////////////////////////////// 206 | #endif // not APSTUDIO_INVOKED 207 | 208 | -------------------------------------------------------------------------------- /OpenGlass/GlassSafetyZoneLayer.cpp: -------------------------------------------------------------------------------- 1 | #include "pch.h" 2 | #include "GlassKernel.hpp" 3 | #include "GlassSafetyZoneLayer.hpp" 4 | 5 | using namespace OpenGlass; 6 | 7 | HRESULT CGlassSafetyZoneLayer::Push( 8 | ID2D1DeviceContext* context, 9 | ID2D1Bitmap1* renderTargetBitmap, 10 | const D2D1_MATRIX_3X2_F& deviceTransform, 11 | const D2D1_RECT_F& originalPixelRectangle, 12 | float extendedAmount, 13 | D2D1_RECT_F& extendedPixelRectangle 14 | ) 15 | { 16 | extendedPixelRectangle = originalPixelRectangle; 17 | m_renderTargetBitmap.copy_from(renderTargetBitmap); 18 | auto pushCleanupScope = wil::scope_exit([this] 19 | { 20 | m_renderTargetBitmap = nullptr; 21 | }); 22 | const auto targetSize = renderTargetBitmap->GetSize(); 23 | const D2D1_RECT_F targetRect 24 | { 25 | 0.f, 26 | 0.f, 27 | targetSize.width, 28 | targetSize.height 29 | }; 30 | 31 | D2D1_RECT_F originalDeviceRectangle; 32 | D2D1_RECT_F extendedDeviceRectangle; 33 | 34 | originalDeviceRectangle = RectF::TransformRect(originalPixelRectangle, deviceTransform); 35 | originalDeviceRectangle.left = std::floor(originalDeviceRectangle.left); 36 | originalDeviceRectangle.top = std::floor(originalDeviceRectangle.top); 37 | originalDeviceRectangle.right = std::ceil(originalDeviceRectangle.right); 38 | originalDeviceRectangle.bottom = std::ceil(originalDeviceRectangle.bottom); 39 | RectF::IntersectUnsafe(originalDeviceRectangle, targetRect); 40 | 41 | extendedDeviceRectangle.left = originalPixelRectangle.left - extendedAmount; 42 | extendedDeviceRectangle.top = originalPixelRectangle.top - extendedAmount; 43 | extendedDeviceRectangle.right = originalPixelRectangle.right + extendedAmount; 44 | extendedDeviceRectangle.bottom = originalPixelRectangle.bottom + extendedAmount; 45 | extendedDeviceRectangle = RectF::TransformRect(extendedDeviceRectangle, deviceTransform); 46 | extendedDeviceRectangle.left = std::floor(extendedDeviceRectangle.left); 47 | extendedDeviceRectangle.top = std::floor(extendedDeviceRectangle.top); 48 | extendedDeviceRectangle.right = std::ceil(extendedDeviceRectangle.right); 49 | extendedDeviceRectangle.bottom = std::ceil(extendedDeviceRectangle.bottom); 50 | RectF::IntersectUnsafe(extendedDeviceRectangle, targetRect); 51 | 52 | D2D1_MATRIX_3X2_F invertedDeviceTransform = deviceTransform; 53 | if (D2D1InvertMatrix(&invertedDeviceTransform)) [[unlikely]] 54 | { 55 | extendedPixelRectangle = RectF::TransformRect(extendedDeviceRectangle, invertedDeviceTransform); 56 | } 57 | else 58 | { 59 | extendedPixelRectangle.left -= extendedAmount; 60 | extendedPixelRectangle.top -= extendedAmount; 61 | extendedPixelRectangle.right += extendedAmount; 62 | extendedPixelRectangle.bottom += extendedAmount; 63 | } 64 | 65 | if ( 66 | extendedPixelRectangle.left == originalPixelRectangle.left && 67 | extendedPixelRectangle.top == originalPixelRectangle.top && 68 | extendedPixelRectangle.right == originalPixelRectangle.right && 69 | extendedPixelRectangle.bottom == originalPixelRectangle.bottom 70 | ) 71 | { 72 | return S_OK; 73 | } 74 | 75 | m_safetyZoneBounds[0] = 76 | { 77 | static_cast(extendedDeviceRectangle.left), 78 | static_cast(extendedDeviceRectangle.top), 79 | static_cast(originalDeviceRectangle.left), 80 | static_cast(originalDeviceRectangle.bottom) 81 | }; 82 | m_safetyZoneBounds[1] = 83 | { 84 | static_cast(originalDeviceRectangle.left), 85 | static_cast(extendedDeviceRectangle.top), 86 | static_cast(extendedDeviceRectangle.right), 87 | static_cast(originalDeviceRectangle.top) 88 | }; 89 | m_safetyZoneBounds[2] = 90 | { 91 | static_cast(originalDeviceRectangle.right), 92 | static_cast(originalDeviceRectangle.top), 93 | static_cast(extendedDeviceRectangle.right), 94 | static_cast(extendedDeviceRectangle.bottom) 95 | }; 96 | m_safetyZoneBounds[3] = 97 | { 98 | static_cast(extendedDeviceRectangle.left), 99 | static_cast(originalDeviceRectangle.bottom), 100 | static_cast(originalDeviceRectangle.right), 101 | static_cast(extendedDeviceRectangle.bottom) 102 | }; 103 | 104 | D2D1_RECT_F extendedRectangle 105 | { 106 | 0.f, 107 | 0.f, 108 | extendedAmount, 109 | extendedAmount 110 | }; 111 | extendedRectangle = RectF::TransformRect(extendedRectangle, deviceTransform); 112 | const auto actualExtendedAmountX = wil::rect_width(extendedRectangle); 113 | const auto actualExtendedAmountY = wil::rect_height(extendedRectangle); 114 | 115 | m_safetyZoneBufferVertical.Resize( 116 | D2D1::SizeU( 117 | static_cast(std::ceil(actualExtendedAmountX)) * 2, 118 | static_cast(std::ceil(targetSize.height + actualExtendedAmountY)) 119 | ) 120 | ); 121 | m_safetyZoneBufferHorizontal.Resize( 122 | D2D1::SizeU( 123 | static_cast(std::ceil(targetSize.width + actualExtendedAmountX)), 124 | static_cast(std::ceil(actualExtendedAmountY)) * 2 125 | ) 126 | ); 127 | 128 | if (!wil::rect_is_empty(m_safetyZoneBounds[0])) 129 | { 130 | RETURN_IF_FAILED( 131 | m_safetyZoneBufferVertical.CopyFrom( 132 | context, 133 | D2D1::Point2U(0, 0), 134 | m_renderTargetBitmap.get(), 135 | m_safetyZoneBounds[0] 136 | ) 137 | ); 138 | } 139 | if (!wil::rect_is_empty(m_safetyZoneBounds[2])) 140 | { 141 | RETURN_IF_FAILED( 142 | m_safetyZoneBufferVertical.CopyFrom( 143 | context, 144 | D2D1::Point2U(wil::rect_width(m_safetyZoneBounds[0]), 0), 145 | m_renderTargetBitmap.get(), 146 | m_safetyZoneBounds[2] 147 | ) 148 | ); 149 | } 150 | if (!wil::rect_is_empty(m_safetyZoneBounds[1])) 151 | { 152 | RETURN_IF_FAILED( 153 | m_safetyZoneBufferHorizontal.CopyFrom( 154 | context, 155 | D2D1::Point2U(0, 0), 156 | m_renderTargetBitmap.get(), 157 | m_safetyZoneBounds[1] 158 | ) 159 | ); 160 | } 161 | if (!wil::rect_is_empty(m_safetyZoneBounds[3])) 162 | { 163 | RETURN_IF_FAILED( 164 | m_safetyZoneBufferHorizontal.CopyFrom( 165 | context, 166 | D2D1::Point2U(0, wil::rect_height(m_safetyZoneBounds[1])), 167 | m_renderTargetBitmap.get(), 168 | m_safetyZoneBounds[3] 169 | ) 170 | ); 171 | } 172 | 173 | pushCleanupScope.release(); 174 | return S_OK; 175 | } 176 | 177 | void CGlassSafetyZoneLayer::Pop() 178 | { 179 | if (!m_renderTargetBitmap) 180 | { 181 | return; 182 | } 183 | 184 | if (!wil::rect_is_empty(m_safetyZoneBounds[0])) 185 | { 186 | m_safetyZoneBufferVertical.CopyTo( 187 | D2D1::Point2U(m_safetyZoneBounds[0].left, m_safetyZoneBounds[0].top), 188 | m_renderTargetBitmap.get(), 189 | D2D1::RectU( 190 | 0u, 191 | 0u, 192 | wil::rect_width(m_safetyZoneBounds[0]), 193 | wil::rect_height(m_safetyZoneBounds[0]) 194 | ) 195 | ); 196 | } 197 | if (!wil::rect_is_empty(m_safetyZoneBounds[2])) 198 | { 199 | m_safetyZoneBufferVertical.CopyTo( 200 | D2D1::Point2U(m_safetyZoneBounds[2].left, m_safetyZoneBounds[2].top), 201 | m_renderTargetBitmap.get(), 202 | D2D1::RectU( 203 | wil::rect_width(m_safetyZoneBounds[0]), 204 | 0, 205 | wil::rect_width(m_safetyZoneBounds[0]) + wil::rect_width(m_safetyZoneBounds[2]), 206 | wil::rect_height(m_safetyZoneBounds[2]) 207 | ) 208 | ); 209 | } 210 | if (!wil::rect_is_empty(m_safetyZoneBounds[1])) 211 | { 212 | m_safetyZoneBufferHorizontal.CopyTo( 213 | D2D1::Point2U(m_safetyZoneBounds[1].left, m_safetyZoneBounds[1].top), 214 | m_renderTargetBitmap.get(), 215 | D2D1::RectU( 216 | 0u, 217 | 0u, 218 | wil::rect_width(m_safetyZoneBounds[1]), 219 | wil::rect_height(m_safetyZoneBounds[1]) 220 | ) 221 | ); 222 | } 223 | if (!wil::rect_is_empty(m_safetyZoneBounds[3])) 224 | { 225 | m_safetyZoneBufferHorizontal.CopyTo( 226 | D2D1::Point2U(m_safetyZoneBounds[3].left, m_safetyZoneBounds[3].top), 227 | m_renderTargetBitmap.get(), 228 | D2D1::RectU( 229 | 0, 230 | wil::rect_height(m_safetyZoneBounds[1]), 231 | wil::rect_width(m_safetyZoneBounds[3]), 232 | wil::rect_height(m_safetyZoneBounds[1]) + wil::rect_height(m_safetyZoneBounds[3]) 233 | ) 234 | ); 235 | } 236 | 237 | m_renderTargetBitmap = nullptr; 238 | ZeroMemory(m_safetyZoneBounds, sizeof(m_safetyZoneBounds)); 239 | } 240 | -------------------------------------------------------------------------------- /OpenGlass/AeroColorizationEffect.cpp: -------------------------------------------------------------------------------- 1 | #include "pch.h" 2 | #include "resource.h" 3 | #include "AeroColorizationEffect.hpp" 4 | 5 | using namespace OpenGlass; 6 | 7 | STDMETHODIMP CAeroColorizationEffect::Register(ID2D1Factory1* factory) 8 | { 9 | const D2D1_PROPERTY_BINDING bindings[] = 10 | { 11 | D2D1_VALUE_TYPE_BINDING(L"vecAfterglow", &SetAfterglow, &GetAfterglow), 12 | D2D1_VALUE_TYPE_BINDING(L"vecBlurBalance", &SetBlurBalance, &GetBlurBalance), 13 | D2D1_VALUE_TYPE_BINDING(L"vecColor", &SetColor, &GetColor), 14 | }; 15 | 16 | return factory->RegisterEffectFromString( 17 | CLSID_AeroColorizationEffect, 18 | L"" 19 | "" 20 | "" 21 | "" 22 | "" 23 | "" 24 | "" 25 | "" 26 | "" 27 | "" 28 | "" 29 | "" 30 | "" 31 | "" 32 | "" 33 | "" 34 | "" 35 | "" 36 | "" 37 | "" 38 | "" 39 | "" 40 | "" 41 | "" 42 | "", 43 | bindings, 44 | std::size(bindings), 45 | CAeroColorizationEffect::Create 46 | ); 47 | } 48 | 49 | STDMETHODIMP CAeroColorizationEffect::UnRegister(ID2D1Factory1* factory) 50 | { 51 | return factory->UnregisterEffect(CLSID_AeroColorizationEffect); 52 | } 53 | 54 | STDMETHODIMP CAeroColorizationEffect::Create(IUnknown** effect) noexcept 55 | { 56 | *effect = static_cast(new (std::nothrow) CAeroColorizationEffect()); 57 | RETURN_HR_IF_NULL(E_OUTOFMEMORY, *effect); 58 | return S_OK; 59 | } 60 | 61 | HRESULT CAeroColorizationEffect::SetAfterglow(D2D1_VECTOR_4F afterglow) 62 | { 63 | m_constants.afterglow = afterglow; 64 | return S_OK; 65 | } 66 | 67 | D2D1_VECTOR_4F CAeroColorizationEffect::GetAfterglow() const 68 | { 69 | return m_constants.afterglow; 70 | } 71 | 72 | HRESULT CAeroColorizationEffect::SetBlurBalance(D2D1_VECTOR_4F blurBalance) 73 | { 74 | m_constants.blurBalance = blurBalance; 75 | return S_OK; 76 | } 77 | 78 | D2D1_VECTOR_4F CAeroColorizationEffect::GetBlurBalance() const 79 | { 80 | return m_constants.blurBalance; 81 | } 82 | 83 | HRESULT CAeroColorizationEffect::SetColor(D2D1_VECTOR_4F color) 84 | { 85 | m_constants.color = color; 86 | return S_OK; 87 | } 88 | D2D1_VECTOR_4F CAeroColorizationEffect::GetColor() const 89 | { 90 | return m_constants.color; 91 | } 92 | 93 | HRESULT CAeroColorizationEffect::UpdateConstants() 94 | { 95 | return m_drawInfo->SetPixelShaderConstantBuffer(reinterpret_cast(&m_constants), sizeof(m_constants)); 96 | } 97 | 98 | IFACEMETHODIMP CAeroColorizationEffect::Initialize( 99 | ID2D1EffectContext* effectContext, 100 | ID2D1TransformGraph* transformGraph 101 | ) 102 | { 103 | if (!effectContext->IsShaderLoaded(CLSID_AeroColorizationEffectPixelShader)) 104 | { 105 | const auto currentModule = wil::GetModuleInstanceHandle(); 106 | const auto resourceHandle = FindResourceW(currentModule, MAKEINTRESOURCE(IDR_RCDATA1), RT_RCDATA); 107 | RETURN_LAST_ERROR_IF_NULL(resourceHandle); 108 | const auto globalHandle = LoadResource(currentModule, resourceHandle); 109 | RETURN_LAST_ERROR_IF_NULL(globalHandle); 110 | const auto cleanup = wil::scope_exit([=] 111 | { 112 | if (globalHandle) 113 | { 114 | UnlockResource(globalHandle); 115 | FreeResource(globalHandle); 116 | } 117 | }); 118 | const auto resourceSize = SizeofResource(currentModule, resourceHandle); 119 | RETURN_LAST_ERROR_IF(resourceSize == 0); 120 | const auto resourceAddress = reinterpret_cast(LockResource(globalHandle)); 121 | RETURN_IF_FAILED( 122 | effectContext->LoadPixelShader( 123 | CLSID_AeroColorizationEffectPixelShader, 124 | resourceAddress, 125 | resourceSize 126 | ) 127 | ); 128 | } 129 | RETURN_IF_FAILED(transformGraph->SetSingleTransformNode(static_cast(this))); 130 | m_effectContext.copy_from(effectContext); 131 | 132 | return S_OK; 133 | } 134 | 135 | IFACEMETHODIMP CAeroColorizationEffect::PrepareForRender([[maybe_unused]] D2D1_CHANGE_TYPE changeType) 136 | { 137 | return UpdateConstants(); 138 | } 139 | 140 | IFACEMETHODIMP CAeroColorizationEffect::SetGraph([[maybe_unused]] ID2D1TransformGraph* graph) 141 | { 142 | return E_NOTIMPL; 143 | } 144 | 145 | IFACEMETHODIMP CAeroColorizationEffect::CAeroColorizationEffect::SetDrawInfo(ID2D1DrawInfo* drawInfo) 146 | { 147 | m_drawInfo.copy_from(drawInfo); 148 | return m_drawInfo->SetPixelShader(CLSID_AeroColorizationEffectPixelShader); 149 | } 150 | 151 | IFACEMETHODIMP CAeroColorizationEffect::MapOutputRectToInputRects( 152 | const D2D1_RECT_L* outputRect, 153 | D2D1_RECT_L* inputRects, 154 | UINT32 inputRectCount 155 | ) const 156 | { 157 | if (inputRectCount != 1) 158 | { 159 | return E_INVALIDARG; 160 | } 161 | 162 | inputRects[0].left = outputRect->left; 163 | inputRects[0].top = outputRect->top; 164 | inputRects[0].right = outputRect->right; 165 | inputRects[0].bottom = outputRect->bottom; 166 | 167 | return S_OK; 168 | } 169 | 170 | IFACEMETHODIMP CAeroColorizationEffect::MapInputRectsToOutputRect( 171 | CONST D2D1_RECT_L* inputRects, 172 | CONST D2D1_RECT_L* inputOpaqueSubRects, 173 | UINT32 inputRectCount, 174 | D2D1_RECT_L* outputRect, 175 | D2D1_RECT_L* outputOpaqueSubRect 176 | ) 177 | { 178 | if (inputRectCount != 1) 179 | { 180 | return E_INVALIDARG; 181 | } 182 | 183 | *outputRect = inputRects[0]; 184 | *outputOpaqueSubRect = inputOpaqueSubRects[0]; 185 | 186 | return S_OK; 187 | } 188 | 189 | IFACEMETHODIMP CAeroColorizationEffect::MapInvalidRect( 190 | [[maybe_unused]] UINT32 inputIndex, 191 | D2D1_RECT_L invalidInputRect, 192 | D2D1_RECT_L* invalidOutputRect 193 | ) const 194 | { 195 | *invalidOutputRect = invalidInputRect; 196 | 197 | return S_OK; 198 | } 199 | 200 | IFACEMETHODIMP_(UINT32) CAeroColorizationEffect::GetInputCount() const 201 | { 202 | return 1; 203 | } 204 | 205 | // D2D ensures that that effects are only referenced from one thread at a time. 206 | // To improve performance, we simply increment/decrement our reference count 207 | // rather than use atomic InterlockedIncrement()/InterlockedDecrement() functions. 208 | IFACEMETHODIMP_(ULONG) CAeroColorizationEffect::AddRef() 209 | { 210 | return (++m_refCount); 211 | } 212 | 213 | IFACEMETHODIMP_(ULONG) CAeroColorizationEffect::Release() 214 | { 215 | if ((--m_refCount) == 0) 216 | { 217 | delete this; 218 | return 0; 219 | } 220 | 221 | return m_refCount; 222 | } 223 | 224 | // This enables the stack of parent interfaces to be queried. In the instance 225 | // of the CAeroColorizationEffect interface, this method simply enables the developer 226 | // to cast a CAeroColorizationEffect instance to an ID2D1EffectImpl or IUnknown instance. 227 | IFACEMETHODIMP CAeroColorizationEffect::QueryInterface( 228 | REFIID riid, 229 | void** output 230 | ) 231 | { 232 | *output = nullptr; 233 | 234 | if (riid == __uuidof(ID2D1EffectImpl)) 235 | { 236 | *output = static_cast(this); 237 | } 238 | else if (riid == __uuidof(ID2D1DrawTransform)) 239 | { 240 | *output = static_cast(this); 241 | } 242 | else if (riid == __uuidof(ID2D1Transform)) 243 | { 244 | *output = static_cast(this); 245 | } 246 | else if (riid == __uuidof(ID2D1TransformNode)) 247 | { 248 | *output = static_cast(this); 249 | } 250 | else if (riid == __uuidof(IUnknown)) 251 | { 252 | *output = this; 253 | } 254 | else 255 | { 256 | return E_NOINTERFACE; 257 | } 258 | 259 | if (*output != nullptr) 260 | { 261 | AddRef(); 262 | } 263 | 264 | return S_OK; 265 | } -------------------------------------------------------------------------------- /OpenGlass/ProjectionHelper.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "HookHelper.hpp" 3 | #include "OSHelper.hpp" 4 | #include "Util.hpp" 5 | 6 | namespace OpenGlass 7 | { 8 | enum class ProjectionType : UCHAR 9 | { 10 | Variable = 0, 11 | Function = 1 << 0, 12 | Optional = 1 << 1 13 | }; 14 | using ProjectionEntry = std::tuple; 15 | 16 | template 17 | struct ProjectionArray : std::array 18 | { 19 | ULONG _build{ 0 }; 20 | size_t _lastEmptyEntryIndex{ 0ull }; 21 | 22 | static bool IsProjectionEntryValid(ULONG build, const ProjectionEntry& entry) 23 | { 24 | if (build == 0) 25 | { 26 | return true; 27 | } 28 | const auto& min_build = std::get<4>(entry); 29 | const auto& max_build = std::get<5>(entry); 30 | if (min_build == 0 && max_build == 0) 31 | { 32 | return true; 33 | } 34 | if (min_build == 0) 35 | { 36 | return build < max_build; 37 | } 38 | if (max_build == 0) 39 | { 40 | return build >= min_build; 41 | } 42 | return build >= min_build && build < max_build; 43 | } 44 | void _Apply(ProjectionEntry& entry, PVOID symbolAddress) 45 | { 46 | [[maybe_unused]] auto& [type, name, from, to, min_build, max_build] = entry; 47 | to = symbolAddress; 48 | 49 | if (type == ProjectionType::Function) 50 | { 51 | UCHAR jmpInstructionBytes[] 52 | { 53 | // jmp qword ptr [rip+0] 54 | 0xFF, 0x25, 55 | 0x00, 0x00, 0x00, 0x00, 56 | 57 | 0x00, 0x00, 0x00, 0x00, 58 | 0x00, 0x00, 0x00, 0x00 59 | }; 60 | auto unprotectedScope = HookHelper::unprotect(from, sizeof(jmpInstructionBytes)); 61 | *reinterpret_cast(&jmpInstructionBytes[6]) = to; 62 | 63 | HookHelper::PatchInstructions( 64 | from, 65 | jmpInstructionBytes, 66 | sizeof(jmpInstructionBytes) 67 | ); 68 | } 69 | if (type == ProjectionType::Variable && from) 70 | { 71 | *reinterpret_cast(from) = to; 72 | } 73 | } 74 | void ApplyByIndex(size_t index, PVOID symbolAddress) 75 | { 76 | auto& entry = this->operator[](index); 77 | if (!IsProjectionEntryValid(_build, entry)) 78 | { 79 | return; 80 | } 81 | 82 | _Apply(entry, symbolAddress); 83 | 84 | if (_lastEmptyEntryIndex == index && std::get<3>(entry)) 85 | { 86 | _lastEmptyEntryIndex += 1ull; 87 | } 88 | } 89 | void Apply(LPCSTR symbolName, PVOID symbolAddress) 90 | { 91 | bool updated{ false }; 92 | for (auto i = _lastEmptyEntryIndex; i < N; i++) 93 | { 94 | auto& entry = this->operator[](i); 95 | if (!IsProjectionEntryValid(_build, entry)) 96 | { 97 | continue; 98 | } 99 | 100 | if (!strcmp(std::get<1>(entry), symbolName)) 101 | { 102 | _Apply(entry, symbolAddress); 103 | 104 | if (_lastEmptyEntryIndex == i && std::get<3>(entry)) 105 | { 106 | _lastEmptyEntryIndex += 1ull; 107 | } 108 | break; 109 | } 110 | else 111 | { 112 | if (!updated && !std::get<3>(entry)) 113 | { 114 | _lastEmptyEntryIndex = i; 115 | updated = true; 116 | } 117 | } 118 | } 119 | } 120 | void ApplyToVariable(LPCSTR symbolName, PVOID* variableAddress) 121 | { 122 | for (auto i = 0ull; i < N; i++) 123 | { 124 | const auto& entry = this->operator[](i); 125 | if (!IsProjectionEntryValid(_build, entry)) 126 | { 127 | continue; 128 | } 129 | if (!strcmp(std::get<1>(entry), symbolName)) 130 | { 131 | *variableAddress = std::get<3>(entry); 132 | break; 133 | } 134 | } 135 | } 136 | template 137 | FORCEINLINE void ApplyToVariable(LPCSTR symbolName, T& variableAddress) 138 | { 139 | return ApplyToVariable(symbolName, reinterpret_cast(&variableAddress)); 140 | } 141 | 142 | bool IsAllReady() const 143 | { 144 | if (_lastEmptyEntryIndex == 0ull) 145 | { 146 | return false; 147 | } 148 | if (_lastEmptyEntryIndex == N) 149 | { 150 | return true; 151 | } 152 | for (auto i = _lastEmptyEntryIndex; i < N; i++) 153 | { 154 | const auto& entry = this->operator[](i); 155 | if (!IsProjectionEntryValid(_build, entry)) 156 | { 157 | continue; 158 | } 159 | 160 | if (!std::get<3>(entry)) 161 | { 162 | return false; 163 | } 164 | } 165 | 166 | return true; 167 | } 168 | void ReportMissing(std::string& missingFunctionsOrVariables, std::string_view prefix) const 169 | { 170 | if (_lastEmptyEntryIndex == N) 171 | { 172 | return; 173 | } 174 | for (auto i = _lastEmptyEntryIndex; i < N; i++) 175 | { 176 | const auto& entry = this->operator[](i); 177 | if (!IsProjectionEntryValid(_build, entry)) 178 | { 179 | continue; 180 | } 181 | 182 | if (!std::get<3>(entry) && !(static_cast(std::get<0>(entry)) & static_cast(ProjectionType::Optional))) 183 | { 184 | missingFunctionsOrVariables.append(prefix); 185 | missingFunctionsOrVariables.append(std::get<1>(entry)); 186 | missingFunctionsOrVariables.append("\n"); 187 | } 188 | } 189 | } 190 | }; 191 | template 192 | ProjectionArray(First, Rest...) -> ProjectionArray<1 + sizeof...(Rest)>; 193 | template 194 | FORCEINLINE auto make_projection_array(ULONG build, Args&&... args) 195 | { 196 | auto result = ProjectionArray{ std::forward(args)... }; 197 | result._build = build; 198 | 199 | return result; 200 | } 201 | 202 | template 203 | struct StubFunctionOf {}; 204 | template 205 | struct StubFunctionOf 206 | { 207 | using type = T(STDMETHODCALLTYPE*)(volatile void*, volatile Args...); 208 | }; 209 | template 210 | struct StubFunctionOf 211 | { 212 | using type = T(STDMETHODCALLTYPE*)(volatile void*, volatile Args...); 213 | }; 214 | template 215 | struct StubFunctionOf 216 | { 217 | using type = T(STDMETHODCALLTYPE*)(volatile void*, volatile Args...); 218 | }; 219 | } 220 | 221 | #define DECLSPEC_PROJECTION DECLSPEC_NOINLINE inline 222 | #define HANDLE_PROJECTION_FUNCTION(function, ...) \ 223 | (reinterpret_cast::type>(Util::compile_time_hash(#function, 0ull))(Util::force_cast_from(&function), ##__VA_ARGS__)) 224 | 225 | #define MAKE_FUNCTION_PROJECTION_TUPLE(function, min_build, max_build) \ 226 | OpenGlass::ProjectionEntry \ 227 | { \ 228 | OpenGlass::ProjectionType::Function, \ 229 | LPCSTR{ #function }, \ 230 | Util::force_cast_from(&function), \ 231 | PVOID{ nullptr }, \ 232 | ULONG{ min_build }, \ 233 | ULONG{ max_build }, \ 234 | } 235 | #define MAKE_FUNCTION_PROJECTION_TUPLE_BY_ALIAS(function, name, min_build, max_build) \ 236 | OpenGlass::ProjectionEntry \ 237 | { \ 238 | OpenGlass::ProjectionType::Function, \ 239 | LPCSTR{ name }, \ 240 | Util::force_cast_from(&function), \ 241 | PVOID{ nullptr }, \ 242 | ULONG{ min_build }, \ 243 | ULONG{ max_build }, \ 244 | } 245 | 246 | #define MAKE_VARIABLE_PROJECTION_TUPLE(variable, min_build, max_build) \ 247 | OpenGlass::ProjectionEntry \ 248 | { \ 249 | OpenGlass::ProjectionType::Variable, \ 250 | LPCSTR{ #variable }, \ 251 | Util::force_cast_from(&variable), \ 252 | PVOID{ nullptr }, \ 253 | ULONG{ min_build }, \ 254 | ULONG{ max_build }, \ 255 | } 256 | #define MAKE_VARIABLE_PROJECTION_TUPLE_BY_ALIAS(variable, name, min_build, max_build) \ 257 | OpenGlass::ProjectionEntry \ 258 | { \ 259 | OpenGlass::ProjectionType::Variable, \ 260 | LPCSTR{ name }, \ 261 | Util::force_cast_from(&variable), \ 262 | PVOID{ nullptr }, \ 263 | ULONG{ min_build }, \ 264 | ULONG{ max_build }, \ 265 | } 266 | 267 | #define MAKE_EMPTY_PROJECTION_TUPLE(name, min_build, max_build) \ 268 | OpenGlass::ProjectionEntry \ 269 | { \ 270 | OpenGlass::ProjectionType::Variable, \ 271 | LPCSTR{ name }, \ 272 | PVOID{ nullptr }, \ 273 | PVOID{ nullptr }, \ 274 | ULONG{ min_build }, \ 275 | ULONG{ max_build }, \ 276 | } 277 | 278 | #define MAKE_OPTIONAL_EMPTY_PROJECTION_TUPLE(name, min_build, max_build) \ 279 | OpenGlass::ProjectionEntry \ 280 | { \ 281 | static_cast(static_cast(OpenGlass::ProjectionType::Variable) | static_cast(OpenGlass::ProjectionType::Optional)), \ 282 | LPCSTR{ name }, \ 283 | PVOID{ nullptr }, \ 284 | PVOID{ nullptr }, \ 285 | ULONG{ min_build }, \ 286 | ULONG{ max_build }, \ 287 | } 288 | -------------------------------------------------------------------------------- /OpenGlass/dllmain.cpp: -------------------------------------------------------------------------------- 1 | #include "pch.h" 2 | #include "resource.h" 3 | #include "Util.hpp" 4 | #include "module.hpp" 5 | #if defined _M_X64 6 | #pragma comment(linker, "/manifestdependency:\"type='win32' name='Microsoft.Windows.Common-Controls' version='6.0.0.0' processorArchitecture='amd64' publicKeyToken='6595b64144ccf1df' language='*'\"") 7 | #else 8 | #error "This platform is currently not supported" 9 | #pragma comment(linker, "/manifestdependency:\"type='win32' name='Microsoft.Windows.Common-Controls' version='6.0.0.0' processorArchitecture='*' publicKeyToken='6595b64144ccf1df' language='*'\"") 10 | #endif 11 | 12 | 13 | _NODISCARD _Ret_notnull_ _Post_writable_byte_size_(size) _VCRT_ALLOCATOR 14 | [[nodiscard]] void* operator new(size_t size) noexcept(false) 15 | { 16 | auto memory = HeapAlloc(OpenGlass::Util::g_processHeap, 0, size); 17 | THROW_LAST_ERROR_IF_NULL(memory); 18 | return memory; 19 | } 20 | _NODISCARD _Ret_maybenull_ _Success_(return != NULL) _Post_writable_byte_size_(size) _VCRT_ALLOCATOR 21 | [[nodiscard]] void* operator new( 22 | size_t size, 23 | std::nothrow_t const& 24 | ) noexcept 25 | { 26 | return HeapAlloc(OpenGlass::Util::g_processHeap, 0, size); 27 | } 28 | _NODISCARD _Ret_notnull_ _Post_writable_byte_size_(size) _VCRT_ALLOCATOR 29 | [[nodiscard]] void* operator new[]( 30 | size_t size 31 | ) 32 | { 33 | auto memory = HeapAlloc(OpenGlass::Util::g_processHeap, 0, size); 34 | THROW_LAST_ERROR_IF_NULL(memory); 35 | return memory; 36 | } 37 | _NODISCARD _Ret_maybenull_ _Success_(return != NULL) _Post_writable_byte_size_(size) _VCRT_ALLOCATOR 38 | [[nodiscard]] void* operator new[]( 39 | size_t size, 40 | std::nothrow_t const& 41 | ) noexcept 42 | { 43 | return HeapAlloc(OpenGlass::Util::g_processHeap, 0, size); 44 | } 45 | void operator delete(void* ptr) noexcept 46 | { 47 | FAIL_FAST_IF_NULL(ptr); 48 | HeapFree(OpenGlass::Util::g_processHeap, 0, ptr); 49 | } 50 | void operator delete( 51 | void* ptr, 52 | std::nothrow_t const& 53 | ) noexcept 54 | { 55 | if (ptr) 56 | { 57 | HeapFree(OpenGlass::Util::g_processHeap, 0, ptr); 58 | } 59 | } 60 | void operator delete[]( 61 | void* ptr 62 | ) noexcept 63 | { 64 | FAIL_FAST_IF_NULL(ptr); 65 | HeapFree(OpenGlass::Util::g_processHeap, 0, ptr); 66 | } 67 | void operator delete[]( 68 | void* ptr, 69 | std::nothrow_t const& 70 | ) noexcept 71 | { 72 | if (ptr) 73 | { 74 | HeapFree(OpenGlass::Util::g_processHeap, 0, ptr); 75 | } 76 | } 77 | void operator delete( 78 | void* ptr, 79 | [[maybe_unused]] size_t size 80 | ) noexcept 81 | { 82 | FAIL_FAST_IF_NULL(ptr); 83 | HeapFree(OpenGlass::Util::g_processHeap, 0, ptr); 84 | } 85 | void operator delete[]( 86 | void* ptr, 87 | [[maybe_unused]] size_t size 88 | ) noexcept 89 | { 90 | FAIL_FAST_IF_NULL(ptr); 91 | HeapFree(OpenGlass::Util::g_processHeap, 0, ptr); 92 | } 93 | 94 | BOOL APIENTRY DllMain( 95 | HMODULE hModule, 96 | DWORD dwReason, 97 | [[maybe_unused]] LPVOID lpReserved 98 | ) 99 | { 100 | switch (dwReason) 101 | { 102 | case DLL_PROCESS_ATTACH: 103 | { 104 | DisableThreadLibraryCalls(hModule); 105 | break; 106 | } 107 | case DLL_PROCESS_DETACH: 108 | { 109 | break; 110 | } 111 | } 112 | return TRUE; 113 | } 114 | 115 | struct ExecutionParameters 116 | { 117 | enum class CommandAction : UCHAR 118 | { 119 | Unknown, 120 | Startup, 121 | Shutdown, 122 | Install, 123 | Uninstall, 124 | Help 125 | } type{ CommandAction::Unknown }; 126 | bool reserved{ false }; 127 | }; 128 | ExecutionParameters AnalyseCommandLine(LPCWSTR lpCmdLine) 129 | { 130 | int args{ 0 }; 131 | auto argv = CommandLineToArgvW(lpCmdLine, &args); 132 | ExecutionParameters params{}; 133 | 134 | for (int i = 0; i < args; i++) 135 | { 136 | if (!_wcsicmp(argv[i], L"/startup") || !_wcsicmp(argv[i], L"-startup") || !_wcsicmp(argv[i], L"--startup")) 137 | { 138 | params.type = ExecutionParameters::CommandAction::Startup; 139 | } 140 | if (!_wcsicmp(argv[i], L"/shutdown") || !_wcsicmp(argv[i], L"-shutdown") || !_wcsicmp(argv[i], L"--shutdown")) 141 | { 142 | params.type = ExecutionParameters::CommandAction::Shutdown; 143 | } 144 | if (!_wcsicmp(argv[i], L"/install") || !_wcsicmp(argv[i], L"/i") || !_wcsicmp(argv[i], L"-install") || !_wcsicmp(argv[i], L"-i") || !_wcsicmp(argv[i], L"--install")) 145 | { 146 | params.type = ExecutionParameters::CommandAction::Install; 147 | } 148 | if (!_wcsicmp(argv[i], L"/uninstall") || !_wcsicmp(argv[i], L"/u") || !_wcsicmp(argv[i], L"-uninstall") || !_wcsicmp(argv[i], L"-u") || !_wcsicmp(argv[i], L"--uninstall")) 149 | { 150 | params.type = ExecutionParameters::CommandAction::Uninstall; 151 | } 152 | if (!_wcsicmp(argv[i], L"/help") || !_wcsicmp(argv[i], L"/h") || !_wcsicmp(argv[i], L"-help") || !_wcsicmp(argv[i], L"-h") || !_wcsicmp(argv[i], L"--help") || !_wcsicmp(argv[i], L"-?") || !_wcsicmp(argv[i], L"/?")) 153 | { 154 | params.type = ExecutionParameters::CommandAction::Help; 155 | } 156 | } 157 | 158 | return params; 159 | } 160 | EXTERN_C int CALLBACK OpenGlass_RunDLL( 161 | [[maybe_unused]] HWND hWnd, 162 | [[maybe_unused]] HINSTANCE hInstance, 163 | LPCSTR lpCmdLine, 164 | [[maybe_unused]] int nCmdShow 165 | ) 166 | { 167 | using namespace OpenGlass; 168 | 169 | SetProcessDpiAwarenessContext(DPI_AWARENESS_CONTEXT_PER_MONITOR_AWARE_V2); 170 | RETURN_IF_FAILED(SetThreadDescription(GetCurrentThread(), L"OpenGlass Client Thread")); 171 | 172 | RETURN_IF_FAILED(RoInitialize(RO_INIT_MULTITHREADED)); 173 | wil::unique_rouninitialize_call wrtScope{}; 174 | 175 | // Convert the ansi string back to unicode string 176 | HRESULT hr{ S_OK }; 177 | std::unique_ptr convertedCommandLine{}; 178 | RETURN_IF_FAILED(Util::MB2WC(convertedCommandLine, lpCmdLine)); 179 | 180 | const auto to_error_string = [](HRESULT hr) static 181 | { 182 | return winrt::hresult_error{ hr }.message(); 183 | }; 184 | auto params = AnalyseCommandLine(convertedCommandLine.get()); 185 | switch (params.type) 186 | { 187 | case ExecutionParameters::CommandAction::Startup: 188 | { 189 | hr = StartupService(); 190 | if (FAILED(hr)) 191 | { 192 | Util::TaskDialog( 193 | nullptr, 194 | nullptr, 195 | nullptr, 196 | Util::GetResourceStringView().data(), 197 | to_error_string(hr).c_str(), 198 | TDCBF_CLOSE_BUTTON, 199 | TD_ERROR_ICON, 200 | nullptr 201 | ); 202 | } 203 | break; 204 | } 205 | case ExecutionParameters::CommandAction::Shutdown: 206 | { 207 | hr = ShutdownService(); 208 | if (true) 209 | { 210 | Util::TaskDialog( 211 | nullptr, 212 | nullptr, 213 | nullptr, 214 | Util::GetResourceStringView().data(), 215 | to_error_string(hr).c_str(), 216 | TDCBF_CLOSE_BUTTON, 217 | FAILED(hr) ? TD_ERROR_ICON : TD_INFORMATION_ICON, 218 | nullptr 219 | ); 220 | } 221 | break; 222 | } 223 | case ExecutionParameters::CommandAction::Install: 224 | { 225 | hr = InstallApp(); 226 | if (true) 227 | { 228 | Util::TaskDialog( 229 | nullptr, 230 | nullptr, 231 | nullptr, 232 | Util::GetResourceStringView().data(), 233 | to_error_string(hr).c_str(), 234 | TDCBF_CLOSE_BUTTON, 235 | FAILED(hr) ? TD_ERROR_ICON : TD_INFORMATION_ICON, 236 | nullptr 237 | ); 238 | } 239 | break; 240 | } 241 | case ExecutionParameters::CommandAction::Uninstall: 242 | { 243 | hr = UninstallApp(); 244 | if (true) 245 | { 246 | Util::TaskDialog( 247 | nullptr, 248 | nullptr, 249 | nullptr, 250 | Util::GetResourceStringView().data(), 251 | to_error_string(hr).c_str(), 252 | TDCBF_CLOSE_BUTTON, 253 | FAILED(hr) ? TD_ERROR_ICON : TD_INFORMATION_ICON, 254 | nullptr 255 | ); 256 | } 257 | break; 258 | } 259 | case ExecutionParameters::CommandAction::Help: 260 | { 261 | hr = S_OK; 262 | if (true) 263 | { 264 | Util::TaskDialog( 265 | nullptr, 266 | nullptr, 267 | nullptr, 268 | L"Help", 269 | L"--help, -help, -h, /h, -?, /?\n--startup, -startup, /startup\n--shutdown, -shutdown, /shutdown\n--install, -i, /install, /i\n--uninstall, -u, /uninstall, /u", 270 | TDCBF_OK_BUTTON, 271 | TD_INFORMATION_ICON, 272 | nullptr 273 | ); 274 | } 275 | break; 276 | } 277 | default: 278 | hr = E_INVALIDARG; 279 | if (true) 280 | { 281 | Util::TaskDialog( 282 | nullptr, 283 | nullptr, 284 | nullptr, 285 | Util::GetResourceStringView().data(), 286 | to_error_string(hr).c_str(), 287 | TDCBF_CLOSE_BUTTON, 288 | TD_ERROR_ICON, 289 | nullptr 290 | ); 291 | } 292 | break; 293 | } 294 | 295 | return hr; 296 | } 297 | -------------------------------------------------------------------------------- /OpenGlass/ReflectionRealizer.cpp: -------------------------------------------------------------------------------- 1 | #include "pch.h" 2 | #include "Shared.hpp" 3 | #include "uDWMProjection.hpp" 4 | #include "ReflectionRealizer.hpp" 5 | 6 | using namespace OpenGlass; 7 | 8 | HRESULT CReflectionRealizer::LoadTexture(ID2D1DeviceContext* context) 9 | { 10 | winrt::com_ptr stream{ nullptr }; 11 | if ( 12 | Shared::g_reflectionTexturePath.empty() || 13 | !PathFileExistsW(Shared::g_reflectionTexturePath.data()) 14 | ) 15 | { 16 | const auto currentModule = wil::GetModuleInstanceHandle(); 17 | const auto resourceHandle = FindResourceW(currentModule, MAKEINTRESOURCE(IDB_REFLECTION), L"PNG"); 18 | RETURN_LAST_ERROR_IF_NULL(resourceHandle); 19 | const auto globalHandle = LoadResource(currentModule, resourceHandle); 20 | RETURN_LAST_ERROR_IF_NULL(globalHandle); 21 | const auto cleanup = wil::scope_exit([=] 22 | { 23 | if (globalHandle) 24 | { 25 | UnlockResource(globalHandle); 26 | FreeResource(globalHandle); 27 | } 28 | }); 29 | const auto resourceSize = SizeofResource(currentModule, resourceHandle); 30 | RETURN_LAST_ERROR_IF(resourceSize == 0); 31 | const auto resourceAddress = reinterpret_cast(LockResource(globalHandle)); 32 | stream = { SHCreateMemStream(resourceAddress, resourceSize), winrt::take_ownership_from_abi }; 33 | } 34 | else 35 | { 36 | wil::unique_hfile file{ CreateFileW(Shared::g_reflectionTexturePath.data(), GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, 0) }; 37 | RETURN_LAST_ERROR_IF(!file.is_valid()); 38 | 39 | LARGE_INTEGER fileSize{}; 40 | RETURN_IF_WIN32_BOOL_FALSE(GetFileSizeEx(file.get(), &fileSize)); 41 | 42 | auto buffer{ std::make_unique(static_cast(fileSize.QuadPart)) }; 43 | RETURN_IF_WIN32_BOOL_FALSE(ReadFile(file.get(), buffer.get(), static_cast(fileSize.QuadPart), nullptr, nullptr)); 44 | stream = { SHCreateMemStream(buffer.get(), static_cast(fileSize.QuadPart)), winrt::take_ownership_from_abi }; 45 | } 46 | RETURN_HR_IF_NULL(E_OUTOFMEMORY, stream); 47 | 48 | winrt::com_ptr wicFactory{ nullptr }; 49 | wicFactory.copy_from(uDWM::CDesktopManager::GetInstance()->GetWICFactory()); 50 | winrt::com_ptr wicDecoder{ nullptr }; 51 | RETURN_IF_FAILED(wicFactory->CreateDecoderFromStream(stream.get(), &GUID_VendorMicrosoft, WICDecodeMetadataCacheOnDemand, wicDecoder.put())); 52 | winrt::com_ptr wicFrame{ nullptr }; 53 | RETURN_IF_FAILED(wicDecoder->GetFrame(0, wicFrame.put())); 54 | winrt::com_ptr wicConverter{ nullptr }; 55 | RETURN_IF_FAILED(wicFactory->CreateFormatConverter(wicConverter.put())); 56 | RETURN_IF_FAILED( 57 | wicConverter->Initialize( 58 | wicFrame.get(), 59 | GUID_WICPixelFormat32bppPBGRA, 60 | WICBitmapDitherTypeNone, 61 | nullptr, 62 | 0, 63 | WICBitmapPaletteTypeCustom 64 | ) 65 | ); 66 | 67 | RETURN_IF_FAILED( 68 | context->CreateBitmapFromWicBitmap( 69 | wicConverter.get(), 70 | D2D1::BitmapProperties1( 71 | D2D1_BITMAP_OPTIONS_NONE, 72 | D2D1::PixelFormat(DXGI_FORMAT_B8G8R8A8_UNORM, D2D1_ALPHA_MODE_PREMULTIPLIED) 73 | ), 74 | m_reflectionBitmap.put() 75 | ) 76 | ); 77 | 78 | return S_OK; 79 | } 80 | 81 | HRESULT CReflectionRealizer::Render( 82 | ID2D1DeviceContext* context, 83 | const CReflectionInput& input 84 | ) 85 | { 86 | if (!m_reflectionBitmap) 87 | { 88 | RETURN_IF_FAILED(LoadTexture(context)); 89 | } 90 | winrt::com_ptr contextForSpriteBatch{}; 91 | RETURN_IF_FAILED(context->QueryInterface(contextForSpriteBatch.put())); 92 | if (!m_spriteBatch) 93 | { 94 | RETURN_IF_FAILED(contextForSpriteBatch->CreateSpriteBatch(m_spriteBatch.put())); 95 | } 96 | 97 | const auto worldTransform3D = input.worldTransform->GetD3DMatrix(); 98 | auto worldTransform2DInversed = input.worldTransform->GetD2DMatrix(); 99 | D2D1InvertMatrix(&worldTransform2DInversed); 100 | 101 | const auto reflectionBitmapSize = m_reflectionBitmap->GetSize(); 102 | const D2D1_SIZE_F viewportSize 103 | { 104 | wil::rect_width(*input.viewport), 105 | wil::rect_height(*input.viewport) 106 | }; 107 | /*for (auto subRectangle : input.rectangles) 108 | { 109 | subRectangle = RectF::TransformRect(subRectangle, worldTransform2DInversed); 110 | if (RectF::IntersectUnsafe(subRectangle, *input.viewport)) 111 | { 112 | D2D1_RECT_F sourceRectangle 113 | { 114 | (subRectangle.left - input.viewport->left) / viewportSize.width * reflectionBitmapSize.width, 115 | (subRectangle.top - input.viewport->top) / viewportSize.height * reflectionBitmapSize.height, 116 | (subRectangle.right - input.viewport->left) / viewportSize.width * reflectionBitmapSize.width, 117 | (subRectangle.bottom - input.viewport->top) / viewportSize.height * reflectionBitmapSize.height, 118 | }; 119 | context->DrawBitmap( 120 | m_reflectionBitmap.get(), 121 | subRectangle, 122 | input.intensity, 123 | D2D1_INTERPOLATION_MODE_LINEAR, 124 | &sourceRectangle, 125 | &worldTransform3D 126 | ); 127 | } 128 | }*/ 129 | 130 | if (input.rectangles.size() == 1) 131 | { 132 | auto subRectangle = RectF::TransformRect(input.rectangles[0], worldTransform2DInversed); 133 | if (RectF::IntersectUnsafe(subRectangle, *input.viewport)) 134 | { 135 | D2D1_RECT_F sourceRectangle 136 | { 137 | (subRectangle.left - input.viewport->left) / viewportSize.width * reflectionBitmapSize.width, 138 | (subRectangle.top - input.viewport->top) / viewportSize.height * reflectionBitmapSize.height, 139 | (subRectangle.right - input.viewport->left) / viewportSize.width * reflectionBitmapSize.width, 140 | (subRectangle.bottom - input.viewport->top) / viewportSize.height * reflectionBitmapSize.height, 141 | }; 142 | context->DrawBitmap( 143 | m_reflectionBitmap.get(), 144 | subRectangle, 145 | input.intensity, 146 | D2D1_INTERPOLATION_MODE_LINEAR, 147 | &sourceRectangle, 148 | &worldTransform3D 149 | ); 150 | } 151 | } 152 | else 153 | { 154 | bool ignoreLayer{ input.intensity == 1.f }; 155 | if (!ignoreLayer) 156 | { 157 | context->PushLayer( 158 | D2D1::LayerParameters1( 159 | D2D1::InfiniteRect(), 160 | nullptr, 161 | D2D1_ANTIALIAS_MODE_ALIASED, 162 | D2D1::IdentityMatrix(), 163 | input.intensity, 164 | nullptr, 165 | D2D1_LAYER_OPTIONS1_NONE 166 | ), 167 | nullptr 168 | ); 169 | } 170 | 171 | struct CSpriteInfo 172 | { 173 | D2D1_RECT_F destinationRectangle; 174 | D2D1_RECT_U sourceRectangle; 175 | }; 176 | UINT32 spriteCount{}; 177 | auto spriteInfoArray = std::make_unique_for_overwrite(input.rectangles.size()); 178 | for (size_t i = 0; i < input.rectangles.size(); i++) 179 | { 180 | auto subRectangle = RectF::TransformRect(input.rectangles[i], worldTransform2DInversed); 181 | if (RectF::IntersectUnsafe(subRectangle, *input.viewport)) 182 | { 183 | spriteInfoArray[spriteCount].destinationRectangle = subRectangle; 184 | spriteInfoArray[spriteCount].sourceRectangle = 185 | { 186 | static_cast(std::round((subRectangle.left - input.viewport->left) / viewportSize.width * reflectionBitmapSize.width)), 187 | static_cast(std::round((subRectangle.top - input.viewport->top) / viewportSize.height * reflectionBitmapSize.height)), 188 | static_cast(std::round((subRectangle.right - input.viewport->left) / viewportSize.width * reflectionBitmapSize.width)), 189 | static_cast(std::round((subRectangle.bottom - input.viewport->top) / viewportSize.height * reflectionBitmapSize.height)), 190 | }; 191 | 192 | spriteCount += 1; 193 | } 194 | } 195 | const auto worldTransform2D = input.worldTransform->GetD2DMatrix(); 196 | m_spriteBatch->AddSprites( 197 | spriteCount, 198 | &spriteInfoArray[0].destinationRectangle, 199 | &spriteInfoArray[0].sourceRectangle, 200 | nullptr, 201 | &worldTransform2D, 202 | sizeof(CSpriteInfo), 203 | sizeof(CSpriteInfo), 204 | 0U, 205 | 0U 206 | ); 207 | 208 | const auto primitiveBlend = contextForSpriteBatch->GetPrimitiveBlend(); 209 | const auto antialiasMode = contextForSpriteBatch->GetAntialiasMode(); 210 | if (!ignoreLayer) 211 | { 212 | contextForSpriteBatch->SetPrimitiveBlend(D2D1_PRIMITIVE_BLEND_COPY); 213 | } 214 | contextForSpriteBatch->SetAntialiasMode(D2D1_ANTIALIAS_MODE_ALIASED); 215 | contextForSpriteBatch->DrawSpriteBatch(m_spriteBatch.get(), m_reflectionBitmap.get()); 216 | contextForSpriteBatch->SetAntialiasMode(antialiasMode); 217 | if (!ignoreLayer) 218 | { 219 | contextForSpriteBatch->SetPrimitiveBlend(primitiveBlend); 220 | } 221 | m_spriteBatch->Clear(); 222 | 223 | if (!ignoreLayer) 224 | { 225 | context->PopLayer(); 226 | } 227 | } 228 | 229 | return S_OK; 230 | } 231 | -------------------------------------------------------------------------------- /OpenGlass/CustomBlurEffect.cpp: -------------------------------------------------------------------------------- 1 | #include "pch.h" 2 | #include "CustomBlurEffect.hpp" 3 | #include "D2DPrivates.hpp" 4 | #include "Util.hpp" 5 | 6 | using namespace OpenGlass; 7 | const float CCustomBlurEffect::k_optimizations[16] 8 | { 9 | 8.f, 6.f, 1.5f, 2.5f, D2D1_SCALE_INTERPOLATION_MODE_LINEAR, 10 | 8.f, 6.f, 1.5f, 2.5f, D2D1_SCALE_INTERPOLATION_MODE_MULTI_SAMPLE_LINEAR, 11 | 12.f, 6.f, 2.f, 3.f, D2D1_SCALE_INTERPOLATION_MODE_MULTI_SAMPLE_LINEAR, 12 | 0.f 13 | }; 14 | 15 | float CCustomBlurEffect::DetermineOutputScale( 16 | float size 17 | ) 18 | { 19 | float outputScale{ 1.f }; 20 | if (size > 1.0) 21 | { 22 | const auto k = m_blurAmount <= k_optimizations[5 * static_cast(m_optimization) + 2] ? 1.f : 0.5f; 23 | outputScale = k * std::max( 24 | 0.1f, 25 | std::min( 26 | 1.f, 27 | k_optimizations[5 * static_cast(m_optimization)] / (m_blurAmount + k_optimizations[5 * static_cast(m_optimization) + 1]) 28 | ) 29 | ); 30 | if (outputScale * size < 1.f) 31 | { 32 | return 1.f / size; 33 | } 34 | } 35 | return outputScale; 36 | } 37 | 38 | HRESULT CCustomBlurEffect::Initialize(ID2D1DeviceContext* context) 39 | { 40 | RETURN_IF_FAILED( 41 | context->CreateEffect( 42 | CLSID_D2D1Crop, 43 | m_cropInputEffect.put() 44 | ) 45 | ); 46 | RETURN_IF_FAILED( 47 | context->CreateEffect( 48 | CLSID_D2D1Scale, 49 | m_scaleDownEffect.put() 50 | ) 51 | ); 52 | RETURN_IF_FAILED( 53 | context->CreateEffect( 54 | CLSID_D2D1Crop, 55 | m_cropAlignEffect.put() 56 | ) 57 | ); 58 | RETURN_IF_FAILED( 59 | context->CreateEffect( 60 | CLSID_D2D1Border, 61 | m_borderEffect.put() 62 | ) 63 | ); 64 | RETURN_IF_FAILED( 65 | context->CreateEffect( 66 | CLSID_D2D1DirectionalBlurKernel, 67 | m_directionalBlurXEffect.put() 68 | ) 69 | ); 70 | RETURN_IF_FAILED( 71 | context->CreateEffect( 72 | CLSID_D2D1DirectionalBlurKernel, 73 | m_directionalBlurYEffect.put() 74 | ) 75 | ); 76 | 77 | RETURN_IF_FAILED( 78 | m_cropInputEffect->SetValue( 79 | D2D1_CROP_PROP_BORDER_MODE, 80 | D2D1_BORDER_MODE_HARD 81 | ) 82 | ); 83 | 84 | RETURN_IF_FAILED( 85 | m_scaleDownEffect->SetValue( 86 | D2D1_SCALE_PROP_BORDER_MODE, 87 | D2D1_BORDER_MODE_HARD 88 | ) 89 | ); 90 | m_scaleDownEffect->SetInputEffect(0, m_cropInputEffect.get()); 91 | 92 | RETURN_IF_FAILED( 93 | m_cropAlignEffect->SetValue( 94 | D2D1_CROP_PROP_BORDER_MODE, 95 | D2D1_BORDER_MODE_HARD 96 | ) 97 | ); 98 | m_cropAlignEffect->SetInputEffect(0, m_scaleDownEffect.get()); 99 | 100 | RETURN_IF_FAILED( 101 | m_borderEffect->SetValue( 102 | D2D1_BORDER_PROP_EDGE_MODE_X, 103 | D2D1_BORDER_EDGE_MODE_MIRROR 104 | ) 105 | ); 106 | RETURN_IF_FAILED( 107 | m_borderEffect->SetValue( 108 | D2D1_BORDER_PROP_EDGE_MODE_Y, 109 | D2D1_BORDER_EDGE_MODE_MIRROR 110 | ) 111 | ); 112 | m_borderEffect->SetInputEffect(0, m_cropAlignEffect.get()); 113 | 114 | m_directionalBlurXEffect->SetInputEffect(0, m_borderEffect.get()); 115 | RETURN_IF_FAILED( 116 | m_directionalBlurXEffect->SetValue( 117 | D2D1_DIRECTIONALBLURKERNEL_PROP_DIRECTION, 118 | D2D1_DIRECTIONALBLURKERNEL_DIRECTION_X 119 | ) 120 | ); 121 | 122 | m_directionalBlurYEffect->SetInputEffect(0, m_directionalBlurXEffect.get()); 123 | RETURN_IF_FAILED( 124 | m_directionalBlurYEffect->SetValue( 125 | D2D1_DIRECTIONALBLURKERNEL_PROP_DIRECTION, 126 | D2D1_DIRECTIONALBLURKERNEL_DIRECTION_Y 127 | ) 128 | ); 129 | 130 | m_initialized = true; 131 | 132 | return S_OK; 133 | } 134 | 135 | HRESULT CCustomBlurEffect::CalculateAndSetEffectParams(const D2D1_RECT_F& imageRectangle) 136 | { 137 | RETURN_IF_FAILED( 138 | m_cropInputEffect->SetValue( 139 | D2D1_CROP_PROP_RECT, 140 | imageRectangle 141 | ) 142 | ); 143 | m_prescaleAmount = 144 | { 145 | DetermineOutputScale(wil::rect_width(imageRectangle)), 146 | DetermineOutputScale(wil::rect_height(imageRectangle)) 147 | }; 148 | 149 | D2D1_VECTOR_2F finalBlurAmount{ m_blurAmount, m_blurAmount }; 150 | auto finalPrescaleAmount = m_prescaleAmount; 151 | 152 | m_offset = {}; 153 | if (m_prescaleAmount.x != 1.f && finalBlurAmount.x > k_optimizations[5 * static_cast(m_optimization) + 2]) 154 | { 155 | if (m_prescaleAmount.x <= 0.5f) 156 | { 157 | finalPrescaleAmount.x *= 2.f; 158 | m_offset.x = 0.25f; 159 | } 160 | } 161 | if (m_prescaleAmount.y != 1.f && finalBlurAmount.y > k_optimizations[5 * static_cast(m_optimization) + 2]) 162 | { 163 | if (m_prescaleAmount.y <= 0.5f) 164 | { 165 | finalPrescaleAmount.y *= 2.f; 166 | m_offset.y = 0.25f; 167 | } 168 | } 169 | 170 | RETURN_IF_FAILED( 171 | m_scaleDownEffect->SetValue( 172 | D2D1_SCALE_PROP_INTERPOLATION_MODE, 173 | static_cast(k_optimizations[5 * m_optimization + 4]) 174 | ) 175 | ); 176 | RETURN_IF_FAILED( 177 | m_scaleDownEffect->SetValue( 178 | D2D1_SCALE_PROP_SCALE, 179 | finalPrescaleAmount 180 | ) 181 | ); 182 | 183 | auto alignedImageRectangle = imageRectangle; 184 | alignedImageRectangle.right = alignedImageRectangle.right * finalPrescaleAmount.x - 1.f; 185 | alignedImageRectangle.bottom = alignedImageRectangle.bottom * finalPrescaleAmount.y - 1.f; 186 | alignedImageRectangle.left = alignedImageRectangle.left * finalPrescaleAmount.x + 1.f; 187 | alignedImageRectangle.top = alignedImageRectangle.top * finalPrescaleAmount.y + 1.f; 188 | if (wil::rect_width(alignedImageRectangle) < 1.f) 189 | { 190 | alignedImageRectangle.left = (imageRectangle.left + imageRectangle.right) / 2.f * finalPrescaleAmount.x - 0.5f; 191 | alignedImageRectangle.right = alignedImageRectangle.left + 1.f; 192 | } 193 | if (wil::rect_height(alignedImageRectangle) < 1.f) 194 | { 195 | alignedImageRectangle.top = (imageRectangle.top + imageRectangle.bottom) / 2.f * finalPrescaleAmount.y - 0.5f; 196 | alignedImageRectangle.bottom = alignedImageRectangle.top + 1.f; 197 | } 198 | RETURN_IF_FAILED( 199 | m_cropAlignEffect->SetValue( 200 | D2D1_CROP_PROP_RECT, 201 | alignedImageRectangle 202 | ) 203 | ); 204 | 205 | finalBlurAmount = D2D1::Vector2F( 206 | finalBlurAmount.x * finalPrescaleAmount.x, 207 | finalBlurAmount.y * finalPrescaleAmount.y 208 | ); 209 | 210 | RETURN_IF_FAILED( 211 | m_directionalBlurXEffect->SetValue( 212 | D2D1_DIRECTIONALBLURKERNEL_PROP_STANDARD_DEVIATION, 213 | finalBlurAmount.x 214 | ) 215 | ); 216 | RETURN_IF_FAILED( 217 | m_directionalBlurXEffect->SetValue( 218 | D2D1_DIRECTIONALBLURKERNEL_PROP_KERNEL_RANGE_FACTOR, 219 | k_optimizations[5 * m_optimization + 3] 220 | ) 221 | ); 222 | RETURN_IF_FAILED( 223 | m_directionalBlurXEffect->SetValue( 224 | D2D1_DIRECTIONALBLURKERNEL_PROP_OPTIMIZATION_TRANSFORM, 225 | (m_prescaleAmount.x != finalPrescaleAmount.x) ? D2D1_DIRECTIONALBLURKERNEL_OPTIMIZATION_TRANSFORM_SCALE : D2D1_DIRECTIONALBLURKERNEL_OPTIMIZATION_TRANSFORM_IDENDITY 226 | ) 227 | ); 228 | RETURN_IF_FAILED( 229 | m_directionalBlurYEffect->SetValue( 230 | D2D1_DIRECTIONALBLURKERNEL_PROP_STANDARD_DEVIATION, 231 | finalBlurAmount.y 232 | ) 233 | ); 234 | RETURN_IF_FAILED( 235 | m_directionalBlurYEffect->SetValue( 236 | D2D1_DIRECTIONALBLURKERNEL_PROP_KERNEL_RANGE_FACTOR, 237 | k_optimizations[5 * m_optimization + 3] 238 | ) 239 | ); 240 | RETURN_IF_FAILED( 241 | m_directionalBlurYEffect->SetValue( 242 | D2D1_DIRECTIONALBLURKERNEL_PROP_OPTIMIZATION_TRANSFORM, 243 | (m_prescaleAmount.y != finalPrescaleAmount.y) ? D2D1_DIRECTIONALBLURKERNEL_OPTIMIZATION_TRANSFORM_SCALE : D2D1_DIRECTIONALBLURKERNEL_OPTIMIZATION_TRANSFORM_IDENDITY 244 | ) 245 | ); 246 | 247 | return S_OK; 248 | } 249 | 250 | HRESULT STDMETHODCALLTYPE CCustomBlurEffect::Build( 251 | ID2D1DeviceContext* context, 252 | ID2D1Image* inputImage, 253 | const D2D1_RECT_F& imageRectangle, 254 | const void* additionalParams 255 | ) 256 | { 257 | if (!m_initialized) 258 | { 259 | RETURN_IF_FAILED(Initialize(context)); 260 | } 261 | 262 | m_cropInputEffect->SetInput(0, inputImage); 263 | 264 | bool recalculateParams{ true }; 265 | do 266 | { 267 | const auto params = static_cast(additionalParams); 268 | 269 | if (params->blurAmount == 0.f) [[unlikely]] 270 | { 271 | m_blurAmount = 0.f; 272 | RETURN_IF_FAILED( 273 | m_cropInputEffect->SetValue( 274 | D2D1_CROP_PROP_RECT, 275 | imageRectangle 276 | ) 277 | ); 278 | return S_OK; 279 | } 280 | 281 | RETURN_IF_FAILED( 282 | m_cropAlignEffect->SetValue( 283 | D2D1_PROPERTY_CACHED, 284 | static_cast(params->cachePrescaledImage) 285 | ) 286 | ); 287 | if (m_blurAmount != params->blurAmount) 288 | { 289 | m_blurAmount = params->blurAmount; 290 | break; 291 | } 292 | if (m_optimization != params->optimization) 293 | { 294 | m_optimization = params->optimization; 295 | break; 296 | } 297 | 298 | D2D1_RECT_F m_imageRectangle; 299 | RETURN_IF_FAILED(m_cropInputEffect->GetValue(D2D1_CROP_PROP_RECT, &m_imageRectangle)); 300 | if (memcmp(&m_imageRectangle, &imageRectangle, sizeof(D2D1_RECT_F)) != 0) 301 | { 302 | break; 303 | } 304 | 305 | recalculateParams = false; 306 | } while (false); 307 | 308 | if (recalculateParams) 309 | { 310 | RETURN_IF_FAILED( 311 | CalculateAndSetEffectParams( 312 | imageRectangle 313 | ) 314 | ); 315 | } 316 | 317 | return S_OK; 318 | } 319 | 320 | D2D1_MATRIX_3X2_F STDMETHODCALLTYPE CCustomBlurEffect::GetOutputMatrix() const 321 | { 322 | if (m_blurAmount == 0.f) 323 | { 324 | return D2D1::IdentityMatrix(); 325 | } 326 | 327 | return D2D1::Matrix3x2F::Scale( 328 | D2D1::SizeF( 329 | 1.f / m_prescaleAmount.x, 330 | 1.f / m_prescaleAmount.y 331 | ) 332 | ); 333 | } 334 | 335 | void STDMETHODCALLTYPE CCustomBlurEffect::GetOutput(ID2D1Image** output) const 336 | { 337 | if (m_blurAmount == 0.f) 338 | { 339 | m_cropInputEffect->GetOutput(output); 340 | } 341 | else 342 | { 343 | m_directionalBlurYEffect->GetOutput(output); 344 | } 345 | } 346 | 347 | void STDMETHODCALLTYPE CCustomBlurEffect::Reset() 348 | { 349 | if (m_cropInputEffect) 350 | { 351 | m_cropInputEffect->SetInput(0, nullptr); 352 | } 353 | } 354 | -------------------------------------------------------------------------------- /OpenGlass/module.cpp: -------------------------------------------------------------------------------- 1 | #include "pch.h" 2 | #include "resource.h" 3 | #include "Util.hpp" 4 | #include "GlassService.hpp" 5 | #include "TaskHandler.hpp" 6 | 7 | _Use_decl_annotations_ STDAPI DllGetClassObject(REFCLSID rclsid, REFIID riid, LPVOID* ppv) 8 | { 9 | using namespace OpenGlass; 10 | 11 | if (ppv) 12 | { 13 | *ppv = nullptr; 14 | } 15 | if ( 16 | GetModuleHandleW(L"dllhost.exe") != GetModuleHandleW(nullptr) || 17 | !Util::IsRunAsLocalSystem() 18 | ) 19 | { 20 | return E_ACCESSDENIED; 21 | } 22 | if (rclsid == CLSID_TaskHandler) 23 | { 24 | return winrt::make>().as(riid, ppv); 25 | } 26 | 27 | return CLASS_E_CLASSNOTAVAILABLE; 28 | } 29 | 30 | _Use_decl_annotations_ STDAPI DllCanUnloadNow() 31 | { 32 | if (winrt::get_module_lock()) 33 | { 34 | return S_FALSE; 35 | } 36 | 37 | winrt::clear_factory_cache(); 38 | return S_OK; 39 | } 40 | 41 | STDAPI DllRegisterServer() 42 | { 43 | return E_NOTIMPL; 44 | } 45 | 46 | STDAPI DllUnregisterServer() 47 | { 48 | return E_NOTIMPL; 49 | } 50 | 51 | STDAPI StartupService() noexcept 52 | { 53 | using namespace OpenGlass; 54 | 55 | if (GlassService::IsRunning()) 56 | { 57 | RETURN_WIN32(ERROR_SERVICE_ALREADY_RUNNING); 58 | } 59 | 60 | winrt::com_ptr taskService{ nullptr }; 61 | RETURN_IF_FAILED( 62 | CoCreateInstance( 63 | CLSID_TaskScheduler, 64 | nullptr, 65 | CLSCTX_INPROC_SERVER, 66 | IID_PPV_ARGS(taskService.put()) 67 | ) 68 | ); 69 | RETURN_IF_FAILED(taskService->Connect(_variant_t{}, _variant_t{}, _variant_t{}, _variant_t{})); 70 | 71 | winrt::com_ptr rootFolder{ nullptr }; 72 | RETURN_IF_FAILED(taskService->GetFolder(_bstr_t{ "\\" }, rootFolder.put())); 73 | 74 | winrt::com_ptr registeredTask{ nullptr }; 75 | HRESULT hr 76 | { 77 | rootFolder->GetTask( 78 | _bstr_t{L"OpenGlass Host"}, 79 | registeredTask.put() 80 | ) 81 | }; 82 | RETURN_IF_FAILED(hr == HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND) ? HRESULT_FROM_WIN32(ERROR_SERVICE_DOES_NOT_EXIST) : hr); 83 | 84 | VARIANT_BOOL enabled{ FALSE }; 85 | RETURN_IF_FAILED(registeredTask->get_Enabled(&enabled)); 86 | RETURN_HR_IF(SCHED_E_TASK_DISABLED, !enabled); 87 | 88 | [[maybe_unused]] winrt::com_ptr runningTask{ nullptr }; 89 | // TASK_RUN_IGNORE_CONSTRAINTS is required otherwise the task will be queued instead of directly run when battery saver is on 90 | RETURN_IF_FAILED(registeredTask->RunEx(_variant_t{}, TASK_RUN_IGNORE_CONSTRAINTS, 0, _bstr_t{}, runningTask.put())); 91 | 92 | LONG lastTaskResult{}; 93 | RETURN_IF_FAILED(registeredTask->get_LastTaskResult(&lastTaskResult)); 94 | 95 | return lastTaskResult; 96 | } 97 | STDAPI ShutdownService() noexcept 98 | { 99 | using namespace OpenGlass; 100 | 101 | if (!GlassService::IsRunning()) 102 | { 103 | RETURN_WIN32(ERROR_SERVICE_NOT_ACTIVE); 104 | } 105 | 106 | winrt::com_ptr taskService{ nullptr }; 107 | RETURN_IF_FAILED( 108 | CoCreateInstance( 109 | CLSID_TaskScheduler, 110 | nullptr, 111 | CLSCTX_INPROC_SERVER, 112 | IID_PPV_ARGS(taskService.put()) 113 | ) 114 | ); 115 | RETURN_IF_FAILED(taskService->Connect(_variant_t{}, _variant_t{}, _variant_t{}, _variant_t{})); 116 | 117 | winrt::com_ptr rootFolder{ nullptr }; 118 | RETURN_IF_FAILED(taskService->GetFolder(_bstr_t{ "\\" }, rootFolder.put())); 119 | 120 | winrt::com_ptr registeredTask{ nullptr }; 121 | HRESULT hr 122 | { 123 | rootFolder->GetTask( 124 | _bstr_t{L"OpenGlass Host"}, 125 | registeredTask.put() 126 | ) 127 | }; 128 | RETURN_IF_FAILED(hr == HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND) ? HRESULT_FROM_WIN32(ERROR_SERVICE_DOES_NOT_EXIST) : hr); 129 | 130 | RETURN_IF_FAILED(registeredTask->Stop(0)); 131 | 132 | return S_OK; 133 | } 134 | STDAPI InstallApp() noexcept 135 | { 136 | using namespace OpenGlass; 137 | 138 | winrt::com_ptr taskService{ nullptr }; 139 | RETURN_IF_FAILED( 140 | CoCreateInstance( 141 | CLSID_TaskScheduler, 142 | nullptr, 143 | CLSCTX_INPROC_SERVER, 144 | IID_PPV_ARGS(taskService.put()) 145 | ) 146 | ); 147 | RETURN_IF_FAILED(taskService->Connect(_variant_t{}, _variant_t{}, _variant_t{}, _variant_t{})); 148 | 149 | winrt::com_ptr rootFolder{ nullptr }; 150 | RETURN_IF_FAILED(taskService->GetFolder(_bstr_t{ "\\" }, rootFolder.put())); 151 | 152 | winrt::com_ptr taskDefinition{ nullptr }; 153 | RETURN_IF_FAILED(taskService->NewTask(0, taskDefinition.put())); 154 | 155 | winrt::com_ptr regInfo{ nullptr }; 156 | RETURN_IF_FAILED(taskDefinition->get_RegistrationInfo(regInfo.put())); 157 | RETURN_IF_FAILED(regInfo->put_Author(_bstr_t{ L"ALTaleX" })); 158 | RETURN_IF_FAILED(regInfo->put_Description(_bstr_t{ OpenGlass::Util::GetResourceStringView().data() })); 159 | 160 | { 161 | winrt::com_ptr principal{ nullptr }; 162 | RETURN_IF_FAILED(taskDefinition->get_Principal(principal.put())); 163 | 164 | RETURN_IF_FAILED(principal->put_UserId(_bstr_t{ L"SYSTEM" })); 165 | RETURN_IF_FAILED(principal->put_LogonType(TASK_LOGON_SERVICE_ACCOUNT)); 166 | RETURN_IF_FAILED(principal->put_DisplayName(_bstr_t{ L"SYSTEM" })); 167 | RETURN_IF_FAILED(principal->put_RunLevel(TASK_RUNLEVEL_HIGHEST)); 168 | } 169 | 170 | { 171 | winrt::com_ptr setting{ nullptr }; 172 | RETURN_IF_FAILED(taskDefinition->get_Settings(setting.put())); 173 | 174 | RETURN_IF_FAILED(setting->put_StopIfGoingOnBatteries(VARIANT_FALSE)); 175 | RETURN_IF_FAILED(setting->put_DisallowStartIfOnBatteries(VARIANT_FALSE)); 176 | RETURN_IF_FAILED(setting->put_AllowDemandStart(VARIANT_TRUE)); 177 | RETURN_IF_FAILED(setting->put_AllowHardTerminate(VARIANT_TRUE)); 178 | RETURN_IF_FAILED(setting->put_StartWhenAvailable(VARIANT_FALSE)); 179 | RETURN_IF_FAILED(setting->put_MultipleInstances(TASK_INSTANCES_IGNORE_NEW)); 180 | } 181 | 182 | { 183 | winrt::com_ptr comHandlerAction{ nullptr }; 184 | { 185 | winrt::com_ptr action{ nullptr }; 186 | { 187 | winrt::com_ptr actionColl{ nullptr }; 188 | RETURN_IF_FAILED(taskDefinition->get_Actions(actionColl.put())); 189 | RETURN_IF_FAILED(actionColl->Create(TASK_ACTION_COM_HANDLER, action.put())); 190 | } 191 | RETURN_HR_IF(E_NOINTERFACE, action.try_as(comHandlerAction) == false); 192 | } 193 | 194 | std::wstring modulePath{}; 195 | RETURN_IF_FAILED((wil::GetModuleFileNameW(wil::GetModuleInstanceHandle(), modulePath))); 196 | 197 | RETURN_IF_FAILED(comHandlerAction->put_ClassId(_bstr_t{ CLSID_TaskHandler_STR })); 198 | RETURN_IF_FAILED(comHandlerAction->put_Data(_bstr_t{})); 199 | } 200 | 201 | winrt::com_ptr triggerColl{ nullptr }; 202 | RETURN_IF_FAILED(taskDefinition->get_Triggers(triggerColl.put())); 203 | 204 | winrt::com_ptr trigger{ nullptr }; 205 | RETURN_IF_FAILED(triggerColl->Create(TASK_TRIGGER_BOOT, trigger.put())); 206 | 207 | winrt::com_ptr registeredTask{ nullptr }; 208 | RETURN_IF_FAILED( 209 | rootFolder->RegisterTaskDefinition( 210 | _bstr_t{ L"OpenGlass Host" }, 211 | taskDefinition.get(), 212 | TASK_CREATE_OR_UPDATE, 213 | _variant_t{}, 214 | _variant_t{}, 215 | TASK_LOGON_NONE, 216 | _variant_t{}, 217 | registeredTask.put() 218 | ) 219 | ); 220 | 221 | wil::unique_hkey key{ nullptr }; 222 | // HKCR.AppID.{} 223 | RETURN_IF_FAILED( 224 | wil::reg::create_unique_key_nothrow( 225 | HKEY_CLASSES_ROOT, 226 | (std::wstring{ L"AppID\\" } + CLSID_TaskHandler_STR).c_str(), 227 | key, 228 | wil::reg::key_access::readwrite 229 | ) 230 | ); 231 | RETURN_IF_FAILED( 232 | wil::reg::set_value_string_nothrow( 233 | key.get(), 234 | nullptr, 235 | L"OpenGlass Host" 236 | ) 237 | ); 238 | RETURN_IF_FAILED( 239 | wil::reg::set_value_string_nothrow( 240 | key.get(), 241 | L"DllSurrogate", 242 | L"" 243 | ) 244 | ); 245 | // HKCR.CLSID.{} 246 | RETURN_IF_FAILED( 247 | wil::reg::create_unique_key_nothrow( 248 | HKEY_CLASSES_ROOT, 249 | (std::wstring{ L"CLSID\\" } + CLSID_TaskHandler_STR).c_str(), 250 | key, 251 | wil::reg::key_access::readwrite 252 | ) 253 | ); 254 | RETURN_IF_FAILED( 255 | wil::reg::set_value_string_nothrow( 256 | key.get(), 257 | nullptr, 258 | L"OpenGlass Host" 259 | ) 260 | ); 261 | RETURN_IF_FAILED( 262 | wil::reg::set_value_string_nothrow( 263 | key.get(), 264 | L"AppID", 265 | CLSID_TaskHandler_STR 266 | ) 267 | ); 268 | // HKCR.CLSID.{}.InProcServer32 269 | RETURN_IF_FAILED( 270 | wil::reg::create_unique_key_nothrow( 271 | HKEY_CLASSES_ROOT, 272 | (std::wstring{ L"CLSID\\" } + CLSID_TaskHandler_STR + L"\\InProcServer32").c_str(), 273 | key, 274 | wil::reg::key_access::readwrite 275 | ) 276 | ); 277 | RETURN_IF_FAILED( 278 | wil::reg::set_value_string_nothrow( 279 | key.get(), 280 | nullptr, 281 | Util::g_thisModulePath.c_str() 282 | ) 283 | ); 284 | RETURN_IF_FAILED( 285 | wil::reg::set_value_string_nothrow( 286 | key.get(), 287 | L"ThreadingModel", 288 | L"Both" 289 | ) 290 | ); 291 | 292 | return S_OK; 293 | } 294 | 295 | STDAPI UninstallApp() noexcept 296 | { 297 | using namespace OpenGlass; 298 | 299 | RETURN_IF_FAILED( 300 | SHDeleteKeyW( 301 | HKEY_CLASSES_ROOT, 302 | (std::wstring{ L"CLSID\\" } + CLSID_TaskHandler_STR).c_str() 303 | ) 304 | ); 305 | RETURN_IF_FAILED( 306 | SHDeleteKeyW( 307 | HKEY_CLASSES_ROOT, 308 | (std::wstring{ L"AppID\\" } + CLSID_TaskHandler_STR).c_str() 309 | ) 310 | ); 311 | 312 | winrt::com_ptr taskService{ nullptr }; 313 | RETURN_IF_FAILED( 314 | CoCreateInstance( 315 | CLSID_TaskScheduler, 316 | nullptr, 317 | CLSCTX_INPROC_SERVER, 318 | IID_PPV_ARGS(taskService.put()) 319 | ) 320 | ); 321 | RETURN_IF_FAILED(taskService->Connect(_variant_t{}, _variant_t{}, _variant_t{}, _variant_t{})); 322 | 323 | winrt::com_ptr rootFolder{ nullptr }; 324 | RETURN_IF_FAILED(taskService->GetFolder(_bstr_t{ "\\" }, rootFolder.put())); 325 | 326 | HRESULT hr 327 | { 328 | rootFolder->DeleteTask( 329 | _bstr_t{ L"OpenGlass Host" }, 330 | 0 331 | ) 332 | }; 333 | RETURN_IF_FAILED(hr == HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND) ? HRESULT_FROM_WIN32(ERROR_SERVICE_DOES_NOT_EXIST) : hr); 334 | 335 | return S_OK; 336 | } 337 | -------------------------------------------------------------------------------- /OpenGlass/HookHelper.cpp: -------------------------------------------------------------------------------- 1 | #include "pch.h" 2 | #include "HookHelper.hpp" 3 | #include "detours.h" 4 | 5 | using namespace OpenGlass; 6 | namespace OpenGlass::HookHelper::Detours 7 | { 8 | // Begin to install hooks 9 | HRESULT Begin(); 10 | // End attaching 11 | HRESULT End(bool commit = true); 12 | } 13 | 14 | void HookHelper::PatchInstructions(void* memory, const UCHAR* data, size_t length) 15 | { 16 | auto unprotectedScope = HookHelper::unprotect(memory, length); 17 | memcpy_s( 18 | memory, 19 | length, 20 | data, 21 | length 22 | ); 23 | THROW_IF_WIN32_BOOL_FALSE(FlushInstructionCache(GetCurrentProcess(), memory, length)); 24 | } 25 | void HookHelper::WritePointerInternal(PVOID* pointerAddress, PVOID value, PVOID* originalValue) 26 | { 27 | auto unprotectedScope = HookHelper::unprotect(pointerAddress, sizeof(value)); 28 | if (originalValue) 29 | { 30 | *originalValue = InterlockedExchangePointer(pointerAddress, value);; 31 | } 32 | else 33 | { 34 | InterlockedExchangePointer(pointerAddress, value); 35 | } 36 | } 37 | 38 | HMODULE HookHelper::GetProcessModule(HANDLE processHandle, std::wstring_view dllPath) 39 | { 40 | HMODULE targetModule{ nullptr }; 41 | DWORD bytesNeeded{ 0 }; 42 | if (!EnumProcessModules(processHandle, nullptr, 0, &bytesNeeded)) 43 | { 44 | return targetModule; 45 | } 46 | DWORD moduleCount{ bytesNeeded / sizeof(HMODULE) }; 47 | auto moduleList = std::make_unique_for_overwrite(moduleCount); 48 | if (!EnumProcessModules(processHandle, moduleList.get(), bytesNeeded, &bytesNeeded)) 49 | { 50 | return targetModule; 51 | } 52 | 53 | for (DWORD i = 0; i < moduleCount; i++) 54 | { 55 | HMODULE moduleHandle{ moduleList[i] }; 56 | std::wstring modulePath{}; 57 | if (FAILED((wil::GetModuleFileNameExW(processHandle, moduleHandle, modulePath)))) 58 | { 59 | continue; 60 | } 61 | 62 | if (!_wcsicmp(modulePath.data(), dllPath.data())) 63 | { 64 | targetModule = moduleHandle; 65 | break; 66 | } 67 | } 68 | 69 | return targetModule; 70 | } 71 | 72 | void HookHelper::WalkIAT(PVOID baseAddress, std::string_view dllName, std::function callback) try 73 | { 74 | THROW_HR_IF(E_INVALIDARG, dllName.empty()); 75 | THROW_HR_IF_NULL(E_INVALIDARG, baseAddress); 76 | THROW_HR_IF_NULL(E_INVALIDARG, callback); 77 | 78 | ULONG size{ 0ul }; 79 | auto importDescriptor = static_cast( 80 | ImageDirectoryEntryToData( 81 | baseAddress, 82 | TRUE, 83 | IMAGE_DIRECTORY_ENTRY_IMPORT, 84 | &size 85 | ) 86 | ); 87 | 88 | THROW_HR_IF_NULL(E_INVALIDARG, importDescriptor); 89 | 90 | bool found = false; 91 | while (importDescriptor->Name) 92 | { 93 | auto moduleName = reinterpret_cast(reinterpret_cast(baseAddress) + importDescriptor->Name); 94 | 95 | if (!_stricmp(moduleName, dllName.data())) 96 | { 97 | found = true; 98 | break; 99 | } 100 | 101 | importDescriptor++; 102 | } 103 | 104 | THROW_HR_IF(HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND), !found); 105 | 106 | auto thunk = reinterpret_cast(reinterpret_cast(baseAddress) + importDescriptor->FirstThunk); 107 | auto nameThunk = reinterpret_cast(reinterpret_cast(baseAddress) + importDescriptor->OriginalFirstThunk); 108 | 109 | bool result{ true }; 110 | while (thunk->u1.Function) 111 | { 112 | LPCSTR functionName{ nullptr }; 113 | auto functionAddress = reinterpret_cast(&thunk->u1.Function); 114 | 115 | bool importedByName{ !IMAGE_SNAP_BY_ORDINAL(nameThunk->u1.Ordinal) }; 116 | if (importedByName) 117 | { 118 | functionName = reinterpret_cast( 119 | RVA_TO_ADDR(baseAddress, static_cast(nameThunk->u1.AddressOfData)) 120 | )->Name; 121 | } 122 | else 123 | { 124 | functionName = MAKEINTRESOURCEA(IMAGE_ORDINAL(nameThunk->u1.Ordinal)); 125 | } 126 | 127 | result = callback(functionAddress, functionName, importedByName); 128 | if (!result) 129 | { 130 | break; 131 | } 132 | 133 | thunk++; 134 | nameThunk++; 135 | } 136 | } 137 | catch (...) {} 138 | 139 | void HookHelper::WalkDelayloadIAT(PVOID baseAddress, std::string_view dllName, std::function callback) try 140 | { 141 | THROW_HR_IF(E_INVALIDARG, dllName.empty()); 142 | THROW_HR_IF_NULL(E_INVALIDARG, baseAddress); 143 | THROW_HR_IF_NULL(E_INVALIDARG, callback); 144 | 145 | ULONG size{ 0ul }; 146 | auto importDescriptor = static_cast( 147 | ImageDirectoryEntryToData( 148 | baseAddress, 149 | TRUE, 150 | IMAGE_DIRECTORY_ENTRY_DELAY_IMPORT, 151 | &size 152 | ) 153 | ); 154 | 155 | THROW_HR_IF_NULL(E_INVALIDARG, importDescriptor); 156 | 157 | bool found = false; 158 | while (importDescriptor->DllNameRVA) 159 | { 160 | auto moduleName = reinterpret_cast( 161 | RVA_TO_ADDR(baseAddress, importDescriptor->DllNameRVA) 162 | ); 163 | 164 | if (!_stricmp(moduleName, dllName.data())) 165 | { 166 | found = true; 167 | break; 168 | } 169 | 170 | importDescriptor++; 171 | } 172 | 173 | THROW_HR_IF(HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND), !found); 174 | 175 | auto attributes = importDescriptor->Attributes.RvaBased; 176 | THROW_WIN32_IF_MSG(ERROR_FILE_NOT_FOUND, attributes != 1, "Unsupported delay loaded dll![%hs]", dllName.data()); 177 | 178 | auto moduleHandle = reinterpret_cast( 179 | RVA_TO_ADDR(baseAddress, importDescriptor->ModuleHandleRVA) 180 | ); 181 | auto thunk = reinterpret_cast( 182 | RVA_TO_ADDR(baseAddress, importDescriptor->ImportAddressTableRVA) 183 | ); 184 | auto nameThunk = reinterpret_cast( 185 | RVA_TO_ADDR(baseAddress, importDescriptor->ImportNameTableRVA) 186 | ); 187 | 188 | bool result{ true }; 189 | while (thunk->u1.Function) 190 | { 191 | LPCSTR functionName{ nullptr }; 192 | auto functionAddress = reinterpret_cast(&thunk->u1.Function); 193 | 194 | bool importedByName{ !IMAGE_SNAP_BY_ORDINAL(nameThunk->u1.Ordinal) }; 195 | if (importedByName) 196 | { 197 | functionName = reinterpret_cast( 198 | RVA_TO_ADDR(baseAddress, nameThunk->u1.AddressOfData) 199 | )->Name; 200 | } 201 | else 202 | { 203 | functionName = MAKEINTRESOURCEA(IMAGE_ORDINAL(nameThunk->u1.Ordinal)); 204 | } 205 | 206 | result = callback(moduleHandle, functionAddress, functionName, importedByName); 207 | if (!result) 208 | { 209 | break; 210 | } 211 | 212 | thunk++; 213 | nameThunk++; 214 | } 215 | } 216 | catch (...) {} 217 | 218 | PVOID* HookHelper::GetIAT(PVOID baseAddress, std::string_view dllName, LPCSTR targetFunctionNameOrOrdinal) 219 | { 220 | PVOID* originalFunction{ nullptr }; 221 | WalkIAT(baseAddress, dllName, [&](PVOID* functionAddress, LPCSTR functionNameOrOrdinal, bool importedByName) -> bool 222 | { 223 | if ( 224 | (importedByName == TRUE && targetFunctionNameOrOrdinal && !strcmp(functionNameOrOrdinal, targetFunctionNameOrOrdinal)) || 225 | (importedByName == FALSE && functionNameOrOrdinal == targetFunctionNameOrOrdinal) 226 | ) 227 | { 228 | originalFunction = functionAddress; 229 | 230 | return false; 231 | } 232 | 233 | return true; 234 | }); 235 | 236 | return originalFunction; 237 | } 238 | std::pair HookHelper::GetDelayloadIAT(PVOID baseAddress, std::string_view dllName, LPCSTR targetFunctionNameOrOrdinal, bool resolveAPI) 239 | { 240 | std::pair originalInfo{ nullptr, nullptr }; 241 | WalkDelayloadIAT(baseAddress, dllName, [&](HMODULE* moduleHandle, PVOID* functionAddress, LPCSTR functionNameOrOrdinal, bool importedByName) -> bool 242 | { 243 | if ( 244 | (importedByName == TRUE && targetFunctionNameOrOrdinal && (reinterpret_cast(targetFunctionNameOrOrdinal) & 0xFFFF0000) != 0 && !strcmp(functionNameOrOrdinal, targetFunctionNameOrOrdinal)) || 245 | (importedByName == FALSE && functionNameOrOrdinal == targetFunctionNameOrOrdinal) 246 | ) 247 | { 248 | originalInfo.first = moduleHandle; 249 | originalInfo.second = functionAddress; 250 | 251 | if (resolveAPI) 252 | { 253 | ResolveDelayloadIAT(originalInfo, baseAddress, dllName, targetFunctionNameOrOrdinal); 254 | } 255 | return false; 256 | } 257 | 258 | return true; 259 | }); 260 | 261 | return originalInfo; 262 | } 263 | 264 | PVOID HookHelper::WriteIAT(PVOID baseAddress, std::string_view dllName, LPCSTR targetFunctionNameOrOrdinal, PVOID detourFunction) 265 | { 266 | PVOID originalFunction{ nullptr }; 267 | 268 | auto functionAddress = GetIAT(baseAddress, dllName, targetFunctionNameOrOrdinal); 269 | if (functionAddress) 270 | { 271 | originalFunction = *functionAddress; 272 | 273 | WritePointer(functionAddress, detourFunction); 274 | } 275 | 276 | return originalFunction; 277 | } 278 | std::pair HookHelper::WriteDelayloadIAT(PVOID baseAddress, std::string_view dllName, LPCSTR targetFunctionNameOrOrdinal, PVOID detourFunction, std::optional newModuleHandle) 279 | { 280 | HMODULE originalModule{ nullptr }; 281 | PVOID originalFunction{ nullptr }; 282 | 283 | auto [moduleHandle, functionAddress] = GetDelayloadIAT(baseAddress, dllName, targetFunctionNameOrOrdinal, true); 284 | if (functionAddress) 285 | { 286 | originalModule = *moduleHandle; 287 | originalFunction = *functionAddress; 288 | 289 | if (newModuleHandle) 290 | { 291 | WritePointer(moduleHandle, newModuleHandle.value()); 292 | } 293 | WritePointer(functionAddress, detourFunction); 294 | } 295 | 296 | return std::make_pair(originalModule, originalFunction); 297 | } 298 | 299 | void HookHelper::ResolveDelayloadIAT(const std::pair& info, PVOID baseAddress, std::string_view dllName, LPCSTR targetFunctionNameOrOrdinal) 300 | { 301 | auto& [moduleHandle, functionAddress] {info}; 302 | if (DetourGetContainingModule(*functionAddress) == baseAddress || DetourGetContainingModule(DetourCodeFromPointer(*functionAddress, nullptr)) == baseAddress) 303 | { 304 | if (!(*moduleHandle)) 305 | { 306 | HMODULE importModule{ LoadLibraryA(dllName.data()) }; 307 | 308 | if (importModule) 309 | { 310 | WritePointer(moduleHandle, importModule); 311 | WritePointer(functionAddress, GetProcAddress(importModule, targetFunctionNameOrOrdinal)); 312 | } 313 | } 314 | else 315 | { 316 | WritePointer(functionAddress, GetProcAddress(*moduleHandle, targetFunctionNameOrOrdinal)); 317 | } 318 | } 319 | } 320 | 321 | HRESULT HookHelper::Detours::Begin() 322 | { 323 | DetourSetIgnoreTooSmall(TRUE); 324 | RETURN_IF_WIN32_ERROR(DetourTransactionBegin()); 325 | RETURN_IF_WIN32_ERROR(DetourUpdateThread(GetCurrentThread())); 326 | 327 | return S_OK; 328 | } 329 | 330 | HRESULT HookHelper::Detours::End(bool commit) 331 | { 332 | return (commit ? HRESULT_FROM_WIN32(DetourTransactionCommit()) : HRESULT_FROM_WIN32(DetourTransactionAbort())); 333 | } 334 | 335 | HRESULT HookHelper::Detours::Write(const std::function&& callback) 336 | { 337 | try 338 | { 339 | THROW_IF_FAILED(Begin()); 340 | 341 | callback(); 342 | 343 | THROW_IF_FAILED(End(true)); 344 | } 345 | CATCH_RETURN() 346 | 347 | return S_OK; 348 | } 349 | 350 | void HookHelper::Detours::Attach(PVOID* realFuncAddr, PVOID hookFuncAddr) 351 | { 352 | THROW_IF_WIN32_ERROR(DetourAttach(realFuncAddr, hookFuncAddr)); 353 | } 354 | 355 | void HookHelper::Detours::Detach(PVOID* realFuncAddr, PVOID hookFuncAddr) 356 | { 357 | THROW_IF_WIN32_ERROR(DetourDetach(realFuncAddr, hookFuncAddr)); 358 | } 359 | -------------------------------------------------------------------------------- /OpenGlass/GlassReflectionHandler.cpp: -------------------------------------------------------------------------------- 1 | #include "pch.h" 2 | #include "GlassReflectionHandler.hpp" 3 | #include "uDWMProjection.hpp" 4 | #include "dwmcoreProjection.hpp" 5 | #include "Shared.hpp" 6 | #include "GlassReflectionBrush.hpp" 7 | 8 | using namespace OpenGlass; 9 | 10 | namespace OpenGlass::GlassReflectionHandler 11 | { 12 | void STDMETHODCALLTYPE MyCAnimatedGlassSheet_OnRectUpdated(uDWM::CAnimatedGlassSheet* This, LPCRECT lprc); 13 | void STDMETHODCALLTYPE MyCAnimatedGlassSheet_Destructor(uDWM::CAnimatedGlassSheet* This); 14 | 15 | HRESULT STDMETHODCALLTYPE MyCLivePreview__FadeOutToGlass(uDWM::CLivePreview* This); 16 | HRESULT STDMETHODCALLTYPE MyCLivePreview__UpdateInstructions(uDWM::CLivePreview* This); 17 | 18 | decltype(&MyCAnimatedGlassSheet_OnRectUpdated) g_CAnimatedGlassSheet_OnRectUpdated_Org{ nullptr }; 19 | decltype(&MyCAnimatedGlassSheet_Destructor) g_CAnimatedGlassSheet_Destructor_Org{ nullptr }; 20 | 21 | decltype(&MyCLivePreview__FadeOutToGlass) g_CLivePreview__FadeOutToGlass_Org{ nullptr }; 22 | decltype(&MyCLivePreview__UpdateInstructions) g_CLivePreview__UpdateInstructions_Org{ nullptr }; 23 | 24 | class CAnimatedReflectionSheet : public winrt::implements 25 | { 26 | uDWM::CAnimatedGlassSheet* m_sheet{ nullptr }; 27 | winrt::com_ptr m_visual{ nullptr }; 28 | winrt::com_ptr m_geometry{ nullptr }; 29 | public: 30 | CAnimatedReflectionSheet(uDWM::CAnimatedGlassSheet* sheet) : m_sheet{ sheet } {}; 31 | virtual ~CAnimatedReflectionSheet() 32 | { 33 | if (m_visual) 34 | { 35 | m_sheet->GetVisualCollection()->Remove(m_visual.get()); 36 | GlassReflectionBrush::Remove(m_visual.get()); 37 | } 38 | } 39 | static HRESULT STDMETHODCALLTYPE Create(uDWM::CAnimatedGlassSheet* glassSheet, CAnimatedReflectionSheet** outputSheet) 40 | { 41 | auto reflectionSheet = winrt::make_self(glassSheet); 42 | RETURN_IF_FAILED(reflectionSheet->Initialize()); 43 | *outputSheet = reflectionSheet.detach(); 44 | return S_OK; 45 | } 46 | 47 | HRESULT STDMETHODCALLTYPE Initialize() 48 | { 49 | RETURN_IF_FAILED( 50 | uDWM::CRenderDataVisual::Create( 51 | m_visual.put() 52 | ) 53 | ); 54 | m_visual->SetInsetFromParent({}); 55 | const auto brush = GlassReflectionBrush::GetOrCreate(m_visual.get(), true); 56 | if (!brush) 57 | { 58 | return E_FAIL; 59 | } 60 | 61 | wil::unique_hrgn emptyRegion{ CreateRectRgn(0, 0, 0, 0) }; 62 | RETURN_LAST_ERROR_IF_NULL(emptyRegion); 63 | 64 | RETURN_IF_FAILED( 65 | uDWM::ResourceHelper::CreateGeometryFromHRGN( 66 | emptyRegion.get(), 67 | m_geometry.put() 68 | ) 69 | ); 70 | winrt::com_ptr instruction{ nullptr }; 71 | RETURN_IF_FAILED( 72 | uDWM::CDrawGeometryInstruction::Create( 73 | brush.get(), 74 | m_geometry.get(), 75 | instruction.put() 76 | ) 77 | ); 78 | RETURN_IF_FAILED(m_visual->AddInstruction(instruction.get())); 79 | RETURN_IF_FAILED( 80 | m_sheet->GetVisualCollection()->InsertRelative( 81 | m_visual.get(), 82 | nullptr, 83 | false, 84 | true 85 | ) 86 | ); 87 | 88 | return S_OK; 89 | } 90 | HRESULT STDMETHODCALLTYPE OnRectUpdated(LPCRECT lprc) 91 | { 92 | const auto brush = GlassReflectionBrush::GetOrCreate(m_visual.get()); 93 | RETURN_IF_FAILED( 94 | brush->Update( 95 | (Shared::g_reflectionPolicy & Shared::ReflectionPolicy::AnimatedGlassSheet) ? 96 | 1.f : 97 | 0.f, 98 | GlassReflectionBrush::CalculateTargetViewport( 99 | { lprc->left, lprc->top } 100 | ), 101 | D2D1::RectF(), 102 | nullptr, 103 | DWM::MilBrushMappingMode::Absolute, 104 | DWM::MilBrushMappingMode::Absolute, 105 | nullptr, 106 | nullptr, 107 | DWM::MilStretch::None, 108 | DWM::MilTileMode::Extend, 109 | DWM::MilHorizontalAlignment::Left, 110 | DWM::MilVerticalAlignment::Top, 111 | nullptr 112 | ) 113 | ); 114 | m_visual->_ValidateVisual(); 115 | 116 | RETURN_IF_FAILED( 117 | uDWM::ResourceHelper::CreateGeometryFromHRGN( 118 | wil::unique_hrgn 119 | { 120 | CreateRoundRectRgn( 121 | 0 - m_sheet->GetAtlasPaddingLeft(), 122 | 0 - m_sheet->GetAtlasPaddingTop(), 123 | wil::rect_width(*lprc) - m_sheet->GetAtlasPaddingRight(), 124 | wil::rect_height(*lprc) - m_sheet->GetAtlasPaddingBottom(), 125 | Shared::g_roundRectRadius, 126 | Shared::g_roundRectRadius 127 | ) 128 | }.get(), 129 | reinterpret_cast(&m_geometry) 130 | ) 131 | ); 132 | return S_OK; 133 | } 134 | }; 135 | std::unordered_map> g_sheetMap{}; 136 | 137 | bool g_disableReflectionHooks{ false }; 138 | } 139 | 140 | void STDMETHODCALLTYPE GlassReflectionHandler::MyCAnimatedGlassSheet_OnRectUpdated(uDWM::CAnimatedGlassSheet* This, LPCRECT lprc) 141 | { 142 | winrt::com_ptr reflectionSheet{}; 143 | if (const auto it = g_sheetMap.find(This); it != g_sheetMap.end()) 144 | { 145 | reflectionSheet = it->second; 146 | } 147 | else 148 | { 149 | if (SUCCEEDED(CAnimatedReflectionSheet::Create(This, reflectionSheet.put()))) 150 | { 151 | g_sheetMap.emplace(This, reflectionSheet); 152 | } 153 | } 154 | 155 | if (reflectionSheet) 156 | { 157 | reflectionSheet->OnRectUpdated(lprc); 158 | } 159 | 160 | return g_CAnimatedGlassSheet_OnRectUpdated_Org(This, lprc); 161 | } 162 | void STDMETHODCALLTYPE GlassReflectionHandler::MyCAnimatedGlassSheet_Destructor(uDWM::CAnimatedGlassSheet* This) 163 | { 164 | g_sheetMap.erase(This); 165 | return g_CAnimatedGlassSheet_Destructor_Org(This); 166 | } 167 | 168 | // here restores 169 | // CLivePreview::_UpdateGlassVisual 170 | // CLivePreview::_UpdateInstructions 171 | HRESULT STDMETHODCALLTYPE GlassReflectionHandler::MyCLivePreview__FadeOutToGlass(uDWM::CLivePreview* This) 172 | { 173 | RETURN_IF_FAILED(This->_UpdateResources()); 174 | 175 | for (auto& visual : This->GetLivePreviewVisualArray()->views()) 176 | { 177 | const auto data = visual.data; 178 | if (uDWM::CLivePreview::IsWindowIncluded(data)) 179 | { 180 | auto windowFrames = visual.windowFrames; 181 | if (visual.unknown0 || !uDWM::CLivePreview::IsWindowCloneAsWindowFrames(data)) 182 | { 183 | if (windowFrames) 184 | { 185 | windowFrames->GetTransformParent()->GetVisualCollection()->Remove( 186 | windowFrames 187 | ); 188 | windowFrames->Release(); 189 | visual.windowFrames = nullptr; 190 | } 191 | } 192 | else if (!windowFrames) 193 | { 194 | visual.data->GetWindow()->CloneVisualTreeForLivePreview(true, &visual.windowFrames); 195 | This->GetGlassVisual()->GetVisualCollection()->InsertRelative( 196 | visual.windowFrames, 197 | nullptr, 198 | false, 199 | true 200 | ); 201 | } 202 | } 203 | } 204 | RETURN_IF_FAILED(This->ClearInstructions()); 205 | RETURN_IF_FAILED(This->GetGlassVisual()->ClearInstructions()); 206 | for (const auto& resource : This->GetLivePreviewResourceArray()->views()) 207 | { 208 | //if (resource.IsWindowBoundingRectNotEmpty()) 209 | if ( 210 | !IsRectEmpty(resource.GetWindowBoundingRect()) 211 | ) 212 | { 213 | winrt::com_ptr instruction{ nullptr }; 214 | if ( 215 | resource.GetWindowVisualBrush() && 216 | resource.GetWindowBoundingGeometry() 217 | ) 218 | { 219 | RETURN_IF_FAILED( 220 | uDWM::CDrawGeometryInstruction::Create( 221 | resource.GetWindowVisualBrush(), 222 | resource.GetWindowBoundingGeometry(), 223 | instruction.put() 224 | ) 225 | ); 226 | RETURN_IF_FAILED(This->AddInstruction(instruction.get())); 227 | } 228 | 229 | if ( 230 | resource.GetGlassVisualBrush() && 231 | resource.GetGlassBoundingGeometry() 232 | ) 233 | { 234 | RETURN_IF_FAILED( 235 | uDWM::CDrawGeometryInstruction::Create( 236 | resource.GetGlassVisualBrush(), 237 | resource.GetGlassBoundingGeometry(), 238 | instruction.put() 239 | ) 240 | ); 241 | RETURN_IF_FAILED(This->AddInstruction(instruction.get())); 242 | } 243 | } 244 | //if (resource.IsGlassBoundingRectNotEmpty()) 245 | if ( 246 | !IsRectEmpty(resource.GetGlassBoundingRect()) && 247 | resource.GetReflectionGeometry() 248 | ) 249 | { 250 | if ( 251 | const auto brush = GlassReflectionBrush::GetOrCreate( 252 | This, 253 | true 254 | ); 255 | brush 256 | ) 257 | { 258 | RETURN_IF_FAILED( 259 | brush->Update( 260 | (Shared::g_reflectionPolicy & Shared::ReflectionPolicy::LivePreview) ? 261 | 1.f : 262 | 0.f, 263 | GlassReflectionBrush::CalculateTargetViewport( 264 | This->GetGlassVisual()->GetLocalToParentVisualOffset(This->GetTransformParent()) 265 | ), 266 | D2D1::RectF(), 267 | nullptr, 268 | DWM::MilBrushMappingMode::Absolute, 269 | DWM::MilBrushMappingMode::Absolute, 270 | nullptr, 271 | nullptr, 272 | DWM::MilStretch::None, 273 | DWM::MilTileMode::Extend, 274 | DWM::MilHorizontalAlignment::Left, 275 | DWM::MilVerticalAlignment::Top, 276 | nullptr 277 | ) 278 | ); 279 | 280 | winrt::com_ptr instruction{ nullptr }; 281 | RETURN_IF_FAILED( 282 | uDWM::CDrawGeometryInstruction::Create( 283 | brush.get(), 284 | resource.GetReflectionGeometry(), 285 | instruction.put() 286 | ) 287 | ); 288 | RETURN_IF_FAILED(This->GetGlassVisual()->AddInstruction(instruction.get())); 289 | } 290 | } 291 | } 292 | 293 | return g_CLivePreview__FadeOutToGlass_Org(This); 294 | } 295 | HRESULT STDMETHODCALLTYPE GlassReflectionHandler::MyCLivePreview__UpdateInstructions(uDWM::CLivePreview* This) 296 | { 297 | const auto hr = g_CLivePreview__UpdateInstructions_Org(This); 298 | 299 | for (const auto& resource : This->GetLivePreviewResourceArray()->views()) 300 | { 301 | //if (resource.IsGlassBoundingRectNotEmpty()) 302 | if ( 303 | !IsRectEmpty(resource.GetGlassBoundingRect()) && 304 | resource.GetReflectionGeometry() 305 | ) 306 | { 307 | if ( 308 | const auto brush = GlassReflectionBrush::GetOrCreate( 309 | This, 310 | true 311 | ); 312 | brush 313 | ) 314 | { 315 | RETURN_IF_FAILED( 316 | brush->Update( 317 | (Shared::g_reflectionPolicy & Shared::ReflectionPolicy::LivePreview) ? 318 | 1.f : 319 | 0.f, 320 | GlassReflectionBrush::CalculateTargetViewport( 321 | This->GetGlassVisual()->GetLocalToParentVisualOffset(This->GetTransformParent()) 322 | ), 323 | D2D1::RectF(), 324 | nullptr, 325 | DWM::MilBrushMappingMode::Absolute, 326 | DWM::MilBrushMappingMode::Absolute, 327 | nullptr, 328 | nullptr, 329 | DWM::MilStretch::None, 330 | DWM::MilTileMode::Extend, 331 | DWM::MilHorizontalAlignment::Left, 332 | DWM::MilVerticalAlignment::Top, 333 | nullptr 334 | ) 335 | ); 336 | 337 | winrt::com_ptr instruction{ nullptr }; 338 | RETURN_IF_FAILED( 339 | uDWM::CDrawGeometryInstruction::Create( 340 | brush.get(), 341 | resource.GetReflectionGeometry(), 342 | instruction.put() 343 | ) 344 | ); 345 | RETURN_IF_FAILED(This->GetGlassVisual()->AddInstruction(instruction.get())); 346 | } 347 | } 348 | } 349 | 350 | return hr; 351 | } 352 | 353 | void GlassReflectionHandler::Update([[maybe_unused]] GlassEngine::UpdateType type) 354 | { 355 | } 356 | 357 | void GlassReflectionHandler::Startup() 358 | { 359 | DWORD value{ 0ul }; 360 | wil::reg::get_value_dword_nothrow( 361 | GlassEngine::GetDwmLocalMachineKey(), 362 | L"DisabledHooks", 363 | &value 364 | ); 365 | g_disableReflectionHooks = (value & 8) != 0; 366 | 367 | if (g_disableReflectionHooks) 368 | { 369 | return; 370 | } 371 | 372 | uDWM::g_projectionArray.ApplyToVariable("CAnimatedGlassSheet::OnRectUpdated", g_CAnimatedGlassSheet_OnRectUpdated_Org); 373 | uDWM::g_projectionArray.ApplyToVariable("CAnimatedGlassSheet::~CAnimatedGlassSheet", g_CAnimatedGlassSheet_Destructor_Org); 374 | 375 | uDWM::g_projectionArray.ApplyToVariable("CLivePreview::_FadeOutToGlass", g_CLivePreview__FadeOutToGlass_Org); 376 | uDWM::g_projectionArray.ApplyToVariable("CLivePreview::_UpdateInstructions", g_CLivePreview__UpdateInstructions_Org); 377 | 378 | THROW_IF_FAILED( 379 | HookHelper::Detours::Write([]() static 380 | { 381 | if (uDWM::g_versionInfo.build < os::build_w11_21h2) 382 | { 383 | HookHelper::Detours::Attach(&g_CAnimatedGlassSheet_OnRectUpdated_Org, MyCAnimatedGlassSheet_OnRectUpdated); 384 | HookHelper::Detours::Attach(&g_CAnimatedGlassSheet_Destructor_Org, MyCAnimatedGlassSheet_Destructor); 385 | 386 | HookHelper::Detours::Attach(&g_CLivePreview__UpdateInstructions_Org, MyCLivePreview__UpdateInstructions); 387 | } 388 | else 389 | { 390 | HookHelper::Detours::Attach(&g_CLivePreview__FadeOutToGlass_Org, MyCLivePreview__FadeOutToGlass); 391 | } 392 | }) 393 | ); 394 | } 395 | 396 | void GlassReflectionHandler::Shutdown() 397 | { 398 | if (g_disableReflectionHooks) 399 | { 400 | return; 401 | } 402 | 403 | THROW_IF_FAILED( 404 | HookHelper::Detours::Write([]() static 405 | { 406 | if (uDWM::g_versionInfo.build < os::build_w11_21h2) 407 | { 408 | HookHelper::Detours::Detach(&g_CAnimatedGlassSheet_OnRectUpdated_Org, MyCAnimatedGlassSheet_OnRectUpdated); 409 | HookHelper::Detours::Detach(&g_CAnimatedGlassSheet_Destructor_Org, MyCAnimatedGlassSheet_Destructor); 410 | 411 | HookHelper::Detours::Detach(&g_CLivePreview__UpdateInstructions_Org, MyCLivePreview__UpdateInstructions); 412 | } 413 | else 414 | { 415 | HookHelper::Detours::Detach(&g_CLivePreview__FadeOutToGlass_Org, MyCLivePreview__FadeOutToGlass); 416 | } 417 | }) 418 | ); 419 | 420 | g_sheetMap.clear(); 421 | } 422 | --------------------------------------------------------------------------------