From 7975091c3dc92911bc8324bb994b24f099ad2812 Mon Sep 17 00:00:00 2001 From: Mikhail Thompson Date: Sun, 2 Jun 2024 17:17:37 +0200 Subject: [PATCH 1/2] push code --- .gitignore | 6 + .../GyroShell.ImmersiveShellHook.vcxproj | 172 +++++++++++ ...roShell.ImmersiveShellHook.vcxproj.filters | 41 +++ GyroShell.ImmersiveShellHook/Source.def | 5 + GyroShell.ImmersiveShellHook/dllmain.cpp | 277 +++++++++++++++++ GyroShell.ImmersiveShellHook/framework.h | 6 + GyroShell.ImmersiveShellHook/pch.cpp | 5 + GyroShell.ImmersiveShellHook/pch.h | 13 + GyroShell.ImmersiveShellHook/undoc.h | 12 + .../vcpkg-configuration.json | 14 + GyroShell.ImmersiveShellHook/vcpkg.json | 5 + .../Helpers/Win32/Win32Interop.cs | 104 ++++++- .../Helpers/Win32/WindowChecks.cs | 2 +- GyroShell.sln | 21 ++ GyroShell/Controls/StartupWindow.xaml.cs | 4 +- GyroShell/GyroShell.csproj | 243 ++++++++------- GyroShell/Properties/Resources.Designer.cs | 73 +++++ GyroShell/Properties/Resources.resx | 124 ++++++++ .../Services/Helpers/IconHelperService.cs | 283 +++++++++--------- .../Managers/ExplorerManagerService.cs | 147 ++++++++- 20 files changed, 1283 insertions(+), 274 deletions(-) create mode 100644 GyroShell.ImmersiveShellHook/GyroShell.ImmersiveShellHook.vcxproj create mode 100644 GyroShell.ImmersiveShellHook/GyroShell.ImmersiveShellHook.vcxproj.filters create mode 100644 GyroShell.ImmersiveShellHook/Source.def create mode 100644 GyroShell.ImmersiveShellHook/dllmain.cpp create mode 100644 GyroShell.ImmersiveShellHook/framework.h create mode 100644 GyroShell.ImmersiveShellHook/pch.cpp create mode 100644 GyroShell.ImmersiveShellHook/pch.h create mode 100644 GyroShell.ImmersiveShellHook/undoc.h create mode 100644 GyroShell.ImmersiveShellHook/vcpkg-configuration.json create mode 100644 GyroShell.ImmersiveShellHook/vcpkg.json create mode 100644 GyroShell/Properties/Resources.Designer.cs create mode 100644 GyroShell/Properties/Resources.resx diff --git a/.gitignore b/.gitignore index dfcfd56..b107b64 100644 --- a/.gitignore +++ b/.gitignore @@ -348,3 +348,9 @@ MigrationBackup/ # Ionide (cross platform F# VS Code tools) working folder .ionide/ + +# C++ +**/vcpkg_installed/** + +# Other +Gyroshell/Resources/rmclient.dll \ No newline at end of file diff --git a/GyroShell.ImmersiveShellHook/GyroShell.ImmersiveShellHook.vcxproj b/GyroShell.ImmersiveShellHook/GyroShell.ImmersiveShellHook.vcxproj new file mode 100644 index 0000000..ffc9113 --- /dev/null +++ b/GyroShell.ImmersiveShellHook/GyroShell.ImmersiveShellHook.vcxproj @@ -0,0 +1,172 @@ + + + + + Debug + Win32 + + + Release + Win32 + + + Debug + x64 + + + Release + x64 + + + + 17.0 + Win32Proj + {617aea24-0755-490c-bc05-6dbb5e2059e0} + GyroShellImmersiveShellHook + 10.0 + + + + DynamicLibrary + true + v143 + Unicode + + + DynamicLibrary + false + v143 + true + Unicode + + + DynamicLibrary + true + v143 + Unicode + + + DynamicLibrary + false + v143 + true + Unicode + + + true + + + + + + + + + + + + + + + + + + + + + rmclient + + + + Level3 + true + WIN32;_DEBUG;GYROSHELLIMMERSIVESHELLHOOK_EXPORTS;_WINDOWS;_USRDLL;%(PreprocessorDefinitions) + true + Use + pch.h + + + Windows + true + false + Source.def + + + + + Level3 + true + true + true + WIN32;NDEBUG;GYROSHELLIMMERSIVESHELLHOOK_EXPORTS;_WINDOWS;_USRDLL;%(PreprocessorDefinitions) + true + Use + pch.h + + + Windows + true + true + true + false + Source.def + + + + + Level3 + true + _DEBUG;GYROSHELLIMMERSIVESHELLHOOK_EXPORTS;_WINDOWS;_USRDLL;%(PreprocessorDefinitions) + true + Use + pch.h + + + Windows + true + false + shlwapi.lib;rpcrt4.lib;Wtsapi32.lib;%(AdditionalDependencies) + Source.def + + + + + Level3 + true + true + true + NDEBUG;GYROSHELLIMMERSIVESHELLHOOK_EXPORTS;_WINDOWS;_USRDLL;%(PreprocessorDefinitions) + true + Use + pch.h + + + Windows + true + true + true + false + shlwapi.lib;rpcrt4.lib;Wtsapi32.lib;%(AdditionalDependencies) + Source.def + + + + + + + + + + + Create + Create + Create + Create + + + + + + + + \ No newline at end of file diff --git a/GyroShell.ImmersiveShellHook/GyroShell.ImmersiveShellHook.vcxproj.filters b/GyroShell.ImmersiveShellHook/GyroShell.ImmersiveShellHook.vcxproj.filters new file mode 100644 index 0000000..c5cea67 --- /dev/null +++ b/GyroShell.ImmersiveShellHook/GyroShell.ImmersiveShellHook.vcxproj.filters @@ -0,0 +1,41 @@ + + + + + {4FC737F1-C7A5-4376-A066-2A32D752A2FF} + cpp;c;cc;cxx;c++;cppm;ixx;def;odl;idl;hpj;bat;asm;asmx + + + {93995380-89BD-4b04-88EB-625FBE52EBFB} + h;hh;hpp;hxx;h++;hm;inl;inc;ipp;xsd + + + {67DA6AB6-F800-4c08-8B7A-83BB121AAD01} + rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms + + + + + Header Files + + + Header Files + + + Header Files + + + + + Source Files + + + Source Files + + + + + Source Files + + + \ No newline at end of file diff --git a/GyroShell.ImmersiveShellHook/Source.def b/GyroShell.ImmersiveShellHook/Source.def new file mode 100644 index 0000000..789090c --- /dev/null +++ b/GyroShell.ImmersiveShellHook/Source.def @@ -0,0 +1,5 @@ +EXPORTS +HamCloseActivity +HamPopulateActivityProperties +SECTIONS +.imrsiv READ \ No newline at end of file diff --git a/GyroShell.ImmersiveShellHook/dllmain.cpp b/GyroShell.ImmersiveShellHook/dllmain.cpp new file mode 100644 index 0000000..eaad3f1 --- /dev/null +++ b/GyroShell.ImmersiveShellHook/dllmain.cpp @@ -0,0 +1,277 @@ +#include "pch.h" +#include +#include +#include +#include +#include + +//INSTALL DETOURS FROM NUGET! (or build from source yourself) +#include +#include + +#include "undoc.h" + +typedef HRESULT(CALLBACK* SetShellWindow)(HWND hwnd); + +long PcRef = 0; +IUnknown* ThreadObject = NULL; + +LRESULT ProgmanWndProc(HWND hwnd, UINT msg, WPARAM w, LPARAM l) +{ + if (msg == WM_CREATE) + { + auto user32 = LoadLibrary(TEXT("user32.dll")); + SetShellWindow SetShellWindowFunc = (SetShellWindow)GetProcAddress(user32, "SetShellWindow"); + if (SetShellWindowFunc == NULL) + { + printf("immersive shell starter: failed to get pointer to SetShellWindow()\n"); + system("pause"); + return GetLastError(); + } + + if (FAILED(SetShellWindowFunc(hwnd))) + { + printf("SetShellWindow failed\n"); + return 0; + } + SendMessageW(hwnd, WM_CHANGEUISTATE, 3u, 0); + SendMessageW(hwnd, WM_UPDATEUISTATE, 0x10001u, 0); + + SetProp(hwnd, TEXT("NonRudeHWND"), (HANDLE)HANDLE_FLAG_INHERIT); + SetProp(hwnd, TEXT("AllowConsentToStealFocus"), (HANDLE)HANDLE_FLAG_INHERIT); + + + if (SUCCEEDED(SHCreateThreadRef(&PcRef, &ThreadObject))) + { + SHSetThreadRef(ThreadObject); + } + else + { + printf("Failed to create thread reference"); + } + } + else if (msg == WM_DESTROY) + { + if (GetShellWindow() == hwnd) + { + RemovePropW(hwnd, L"AllowConsentToStealFocus"); + RemovePropW(hwnd, L"NonRudeHWND"); + + auto user32 = LoadLibrary(TEXT("user32.dll")); + SetShellWindow SetShellWindowFunc = (SetShellWindow)GetProcAddress(user32, "SetShellWindow"); + if (SetShellWindowFunc == NULL) + { + printf("immersive shell starter: failed to get pointer to SetShellWindow()\n"); + system("pause"); + return GetLastError(); + } + SetShellWindowFunc(NULL); + } + } + else if (msg == WM_SIZE) + { + ShowWindow(hwnd, 5); + } + else if (msg == WM_CLOSE) + { + return -1; + } + else if (msg == WM_PAINT) + { + PAINTSTRUCT Paint; + RECT Rect; + HDC dc = BeginPaint(hwnd, &Paint); + GetClientRect(hwnd, &Rect); + FillRect(dc, &Rect, CreateSolidBrush(RGB(0, 36, 0))); + EndPaint(hwnd, &Paint); + return 0; + } + else if (msg == WM_TIMER) + { + printf("timer!\n"); + } + return DefWindowProc(hwnd, msg, w, l); +} + + + +HINSTANCE g_hInstance = NULL; + +HWND CreateProgman() +{ + printf("Create program manager\n"); + + WNDCLASSEX progmanclass = {}; + progmanclass.cbClsExtra = 0; + progmanclass.hIcon = 0; + progmanclass.lpszMenuName = 0; + progmanclass.hIconSm = 0; + progmanclass.cbSize = 80; + progmanclass.style = 8; + progmanclass.lpfnWndProc = (WNDPROC)ProgmanWndProc; + progmanclass.cbWndExtra = 8; + progmanclass.hInstance = g_hInstance; + progmanclass.hCursor = LoadCursor(NULL, IDC_ARROW); + progmanclass.hbrBackground = (HBRUSH)2; + progmanclass.lpszClassName = TEXT("Progman"); + + if (!RegisterClassExW(&progmanclass)) + { + printf("failed to register progman class %d", GetLastError()); + return NULL; + } + + return CreateWindowExW(128, L"Progman", TEXT("Program Manager"), 0x82000000, 0, 0, 0, 0, 0, 0, progmanclass.hInstance, 0); +} + +int MainHook( + HINSTANCE hInstance, + HINSTANCE hPrevInstance, + LPSTR lpCmdLine, + int nShowCmd +) +{ + printf("Winmain hooked!\n"); + g_hInstance = hInstance; + + if (FAILED(CoInitializeEx(NULL, 2))) + { + printf("Failed to initialize COM\n"); + return -1; + } + printf("Starting the immersive shell provider/controller\n"); + + + + + // find progman window and set it as the shell window + HWND progman = CreateProgman(); + if (!progman) + { + printf("failed to create progman window\n"); + system("pause"); + return GetLastError(); + } + + IImmersiveShellBuilder* ImmersiveShellBuilder = NULL; + + GUID guid; + if (FAILED(CLSIDFromString(L"{c71c41f1-ddad-42dc-a8fc-f5bfc61df957}", &guid))) + { + printf("failed to read guid1\n"); + return -1; + } + GUID guid2; + if (FAILED(CLSIDFromString(L"{1c56b3e4-e6ea-4ced-8a74-73b72c6bd435}", &guid2))) + { + printf("failed to read guid2\n"); + return -1; + } + HRESULT hr = CoCreateInstance( + guid, + 0, + 1u, + guid2, + (LPVOID*)&ImmersiveShellBuilder); + + if (FAILED(hr)) + { + printf("Failed to create the immersive shell builder: 0x%x\n", hr); + system("pause"); + return hr; + } + IImmersiveShellController* controller = NULL; + hr = ImmersiveShellBuilder->CreateImmersiveShellController(&controller); //CImmersiveShellController + if (FAILED(hr)) + { + printf("Failed to create the immersive shell controller: 0x%x\n", hr); + system("pause"); + return hr; + } + + + + hr = controller->Start(); + + + if (FAILED(hr)) + { + printf("immersive shell start failed with 0x%x\n", hr); + } + else + { + printf("Immersive shell created. Starting message loop\n"); + + if (!CreateEventW(0, TRUE, 0, L"Local\\ShellStartupEvent")) + { + printf("Failed to create start event: %d\n", GetLastError()); + + } + + HANDLE StartEvent = OpenEvent(2, FALSE, TEXT("Local\\ShellStartupEvent")); + if (!StartEvent) + { + printf("Failed to open start event: %d\n", GetLastError()); + } + else + { + if (!SetEvent(StartEvent)) + { + printf("Failed to set start event: %d\n", GetLastError()); + } + } + } + + return -1; +} + +BOOL APIENTRY DllMain(HMODULE hModule, DWORD ul_reason_for_call, LPVOID lpReserved) +{ + switch (ul_reason_for_call) + { + case DLL_PROCESS_ATTACH: + { + DisableThreadLibraryCalls(hModule); + AllocConsole(); + + freopen("CONIN$", "r", stdin); + freopen("CONOUT$", "w", stdout); + freopen("CONOUT$", "w", stderr); + + printf("Hooked into runtimebroker"); + + //LaunchCustomShellHost + MODULEINFO info = {}; + if (!GetModuleInformation(GetCurrentProcess(), NULL, &info, sizeof(MODULEINFO))) + { + printf("GetModuleInformation() failure: %d", GetLastError()); + } + else + { + printf("entry point of runtimebroker is at %x, hooking it now\n", info.EntryPoint); + + DetourTransactionBegin(); + DetourUpdateThread(GetCurrentThread()); + DetourAttach(&info.EntryPoint, (PVOID)MainHook); + DetourTransactionCommit(); + } + } + break; + case DLL_PROCESS_DETACH: + { + //TODO + } + break; + } + return TRUE; +} + +void HamCloseActivity() +{ + printf("STUB FUNCTION: HamCloseActivity\n"); +} + +void HamPopulateActivityProperties() +{ + printf("STUB FUNCTION: HamPopulateActivityProperties\n"); +} \ No newline at end of file diff --git a/GyroShell.ImmersiveShellHook/framework.h b/GyroShell.ImmersiveShellHook/framework.h new file mode 100644 index 0000000..0965e73 --- /dev/null +++ b/GyroShell.ImmersiveShellHook/framework.h @@ -0,0 +1,6 @@ +#pragma once + +#define _CRT_SECURE_NO_WARNINGS 1 +#define WIN32_LEAN_AND_MEAN // Exclude rarely-used stuff from Windows headers +// Windows Header Files +#include diff --git a/GyroShell.ImmersiveShellHook/pch.cpp b/GyroShell.ImmersiveShellHook/pch.cpp new file mode 100644 index 0000000..91c22df --- /dev/null +++ b/GyroShell.ImmersiveShellHook/pch.cpp @@ -0,0 +1,5 @@ +// pch.cpp: source file corresponding to the pre-compiled header + +#include "pch.h" + +// When you are using pre-compiled headers, this source file is necessary for compilation to succeed. diff --git a/GyroShell.ImmersiveShellHook/pch.h b/GyroShell.ImmersiveShellHook/pch.h new file mode 100644 index 0000000..04ff4c2 --- /dev/null +++ b/GyroShell.ImmersiveShellHook/pch.h @@ -0,0 +1,13 @@ +// pch.h: This is a precompiled header file. +// Files listed below are compiled only once, improving build performance for future builds. +// This also affects IntelliSense performance, including code completion and many code browsing features. +// However, files listed here are ALL re-compiled if any one of them is updated between builds. +// Do not add files here that you will be updating frequently as this negates the performance advantage. + +#ifndef PCH_H +#define PCH_H + +// add headers that you want to pre-compile here +#include "framework.h" + +#endif //PCH_H diff --git a/GyroShell.ImmersiveShellHook/undoc.h b/GyroShell.ImmersiveShellHook/undoc.h new file mode 100644 index 0000000..f485c98 --- /dev/null +++ b/GyroShell.ImmersiveShellHook/undoc.h @@ -0,0 +1,12 @@ +#pragma once +interface IImmersiveShellController : IUnknown +{ + virtual HRESULT Start(); + virtual HRESULT Stop(void* unknown); + virtual HRESULT SetCreationBehavior(void* structure); + +}; +interface IImmersiveShellBuilder : IUnknown +{ + virtual HRESULT CreateImmersiveShellController(IImmersiveShellController** other); +}; diff --git a/GyroShell.ImmersiveShellHook/vcpkg-configuration.json b/GyroShell.ImmersiveShellHook/vcpkg-configuration.json new file mode 100644 index 0000000..b9734a0 --- /dev/null +++ b/GyroShell.ImmersiveShellHook/vcpkg-configuration.json @@ -0,0 +1,14 @@ +{ + "default-registry": { + "kind": "git", + "baseline": "7f9f0e44db287e8e67c0e888141bfa200ab45121", + "repository": "https://github.com/microsoft/vcpkg" + }, + "registries": [ + { + "kind": "artifact", + "location": "https://github.com/microsoft/vcpkg-ce-catalog/archive/refs/heads/main.zip", + "name": "microsoft" + } + ] +} diff --git a/GyroShell.ImmersiveShellHook/vcpkg.json b/GyroShell.ImmersiveShellHook/vcpkg.json new file mode 100644 index 0000000..d184b6f --- /dev/null +++ b/GyroShell.ImmersiveShellHook/vcpkg.json @@ -0,0 +1,5 @@ +{ + "dependencies": [ + "detours" + ] +} diff --git a/GyroShell.Library/Helpers/Win32/Win32Interop.cs b/GyroShell.Library/Helpers/Win32/Win32Interop.cs index 5b051be..433545c 100644 --- a/GyroShell.Library/Helpers/Win32/Win32Interop.cs +++ b/GyroShell.Library/Helpers/Win32/Win32Interop.cs @@ -200,8 +200,8 @@ public enum GetWindowCmd : uint GW_ENABLEDPOPUP = 6 } - [DllImport("user32.dll", SetLastError = true, CharSet = CharSet.Auto)] - public static extern int MessageBox(IntPtr hWnd, string text, string caption, uint type); + [DllImport("user32.dll", SetLastError = true, CharSet = CharSet.Unicode)] + public static extern int MessageBoxW(IntPtr hWnd, string text, string caption, uint type); [DllImport("PowrProf.dll")] public static extern bool SetSuspendState(bool hibernate, bool forceCritical, bool disableWakeEvent); @@ -240,8 +240,8 @@ public enum GetWindowCmd : uint public static extern bool EnumWindows(EnumWindowsCallback lpEnumFunc, IntPtr lParam); public delegate bool EnumWindowsCallback(IntPtr hwnd, IntPtr lParam); - [DllImport("user32.dll", SetLastError = true, CharSet = CharSet.Auto)] - public static extern int GetClassName(IntPtr hWnd, StringBuilder lpClassName, int nMaxCount); + [DllImport("user32.dll", SetLastError = true, CharSet = CharSet.Unicode)] + public static extern int GetClassNameW(IntPtr hWnd, StringBuilder lpClassName, int nMaxCount); [DllImport("user32.dll")] [return: MarshalAs(UnmanagedType.Bool)] @@ -263,7 +263,7 @@ public enum GetWindowCmd : uint public static extern bool IsTopLevelWindow(IntPtr hWnd); [DllImport("user32.dll", SetLastError = true)] - public static extern IntPtr FindWindow(string lpClassName, string lpWindowName); + public static extern IntPtr FindWindowW(string lpClassName, string lpWindowName); [DllImport("user32.dll")] [return: MarshalAs(UnmanagedType.Bool)] @@ -286,7 +286,7 @@ public enum GetWindowCmd : uint public static extern int GetWindowTextLength(IntPtr hWnd); [DllImport("user32.dll", SetLastError = true)] - public static extern IntPtr FindWindowEx(IntPtr parentHandle, IntPtr childAfter, string className, string windowTitle); + public static extern IntPtr FindWindowExW(IntPtr parentHandle, IntPtr childAfter, string className, string windowTitle); [DllImport("user32.dll")] public static extern int ShowWindow(IntPtr hwnd, int nCmdShow); @@ -337,7 +337,10 @@ public enum GetWindowCmd : uint public static extern IntPtr ShellExecute(IntPtr hwnd, string lpOperation, string lpFile, string lpParameters, string lpDirectory, int nShowCmd); [DllImport("user32.dll", SetLastError = true)] - public static extern bool RegisterShellHookWindow(IntPtr hWnd); + public static extern bool RegisterShellHookWindow(IntPtr hWnd); + + [DllImport("user32.dll", CharSet = CharSet.Unicode, SetLastError = true)] + public static extern uint RegisterWindowMessageW(string lpString); [DllImport("user32.dll")] public static extern bool DeregisterShellHookWindow(IntPtr hWnd); @@ -376,7 +379,60 @@ public enum DWM_WINDOW_CORNER_PREFERENCE public static extern bool ShellDDEInit(bool init); [DllImport("shell32.dll", SetLastError = true, EntryPoint = "#181")] - public static extern bool RegisterShellHook(IntPtr hwnd, int fInstall); + public static extern bool RegisterShellHook(IntPtr hwnd, int fInstall); + [DllImport("user32.dll", SetLastError = true)] + [return: MarshalAs(UnmanagedType.U2)] + public static extern ushort RegisterClassExW([In] ref WNDCLASSEX lpwcx); + [DllImport("user32.dll", SetLastError = true, CharSet =CharSet.Unicode)] + public static extern IntPtr CreateWindowExW( + uint dwExStyle, + string lpClassName, + string lpWindowName, + uint dwStyle, + int x, + int y, + int nWidth, + int nHeight, + IntPtr hWndParent, + IntPtr hMenu, + IntPtr hInstance, + IntPtr lpParam); + [DllImport("user32.dll")] + public static extern IntPtr DefWindowProcW(nint hWnd, uint uMsg, nint wParam, nint lParam); + [DllImport("user32.dll")] + public static extern bool SetTaskmanWindow(nint hWnd); + [DllImport("user32.dll")] + public static extern nint GetTaskmanWindow(); + + [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto)] + public struct WNDCLASSEX + { + [MarshalAs(UnmanagedType.U4)] + public int cbSize; + [MarshalAs(UnmanagedType.U4)] + public int style; + public IntPtr lpfnWndProc; // not WndProc + public int cbClsExtra; + public int cbWndExtra; + public IntPtr hInstance; + public IntPtr hIcon; + public IntPtr hCursor; + public IntPtr hbrBackground; + public string lpszMenuName; + public string lpszClassName; + public IntPtr hIconSm; + + //Use this function to make a new one with cbSize already filled in. + //For example: + //var WndClss = WNDCLASSEX.Build() + public static WNDCLASSEX Build() + { + var nw = new WNDCLASSEX(); + nw.cbSize = Marshal.SizeOf(typeof(WNDCLASSEX)); + return nw; + } + } + [StructLayout(LayoutKind.Sequential)] public struct SYSTEM_INFO @@ -491,6 +547,36 @@ public enum WindowZOrder } [DllImport("UXTheme.dll", SetLastError = true, EntryPoint = "#138")] - public static extern bool ShouldSystemUseDarkMode(); + public static extern bool ShouldSystemUseDarkMode(); + + [ComImport] + [Guid("914d9b3a-5e53-4e14-bbba-46062acb35a4")] + [InterfaceType(ComInterfaceType.InterfaceIsIUnknown)] + public interface IImmersiveShellHookService + { + int Register(); //TODO args + int Unregister(uint cookie); + int PostShellHookMessage(nint wparam, nint lparam); + int SetTargetWindowForSerialization(nint hwnd); + int PostShellHookMessageWithSerialization();//todo: args + int UpdateWindowApplicationId(nint hwnd, string pszAppid); + int HandleWindowReplacement(nint hwndOld, nint hwndNew); + bool IsExecutionOnSerializedThread(); + } + [ComImport] + [Guid("6d5140c1-7436-11ce-8034-00aa006009fa")] + [InterfaceType(ComInterfaceType.InterfaceIsIUnknown)] + public interface IServiceProvider + { + int QueryService(ref Guid guidService, ref Guid riid, + [MarshalAs(UnmanagedType.Interface)] out object ppvObject); + } + [ComImport] + [Guid("c2f03a33-21f5-47fa-b4bb-156362a2f239")] + [ClassInterface(ClassInterfaceType.None)] + public class CImmersiveShell + { + + } } } \ No newline at end of file diff --git a/GyroShell.Library/Helpers/Win32/WindowChecks.cs b/GyroShell.Library/Helpers/Win32/WindowChecks.cs index eb45b73..07523e7 100644 --- a/GyroShell.Library/Helpers/Win32/WindowChecks.cs +++ b/GyroShell.Library/Helpers/Win32/WindowChecks.cs @@ -62,7 +62,7 @@ private static bool IsCloaked(IntPtr hWnd) private static bool ClassNameCheck(IntPtr hWnd) { - GetClassName(hWnd, className, className.Capacity); + GetClassNameW(hWnd, className, className.Capacity); if (className.ToString() == "ApplicationFrameWindow" || className.ToString() == "Windows.UI.Core.CoreWindow") { diff --git a/GyroShell.sln b/GyroShell.sln index ed6d5f8..7e540d8 100644 --- a/GyroShell.sln +++ b/GyroShell.sln @@ -4,6 +4,9 @@ Microsoft Visual Studio Solution File, Format Version 12.00 VisualStudioVersion = 17.3.32922.545 MinimumVisualStudioVersion = 10.0.40219.1 Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "GyroShell", "GyroShell\GyroShell.csproj", "{9489365D-B182-45AD-A7BF-F6D942949A5A}" + ProjectSection(ProjectDependencies) = postProject + {617AEA24-0755-490C-BC05-6DBB5E2059E0} = {617AEA24-0755-490C-BC05-6DBB5E2059E0} + EndProjectSection EndProject Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{9C6095DC-1FBF-4CF2-9225-F8E391132412}" ProjectSection(SolutionItems) = preProject @@ -12,6 +15,8 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "GyroShell.Library", "GyroShell.Library\GyroShell.Library.csproj", "{1623C0B8-50B8-4904-92F8-BDB6999BCEE1}" EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "GyroShell.ImmersiveShellHook", "GyroShell.ImmersiveShellHook\GyroShell.ImmersiveShellHook.vcxproj", "{617AEA24-0755-490C-BC05-6DBB5E2059E0}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -64,6 +69,22 @@ Global {1623C0B8-50B8-4904-92F8-BDB6999BCEE1}.Release|x64.Build.0 = Release|Any CPU {1623C0B8-50B8-4904-92F8-BDB6999BCEE1}.Release|x86.ActiveCfg = Release|Any CPU {1623C0B8-50B8-4904-92F8-BDB6999BCEE1}.Release|x86.Build.0 = Release|Any CPU + {617AEA24-0755-490C-BC05-6DBB5E2059E0}.Debug|Any CPU.ActiveCfg = Debug|x64 + {617AEA24-0755-490C-BC05-6DBB5E2059E0}.Debug|Any CPU.Build.0 = Debug|x64 + {617AEA24-0755-490C-BC05-6DBB5E2059E0}.Debug|arm64.ActiveCfg = Debug|x64 + {617AEA24-0755-490C-BC05-6DBB5E2059E0}.Debug|arm64.Build.0 = Debug|x64 + {617AEA24-0755-490C-BC05-6DBB5E2059E0}.Debug|x64.ActiveCfg = Debug|x64 + {617AEA24-0755-490C-BC05-6DBB5E2059E0}.Debug|x64.Build.0 = Debug|x64 + {617AEA24-0755-490C-BC05-6DBB5E2059E0}.Debug|x86.ActiveCfg = Debug|Win32 + {617AEA24-0755-490C-BC05-6DBB5E2059E0}.Debug|x86.Build.0 = Debug|Win32 + {617AEA24-0755-490C-BC05-6DBB5E2059E0}.Release|Any CPU.ActiveCfg = Release|x64 + {617AEA24-0755-490C-BC05-6DBB5E2059E0}.Release|Any CPU.Build.0 = Release|x64 + {617AEA24-0755-490C-BC05-6DBB5E2059E0}.Release|arm64.ActiveCfg = Release|x64 + {617AEA24-0755-490C-BC05-6DBB5E2059E0}.Release|arm64.Build.0 = Release|x64 + {617AEA24-0755-490C-BC05-6DBB5E2059E0}.Release|x64.ActiveCfg = Release|x64 + {617AEA24-0755-490C-BC05-6DBB5E2059E0}.Release|x64.Build.0 = Release|x64 + {617AEA24-0755-490C-BC05-6DBB5E2059E0}.Release|x86.ActiveCfg = Release|Win32 + {617AEA24-0755-490C-BC05-6DBB5E2059E0}.Release|x86.Build.0 = Release|Win32 EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE diff --git a/GyroShell/Controls/StartupWindow.xaml.cs b/GyroShell/Controls/StartupWindow.xaml.cs index a9ba2fc..6049cb8 100644 --- a/GyroShell/Controls/StartupWindow.xaml.cs +++ b/GyroShell/Controls/StartupWindow.xaml.cs @@ -59,7 +59,7 @@ internal StartupWindow() OverlappedPresenter presenter = GetAppWindowAndPresenter(); presenter.IsMaximizable = false; presenter.IsMinimizable = false; - presenter.IsAlwaysOnTop = true; + presenter.IsAlwaysOnTop = false; presenter.IsResizable = false; presenter.SetBorderAndTitleBar(false, false); m_AppWindow = GetAppWindowForCurrentWindow(); @@ -101,7 +101,7 @@ private void CloseTimer_Elapsed(object sender, ElapsedEventArgs e) private new void Close() { - MessageBox(hWnd, "If you keep seeing this message, please contact the developers.", "GyroShell was unable to start.", 0x00000000 | 0x00000030); + MessageBoxW(hWnd, "If you keep seeing this message, please contact the developers.", "GyroShell was unable to start.", 0x00000000 | 0x00000030); m_explorerManager.ShowTaskbar(); appProcess.Kill(); } diff --git a/GyroShell/GyroShell.csproj b/GyroShell/GyroShell.csproj index 77c1a07..9cdd5a2 100644 --- a/GyroShell/GyroShell.csproj +++ b/GyroShell/GyroShell.csproj @@ -1,132 +1,147 @@ - - - WinExe - net6.0-windows10.0.19041.0 - 10.0.17763.0 - GyroShell - app.manifest - x86;x64;arm64 - win10-x86;win10-x64;win10-arm64 - win10-$(Platform).pubxml - true - true - -include WindowsUdk - true - False - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - true - - - - - - - - - - - - - - - - - - - + + + WinExe + net6.0-windows10.0.19041.0 + 10.0.17763.0 + GyroShell + app.manifest + x86;x64;arm64 + win10-x86;win10-x64;win10-arm64 + win10-$(Platform).pubxml + true + true + -include WindowsUdk + true + False + true + copy /Y $(SolutionDir)$(Platform)\$(Configuration)\rmclient.dll $(SolutionDir)\GyroShell\Resources\rmclient.dll + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + true + + + + + + + + + + + + + + + + + + + - + + + + True + True + Resources.resx + + + + + ResXFileCodeGenerator + Resources.Designer.cs + + MSBuild:Compile - + MSBuild:Compile - + MSBuild:Compile - - - - MSBuild:Compile - - - - - MSBuild:Compile - - - - - MSBuild:Compile - - - - - MSBuild:Compile - - - - - MSBuild:Compile - - - - - MSBuild:Compile - - + + + + MSBuild:Compile + + + + + MSBuild:Compile + + + + + MSBuild:Compile + + + + + MSBuild:Compile + + + + + MSBuild:Compile + + + + + MSBuild:Compile + + MSBuild:Compile - - + + diff --git a/GyroShell/Properties/Resources.Designer.cs b/GyroShell/Properties/Resources.Designer.cs new file mode 100644 index 0000000..c27c999 --- /dev/null +++ b/GyroShell/Properties/Resources.Designer.cs @@ -0,0 +1,73 @@ +//------------------------------------------------------------------------------ +// +// This code was generated by a tool. +// Runtime Version:4.0.30319.42000 +// +// Changes to this file may cause incorrect behavior and will be lost if +// the code is regenerated. +// +//------------------------------------------------------------------------------ + +namespace GyroShell.Properties { + using System; + + + /// + /// A strongly-typed resource class, for looking up localized strings, etc. + /// + // This class was auto-generated by the StronglyTypedResourceBuilder + // class via a tool like ResGen or Visual Studio. + // To add or remove a member, edit your .ResX file then rerun ResGen + // with the /str option, or rebuild your VS project. + [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "17.0.0.0")] + [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] + [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()] + internal class Resources { + + private static global::System.Resources.ResourceManager resourceMan; + + private static global::System.Globalization.CultureInfo resourceCulture; + + [global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + internal Resources() { + } + + /// + /// Returns the cached ResourceManager instance used by this class. + /// + [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] + internal static global::System.Resources.ResourceManager ResourceManager { + get { + if (object.ReferenceEquals(resourceMan, null)) { + global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("GyroShell.Properties.Resources", typeof(Resources).Assembly); + resourceMan = temp; + } + return resourceMan; + } + } + + /// + /// Overrides the current thread's CurrentUICulture property for all + /// resource lookups using this strongly typed resource class. + /// + [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] + internal static global::System.Globalization.CultureInfo Culture { + get { + return resourceCulture; + } + set { + resourceCulture = value; + } + } + + /// + /// Looks up a localized resource of type System.Byte[]. + /// + internal static byte[] ImmersiveShellHook { + get { + object obj = ResourceManager.GetObject("ImmersiveShellHook", resourceCulture); + return ((byte[])(obj)); + } + } + } +} diff --git a/GyroShell/Properties/Resources.resx b/GyroShell/Properties/Resources.resx new file mode 100644 index 0000000..25352f0 --- /dev/null +++ b/GyroShell/Properties/Resources.resx @@ -0,0 +1,124 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + + ..\Resources\rmclient.dll;System.Byte[], mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + \ No newline at end of file diff --git a/GyroShell/Services/Helpers/IconHelperService.cs b/GyroShell/Services/Helpers/IconHelperService.cs index ea89964..a2e9469 100644 --- a/GyroShell/Services/Helpers/IconHelperService.cs +++ b/GyroShell/Services/Helpers/IconHelperService.cs @@ -1,140 +1,145 @@ -#region Copyright (BSD 3-Clause License) -/* - * GyroShell - A modern, extensible, fast, and customizable shell platform. - * Copyright 2022-2024 Pdawg - * - * Licensed under the BSD 3-Clause License. - * SPDX-License-Identifier: BSD-3-Clause - */ -#endregion - -using GyroShell.Library.Services.Helpers; -using Microsoft.UI.Xaml.Media.Imaging; -using System; -using System.Diagnostics; -using System.Drawing; -using System.Drawing.Imaging; -using System.Runtime.InteropServices.WindowsRuntime; -using System.Runtime.InteropServices; -using Windows.Graphics.Imaging; -using static GyroShell.Library.Helpers.Win32.Win32Interop; - -namespace GyroShell.Services.Helpers -{ - public class IconHelperService : IIconHelperService - { - private readonly IBitmapHelperService m_bmpHelper; - private readonly IAppHelperService m_appHelper; - - public IconHelperService(IBitmapHelperService bmpHelper, IAppHelperService appHelper) - { - m_bmpHelper = bmpHelper; - m_appHelper = appHelper; - } - - - public bool IsUwpWindow(IntPtr hWnd) => - m_appHelper.GetPackageFromAppHandle(hWnd) != null; - - public SoftwareBitmapSource GetUwpOrWin32Icon(IntPtr hWnd, int targetSize) - { - if (IsUwpWindow(hWnd)) - { - return ConvertIconBitmapToSoftwareBitmapSource(GetUWPBitmap(hWnd)); - } - else - { - return ConvertIconBitmapToSoftwareBitmapSource(GetWin32Bitmap(hWnd, 32)); - } - } - - - #region Win32 - private Bitmap GetWin32Bitmap(IntPtr hWnd, int targetSize) - { - try - { - GetWindowThreadProcessId(hWnd, out uint pid); - Process proc = Process.GetProcessById((int)pid); - Icon icon = Icon.ExtractAssociatedIcon(proc.MainModule.FileName); - - if (icon != null) - { - Bitmap resizedBitmap = new Bitmap(icon.ToBitmap(), new Size(targetSize, targetSize)); - Icon resizedIcon = Icon.FromHandle(resizedBitmap.GetHicon()); - return resizedIcon.ToBitmap(); - } - return null; - } - catch (Exception ex) - { - Debug.WriteLine("GetHandleIcon => GetIcon: " + ex.Message); - return null; - } - } - #endregion - - #region UWP - private Bitmap GetUWPBitmap(IntPtr hWnd) - { - try - { - string iconPath = m_appHelper.GetUwpAppIconPath(hWnd); - return (Bitmap)Image.FromFile(iconPath); - - /*using (IRandomAccessStream stream = await m_appHelper.GetUwpIconStream(hWnd).OpenReadAsync()) - { - BitmapDecoder decoder = await BitmapDecoder.CreateAsync(stream); - SoftwareBitmap softwareBitmap = await decoder.GetSoftwareBitmapAsync(); - - Bitmap bitmap; - using (MemoryStream memoryStream = new MemoryStream()) - { - BitmapEncoder encoder = await BitmapEncoder.CreateAsync(BitmapEncoder.PngEncoderId, memoryStream.AsRandomAccessStream()); - encoder.SetSoftwareBitmap(softwareBitmap); - await encoder.FlushAsync(); - - memoryStream.Seek(0, SeekOrigin.Begin); - - using (MemoryStream copiedStream = new MemoryStream()) - { - await memoryStream.CopyToAsync(copiedStream); - copiedStream.Seek(0, SeekOrigin.Begin); - bitmap = new Bitmap(copiedStream); - } - } - - return bitmap; - }*/ - } - catch (Exception e) - { - Debug.WriteLine(e.Message); - return null; - } - } - #endregion - - #region Common - private SoftwareBitmapSource ConvertIconBitmapToSoftwareBitmapSource(Bitmap bmp) - { - using (Bitmap croppedBmp = m_bmpHelper.RemoveTransparentPadding(bmp)) - { - Bitmap resampledBmp = m_bmpHelper.FilterAndScaleBitmap(croppedBmp, croppedBmp.Width, croppedBmp.Height); - - BitmapData data = resampledBmp.LockBits(new Rectangle(0, 0, resampledBmp.Width, resampledBmp.Height), ImageLockMode.ReadOnly, resampledBmp.PixelFormat); - byte[] bytes = new byte[data.Stride * data.Height]; - Marshal.Copy(data.Scan0, bytes, 0, bytes.Length); - resampledBmp.UnlockBits(data); - - SoftwareBitmap softwareBitmap = new SoftwareBitmap(BitmapPixelFormat.Bgra8, resampledBmp.Width, resampledBmp.Height, BitmapAlphaMode.Premultiplied); - softwareBitmap.CopyFromBuffer(bytes.AsBuffer()); - - SoftwareBitmapSource source = new SoftwareBitmapSource(); - source.SetBitmapAsync(softwareBitmap); - return source; - } - } - #endregion - } +#region Copyright (BSD 3-Clause License) +/* + * GyroShell - A modern, extensible, fast, and customizable shell platform. + * Copyright 2022-2024 Pdawg + * + * Licensed under the BSD 3-Clause License. + * SPDX-License-Identifier: BSD-3-Clause + */ +#endregion + +using GyroShell.Library.Services.Helpers; +using Microsoft.UI.Xaml.Media.Imaging; +using System; +using System.Diagnostics; +using System.Drawing; +using System.Drawing.Imaging; +using System.Runtime.InteropServices.WindowsRuntime; +using System.Runtime.InteropServices; +using Windows.Graphics.Imaging; +using static GyroShell.Library.Helpers.Win32.Win32Interop; + +namespace GyroShell.Services.Helpers +{ + public class IconHelperService : IIconHelperService + { + private readonly IBitmapHelperService m_bmpHelper; + private readonly IAppHelperService m_appHelper; + + public IconHelperService(IBitmapHelperService bmpHelper, IAppHelperService appHelper) + { + m_bmpHelper = bmpHelper; + m_appHelper = appHelper; + } + + + public bool IsUwpWindow(IntPtr hWnd) => + m_appHelper.GetPackageFromAppHandle(hWnd) != null; + + public SoftwareBitmapSource GetUwpOrWin32Icon(IntPtr hWnd, int targetSize) + { + if (IsUwpWindow(hWnd)) + { + return ConvertIconBitmapToSoftwareBitmapSource(GetUWPBitmap(hWnd)); + } + else + { + return ConvertIconBitmapToSoftwareBitmapSource(GetWin32Bitmap(hWnd, 32)); + } + } + + + #region Win32 + private Bitmap GetWin32Bitmap(IntPtr hWnd, int targetSize) + { + try + { + GetWindowThreadProcessId(hWnd, out uint pid); + Process proc = Process.GetProcessById((int)pid); + Icon icon = Icon.ExtractAssociatedIcon(proc.MainModule.FileName); + + if (icon != null) + { + Bitmap resizedBitmap = new Bitmap(icon.ToBitmap(), new Size(targetSize, targetSize)); + Icon resizedIcon = Icon.FromHandle(resizedBitmap.GetHicon()); + return resizedIcon.ToBitmap(); + } + return null; + } + catch (Exception ex) + { + Debug.WriteLine("GetHandleIcon => GetIcon: " + ex.Message); + return null; + } + } + #endregion + + #region UWP + private Bitmap GetUWPBitmap(IntPtr hWnd) + { + try + { + string iconPath = m_appHelper.GetUwpAppIconPath(hWnd); + return (Bitmap)Image.FromFile(iconPath); + + /*using (IRandomAccessStream stream = await m_appHelper.GetUwpIconStream(hWnd).OpenReadAsync()) + { + BitmapDecoder decoder = await BitmapDecoder.CreateAsync(stream); + SoftwareBitmap softwareBitmap = await decoder.GetSoftwareBitmapAsync(); + + Bitmap bitmap; + using (MemoryStream memoryStream = new MemoryStream()) + { + BitmapEncoder encoder = await BitmapEncoder.CreateAsync(BitmapEncoder.PngEncoderId, memoryStream.AsRandomAccessStream()); + encoder.SetSoftwareBitmap(softwareBitmap); + await encoder.FlushAsync(); + + memoryStream.Seek(0, SeekOrigin.Begin); + + using (MemoryStream copiedStream = new MemoryStream()) + { + await memoryStream.CopyToAsync(copiedStream); + copiedStream.Seek(0, SeekOrigin.Begin); + bitmap = new Bitmap(copiedStream); + } + } + + return bitmap; + }*/ + } + catch (Exception e) + { + Debug.WriteLine(e.Message); + return null; + } + } + #endregion + + #region Common + private SoftwareBitmapSource ConvertIconBitmapToSoftwareBitmapSource(Bitmap bmp) + { + if (bmp == null) + { + return null; + } + + using (Bitmap croppedBmp = m_bmpHelper.RemoveTransparentPadding(bmp)) + { + Bitmap resampledBmp = m_bmpHelper.FilterAndScaleBitmap(croppedBmp, croppedBmp.Width, croppedBmp.Height); + + BitmapData data = resampledBmp.LockBits(new Rectangle(0, 0, resampledBmp.Width, resampledBmp.Height), ImageLockMode.ReadOnly, resampledBmp.PixelFormat); + byte[] bytes = new byte[data.Stride * data.Height]; + Marshal.Copy(data.Scan0, bytes, 0, bytes.Length); + resampledBmp.UnlockBits(data); + + SoftwareBitmap softwareBitmap = new SoftwareBitmap(BitmapPixelFormat.Bgra8, resampledBmp.Width, resampledBmp.Height, BitmapAlphaMode.Premultiplied); + softwareBitmap.CopyFromBuffer(bytes.AsBuffer()); + + SoftwareBitmapSource source = new SoftwareBitmapSource(); + source.SetBitmapAsync(softwareBitmap); + return source; + } + } + #endregion + } } \ No newline at end of file diff --git a/GyroShell/Services/Managers/ExplorerManagerService.cs b/GyroShell/Services/Managers/ExplorerManagerService.cs index 41bd61e..9571668 100644 --- a/GyroShell/Services/Managers/ExplorerManagerService.cs +++ b/GyroShell/Services/Managers/ExplorerManagerService.cs @@ -11,6 +11,9 @@ using GyroShell.Library.Events; using GyroShell.Library.Services.Managers; using System; +using System.ComponentModel; +using System.Diagnostics; +using System.IO; using System.Runtime.InteropServices; using static GyroShell.Library.Helpers.Win32.Win32Interop; @@ -22,20 +25,146 @@ internal class ExplorerManagerService : IExplorerManagerService public IntPtr m_hTaskBar { get; set; } public IntPtr m_hMultiTaskBar { get; set; } - public IntPtr m_hStartMenu { get; set; } + public IntPtr m_hStartMenu { get; set; } + + private static Guid SID_ImmersiveShellHookService = new Guid("4624bd39-5fc3-44a8-a809-163a836e9031"); + private static Guid ImmersiveShellHookServiceInterface = new Guid("914d9b3a-5e53-4e14-bbba-46062acb35a4"); + private static IImmersiveShellHookService? HookService; public void Initialize() { - m_hTaskBar = FindWindow("Shell_TrayWnd", null); - m_hMultiTaskBar = FindWindow("Shell_SecondaryTrayWnd", null); - m_hStartMenu = FindWindowEx(m_hStartMenu, IntPtr.Zero, "Button", "Start"); - + //m_hTaskBar = FindWindowW("Shell_TrayWnd", null); + //m_hMultiTaskBar = FindWindowW("Shell_SecondaryTrayWnd", null); + //m_hStartMenu = FindWindowExW(m_hStartMenu, IntPtr.Zero, "Button", "Start"); + if (m_hStartMenu == IntPtr.Zero) { - m_hStartMenu = FindWindow("Button", null); - } - } - + m_hStartMenu = FindWindowW("Button", null); + } + + RegisterTaskmanWindow(); + + /* In order to allow Immersive processes (packaged apps, uwp apps, etc) to run, we need to use the CImmersiveShellController interface. + However, that API requires IAM access, which means that the app must be signed by Microsoft and must have the .imsrv PE header section. + In order to circumvent this, we need to copy runtimebroker.exe to a temp folder which meets those requirements, inject a DLL into it + to replace WinMain with our own, and then run it. This will allow us to start the Immersive Shell Controller and allow Immersive processes to run. + + Copy runtimebroker.exe to a temp folder, write injected dll, and start it. + */ + + string tempPath = Path.Combine(System.Environment.GetFolderPath(System.Environment.SpecialFolder.LocalApplicationData), "Temp", "GyroshellImmersiveUtility"); + string process = Path.Combine(tempPath, "GryoShellImmersiveShell.exe"); + Directory.CreateDirectory(tempPath); + + // todo: remove this hack + Process.Start("taskkill", "/f /im GryoShellImmersiveShell.exe").WaitForExit(); + Process.Start("taskkill", "/f /im explorer.exe").WaitForExit(); + + try + { + File.Delete(process); + File.Delete(Path.Combine(tempPath, "rmclient.dll")); + } + catch + { + Debugger.Break(); + } + + File.Copy(Path.Combine(System.Environment.GetFolderPath(System.Environment.SpecialFolder.System), "RuntimeBroker.exe"), process, true); + File.WriteAllBytes(Path.Combine(tempPath, "rmclient.dll"), Properties.Resources.ImmersiveShellHook); + + // start the process + Process.Start(process); + } + private static uint windowMessage; + delegate nint WndProcDelegate(nint hwnd, uint message, nint wParam, nint lParam); + private static nint TaskmanWindowProc(nint hwnd, uint message, nint wParam, nint lParam) + { + if (message == 1) + { + // WM_CREATE + //if (!SetTaskmanWindow(hwnd)) + //{ + // throw new Win32Exception(); + //} + // TODO: This causes an issue?? + windowMessage = RegisterWindowMessageW("SHELLHOOK"); + if (!RegisterShellHookWindow(hwnd)) + { + throw new Win32Exception(); + } + } + //else if (message == 2) + //{ + // // WM_DESTROY + // if (GetTaskmanWindow() == hwnd) + // { + // SetTaskmanWindow(0); + // } + // DeregisterShellHookWindow(hwnd); + //} + //else if (message == windowMessage || message == 0x312) //WM_HOTKEY + //{ + // if (HookService == null) + // { + // var x = (Library.Helpers.Win32.Win32Interop.IServiceProvider)new CImmersiveShell(); + // if (x.QueryService(ref SID_ImmersiveShellHookService, ref ImmersiveShellHookServiceInterface, out object shellhooksrv) < 0) + // { + // Console.WriteLine("failed to get the immersive shell hook service"); + // return 0; + // } + // else + // { + // HookService = (IImmersiveShellHookService)shellhooksrv; + // } + + // return 0; + // } + + // // Pass the message to TwinUI to allow UWP apps to work correctly. + + // bool handle = true; + // if (wParam == 12) + // { + // Console.WriteLine("set window"); + // HookService.SetTargetWindowForSerialization(lParam); + // } + // else if (wParam == 0x32) + // { + // handle = false; + // } + // if (handle) + // { + // HookService.PostShellHookMessage(wParam, lParam); + // } + // return 0; + //} + + return DefWindowProcW(hwnd, message, wParam, lParam); + } + private void RegisterTaskmanWindow() + { + WNDCLASSEX progman = WNDCLASSEX.Build(); + progman.style = 8; + progman.hInstance = Marshal.GetHINSTANCE(typeof(ExplorerManagerService).Module); + progman.lpszClassName = "TaskmanWndClass"; + //progman.lpfnWndProc = Marshal.GetFunctionPointerForDelegate((WndProcDelegate)TaskmanWindowProc); + + ushort atom = RegisterClassExW(ref progman); + if (atom == 0) + { + // throw new Win32Exception(); + return; + } + + var hwnd = CreateWindowExW(0, progman.lpszClassName, null, 0x82000000, 0, 0, 0, 0, IntPtr.Zero, IntPtr.Zero, Marshal.GetHINSTANCE(typeof(ExplorerManagerService).Module), IntPtr.Zero); + + if (hwnd == IntPtr.Zero) + { + // throw new Win32Exception(); + } + } + public event EventHandler SystemControlStateChanged; private bool _isStartMenuOpen; From 1ff227e348cc058a54499f4a3436cb32eba6fe6a Mon Sep 17 00:00:00 2001 From: Mikhail Date: Sun, 7 Jul 2024 16:24:48 -0400 Subject: [PATCH 2/2] fixes --- .../Helpers/Win32/Win32Interop.cs | 6 +- .../Managers/ExplorerManagerService.cs | 114 +++++++++--------- 2 files changed, 62 insertions(+), 58 deletions(-) diff --git a/GyroShell.Library/Helpers/Win32/Win32Interop.cs b/GyroShell.Library/Helpers/Win32/Win32Interop.cs index afaeb6f..6e1f6c5 100644 --- a/GyroShell.Library/Helpers/Win32/Win32Interop.cs +++ b/GyroShell.Library/Helpers/Win32/Win32Interop.cs @@ -175,7 +175,7 @@ public enum GetWindowType : uint public static extern bool IsWindowVisible(IntPtr hWnd); [DllImport("user32.dll", SetLastError = true)] - public static extern IntPtr FindWindowW(string lpClassName, string lpWindowName); + public static extern IntPtr FindWindow(string lpClassName, string lpWindowName); [DllImport("user32.dll")] [return: MarshalAs(UnmanagedType.Bool)] @@ -204,7 +204,7 @@ public enum GetWindowType : uint public static extern int GetWindowTextLength(IntPtr hWnd); [DllImport("user32.dll", SetLastError = true)] - public static extern IntPtr FindWindowExW(IntPtr parentHandle, IntPtr childAfter, string className, string windowTitle); + public static extern IntPtr FindWindowEx(IntPtr parentHandle, IntPtr childAfter, string className, string windowTitle); [DllImport("user32.dll")] public static extern int ShowWindow(IntPtr hwnd, int nCmdShow); @@ -310,7 +310,7 @@ public static extern IntPtr CreateWindowExW( IntPtr lpParam); [DllImport("user32.dll")] public static extern IntPtr DefWindowProcW(nint hWnd, uint uMsg, nint wParam, nint lParam); - [DllImport("user32.dll")] + [DllImport("user32.dll", SetLastError = true)] public static extern bool SetTaskmanWindow(nint hWnd); [DllImport("user32.dll")] public static extern nint GetTaskmanWindow(); diff --git a/GyroShell/Services/Managers/ExplorerManagerService.cs b/GyroShell/Services/Managers/ExplorerManagerService.cs index 9571668..b57df11 100644 --- a/GyroShell/Services/Managers/ExplorerManagerService.cs +++ b/GyroShell/Services/Managers/ExplorerManagerService.cs @@ -33,13 +33,19 @@ internal class ExplorerManagerService : IExplorerManagerService public void Initialize() { - //m_hTaskBar = FindWindowW("Shell_TrayWnd", null); - //m_hMultiTaskBar = FindWindowW("Shell_SecondaryTrayWnd", null); - //m_hStartMenu = FindWindowExW(m_hStartMenu, IntPtr.Zero, "Button", "Start"); + m_hTaskBar = FindWindow("Shell_TrayWnd", null); + m_hMultiTaskBar = FindWindow("Shell_SecondaryTrayWnd", null); + m_hStartMenu = FindWindowEx(m_hStartMenu, IntPtr.Zero, "Button", "Start"); if (m_hStartMenu == IntPtr.Zero) { - m_hStartMenu = FindWindowW("Button", null); + m_hStartMenu = FindWindow("Button", null); + } + + if (m_hTaskBar != IntPtr.Zero) + { + // Explorer is probably already running. + return; } RegisterTaskmanWindow(); @@ -83,62 +89,61 @@ private static nint TaskmanWindowProc(nint hwnd, uint message, nint wParam, nint if (message == 1) { // WM_CREATE - //if (!SetTaskmanWindow(hwnd)) - //{ - // throw new Win32Exception(); - //} - // TODO: This causes an issue?? + if (!SetTaskmanWindow(hwnd)) + { + throw new Win32Exception(); + } windowMessage = RegisterWindowMessageW("SHELLHOOK"); if (!RegisterShellHookWindow(hwnd)) { throw new Win32Exception(); } } - //else if (message == 2) - //{ - // // WM_DESTROY - // if (GetTaskmanWindow() == hwnd) - // { - // SetTaskmanWindow(0); - // } - // DeregisterShellHookWindow(hwnd); - //} - //else if (message == windowMessage || message == 0x312) //WM_HOTKEY - //{ - // if (HookService == null) - // { - // var x = (Library.Helpers.Win32.Win32Interop.IServiceProvider)new CImmersiveShell(); - // if (x.QueryService(ref SID_ImmersiveShellHookService, ref ImmersiveShellHookServiceInterface, out object shellhooksrv) < 0) - // { - // Console.WriteLine("failed to get the immersive shell hook service"); - // return 0; - // } - // else - // { - // HookService = (IImmersiveShellHookService)shellhooksrv; - // } + else if (message == 2) + { + // WM_DESTROY + if (GetTaskmanWindow() == hwnd) + { + SetTaskmanWindow(0); + } + DeregisterShellHookWindow(hwnd); + } + else if (message == windowMessage || message == 0x312) //WM_HOTKEY + { + if (HookService == null) + { + var x = (Library.Helpers.Win32.Win32Interop.IServiceProvider)new CImmersiveShell(); + if (x.QueryService(ref SID_ImmersiveShellHookService, ref ImmersiveShellHookServiceInterface, out object shellhooksrv) < 0) + { + Console.WriteLine("failed to get the immersive shell hook service"); + return 0; + } + else + { + HookService = (IImmersiveShellHookService)shellhooksrv; + } - // return 0; - // } + return 0; + } - // // Pass the message to TwinUI to allow UWP apps to work correctly. + // Pass the message to TwinUI to allow UWP apps to work correctly. - // bool handle = true; - // if (wParam == 12) - // { - // Console.WriteLine("set window"); - // HookService.SetTargetWindowForSerialization(lParam); - // } - // else if (wParam == 0x32) - // { - // handle = false; - // } - // if (handle) - // { - // HookService.PostShellHookMessage(wParam, lParam); - // } - // return 0; - //} + bool handle = true; + if (wParam == 12) + { + Console.WriteLine("set window"); + HookService.SetTargetWindowForSerialization(lParam); + } + else if (wParam == 0x32) + { + handle = false; + } + if (handle) + { + HookService.PostShellHookMessage(wParam, lParam); + } + return 0; + } return DefWindowProcW(hwnd, message, wParam, lParam); } @@ -148,20 +153,19 @@ private void RegisterTaskmanWindow() progman.style = 8; progman.hInstance = Marshal.GetHINSTANCE(typeof(ExplorerManagerService).Module); progman.lpszClassName = "TaskmanWndClass"; - //progman.lpfnWndProc = Marshal.GetFunctionPointerForDelegate((WndProcDelegate)TaskmanWindowProc); + progman.lpfnWndProc = Marshal.GetFunctionPointerForDelegate((WndProcDelegate)TaskmanWindowProc); ushort atom = RegisterClassExW(ref progman); if (atom == 0) { - // throw new Win32Exception(); - return; + throw new Win32Exception(); } var hwnd = CreateWindowExW(0, progman.lpszClassName, null, 0x82000000, 0, 0, 0, 0, IntPtr.Zero, IntPtr.Zero, Marshal.GetHINSTANCE(typeof(ExplorerManagerService).Module), IntPtr.Zero); if (hwnd == IntPtr.Zero) { - // throw new Win32Exception(); + throw new Win32Exception(); } }