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 b7c883a..6e1f6c5 100644 --- a/GyroShell.Library/Helpers/Win32/Win32Interop.cs +++ b/GyroShell.Library/Helpers/Win32/Win32Interop.cs @@ -1,493 +1,579 @@ -#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 System; -using System.Runtime.InteropServices; -using System.Text; -using static GyroShell.Library.Interfaces.IPropertyStoreAUMID; - -namespace GyroShell.Library.Helpers.Win32 -{ - public static class Win32Interop - { - [StructLayout(LayoutKind.Sequential)] - public struct NativeRect - { - public int Left; - public int Top; - public int Right; - public int Bottom; - } - - [StructLayout(LayoutKind.Sequential)] - public struct RECT - { - public int left; - public int top; - public int right; - public int bottom; - } - - public const int WM_COMMAND = 0x0111; - public const int WM_SYSCOMMAND = 0x0112; - - public const int SC_MINIMIZE = 0xF020; - public const int SC_MOVE = 0xF010; - public const int SC_RESTORE = 0xF120; - public const int SC_SIZE = 0xF000; - public const int SC_CLOSE = 0xF060; - - public const int SW_RESTORE = 9; - public const int SW_MINIMIZE = 6; - public const int SW_SHOW = 5; - public const int SW_HIDE = 0; - public const int SW_MAXIMIZE = 3; - - public const int SPI_SETWORKAREA = 0x002F; - public const int SPI_GETWORKAREA = 0x0030; - - public const int SPIF_UPDATEINIFILE = 1; - - public const int GWL_EXSTYLE = -20; - public const int GWL_STYLE = -16; - - public const int DWMWA_CLOAKED = 14; - - public const int GCL_HICONSM = -34; - public const int GCL_HICON = -14; - - public const int ICON_SMALL = 0; - public const int ICON_BIG = 1; - public const int ICON_SMALL2 = 2; - public const int WM_GETICON = 0x7F; - - public const uint GA_PARENT = 1; - public const uint GA_ROOT = 2; - public const uint GA_ROOTOWNER = 3; - - public const int WS_EX_APPWINDOW = 0x00040000; - public const int WS_EX_TOOLWINDOW = 0x00000080; - public const int WS_EX_NOACTIVATE = 0x08000000; - public const int WS_EX_WINDOWEDGE = 0x100; - public const int WS_EX_TOPMOST = 0x00000008; - public const int WS_VISIBLE = 0x10000000; - public const int WS_CHILD = 0x40000000; - - public const int HSHELL_WINDOWCREATED = 1; - public const int HSHELL_WINDOWDESTROYED = 2; - public const int HSHELL_ACTIVATESHELLWINDOW = 3; - public const int HSHELL_WINDOWACTIVATED = 4; - public const int HSHELL_RUDEAPPACTIVATED = 32772; - public const int HSHELL_GETMINRECT = 5; - public const int HSHELL_REDRAW = 6; - public const int HSHELL_TASKMAN = 7; - public const int HSHELL_LANGUAGE = 8; - public const int HSHELL_SYSMENU = 9; - public const int HSHELL_ENDTASK = 10; - public const int HSHELL_ACCESSIBILITYSTATE = 11; - public const int HSHELL_APPCOMMAND = 12; - public const int HSHELL_WINDOWREPLACED = 13; - public const int HSHELL_WINDOWREPLACING = 14; - public const int HSHELL_MONITORCHANGED = 16; //A window is moved to a different monitor. - public const int HSHELL_HIGHBIT = 0x8000; - public const int HSHELL_FLASH = 0x8006; - - public const int FAPPCOMMAND_MASK = 0xF000; - - public const int GWLP_WNDPROC = -4; - public const int SM_CXSCREEN = 0; - public const int SM_CYSCREEN = 1; - - public const int WINEVENT_OUTOFCONTEXT = 0x0000; - public const int WINEVENT_SKIPOWNTHREAD = 0x0001; - public const int EVENT_SYSTEM_DESKTOPSWITCH = 0x0020; - public const int EVENT_OBJECT_CLOAKED = 0x8017; - public const int EVENT_OBJECT_UNCLOAKED = 0x8018; - public const int EVENT_OBJECT_NAMECHANGED = 0x800C; - public const int EVENT_OBJECT_DESTROY = 0x8001; - public const int EVENT_OBJECT_CREATE = 0x8000; - public const int WINEVENT_INCONTEXT = 4; - public const int WINEVENT_SKIPOWNPROCESS = 2; - public const int EVENT_SYSTEM_FOREGROUND = 3; - public const int WH_SHELL = 10; - public const int GW_OWNER = 4; - public const long OBJID_WINDOW = 0x00000000L; - - public const uint PROCESS_QUERY_INFORMATION = 0x0400; - - public const uint EWX_LOGOFF = 0x00000000; - - public delegate bool EnumThreadProc(IntPtr hwnd, IntPtr lParam); - - [DllImport("dwmapi.dll")] - public static extern int DwmGetWindowAttribute(IntPtr hwnd, int dwAttribute, out int pvAttribute, int cbAttribute); - - [DllImport("user32.dll", ExactSpelling = true)] - public static extern IntPtr GetAncestor(IntPtr hwnd, GetAncestorFlags flags); - public enum GetAncestorFlags - { - GetParent = 1, - GetRoot = 2, - GetRootOwner = 3 - } - - [DllImport("user32.dll", SetLastError = true)] - public static extern IntPtr GetWindow(IntPtr hWnd, GetWindowType uCmd); - public enum GetWindowType : uint - { - GW_HWNDFIRST = 0, - GW_HWNDLAST = 1, - GW_HWNDNEXT = 2, - GW_HWNDPREV = 3, - GW_OWNER = 4, - GW_CHILD = 5, - 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("PowrProf.dll")] - public static extern bool SetSuspendState(bool hibernate, bool forceCritical, bool disableWakeEvent); - - [DllImport("user32.dll")] - public static extern bool ExitWindowsEx(uint uFlags, uint dwReason); - - [DllImport("user32.dll")] - public static extern IntPtr GetForegroundWindow(); - - [DllImport("user32.dll")] - 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")] - [return: MarshalAs(UnmanagedType.Bool)] - public static extern bool IsWindowVisible(IntPtr hWnd); - - [DllImport("user32.dll", SetLastError = true)] - public static extern IntPtr FindWindow(string lpClassName, string lpWindowName); - - [DllImport("user32.dll")] - [return: MarshalAs(UnmanagedType.Bool)] - public static extern bool IsWindow(IntPtr hWnd); - - [DllImport("user32.dll", SetLastError = true)] - public static extern int GetWindowLong(IntPtr hWnd, int nIndex); - - [DllImport("user32.dll")] - public static extern int SetWindowLong(IntPtr hWnd, int nIndex, int dwNewLong); - - [DllImport("user32.dll", EntryPoint = "GetWindowLongPtr")] - public static extern IntPtr GetWindowLongPtr(IntPtr hWnd, int nIndex); - - public delegate void WinEventDelegate(IntPtr hWinEventHook, uint eventType, IntPtr hwnd, int idObject, int idChild, uint dwEventThread, uint dwmsEventTime); - [DllImport("user32.dll")] - public static extern IntPtr SetWinEventHook(uint eventMin, uint eventMax, IntPtr hmodWinEventProc, WinEventDelegate lpfnWinEventProc, uint idProcess, uint idThread, uint dwFlags); - - [DllImport("user32.dll")] - public static extern bool UnhookWinEvent(IntPtr hWinEventHook); - - [DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)] - public static extern int GetWindowText(IntPtr hWnd, StringBuilder lpString, int nMaxCount); - - [DllImport("user32.dll", SetLastError = true, CharSet = CharSet.Auto)] - 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); - - [DllImport("user32.dll")] - public static extern int ShowWindow(IntPtr hwnd, int nCmdShow); - - [DllImport("Kernel32.dll", SetLastError = true)] - public static extern IntPtr OpenEvent(uint dwDesiredAccess, bool bInheritHandle, string lpName); - - [DllImport("kernel32.dll")] - public static extern bool SetEvent(IntPtr hEvent); - - [DllImport("kernel32", SetLastError = true)] - public static extern bool CloseHandle(IntPtr hObject); - - [DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)] - [return: MarshalAs(UnmanagedType.Bool)] - public static extern bool SystemParametersInfoA(uint uiAction, uint uiParam, ref NativeRect pvParam, uint fWinIni); - - public delegate bool MonitorEnumProc(IntPtr hMonitor, IntPtr hdcMonitor, ref NativeRect lprcMonitor, IntPtr dwData); - - [DllImport("User32.dll")] - public static extern bool EnumDisplayMonitors(IntPtr hdc, IntPtr lprcClip, MonitorEnumProc lpfnEnum, IntPtr dwData); - - [DllImport("User32.dll")] - public static extern int GetSystemMetrics(int nIndex); - - [DllImport("user32.dll", EntryPoint = "SetWindowLong")] // 32-bit Eq. of SetWindowLongPtr - public static extern IntPtr SetWindowLong(IntPtr hWnd, int nIndex, IntPtr dwNewLong); - - [DllImport("user32.dll", EntryPoint = "SetWindowLongPtr")] - public static extern IntPtr SetWindowLongPtr(IntPtr hWnd, int nIndex, IntPtr dwNewLong); - - [DllImport("user32.dll", CharSet = CharSet.Auto)] - public static extern IntPtr CallWindowProc(IntPtr lpPrevWndFunc, IntPtr hwnd, uint msg, IntPtr wParam, IntPtr lParam); - - [DllImport("user32.dll")] - public static extern IntPtr SendMessage(IntPtr hWnd, int wMsg, IntPtr wParam, IntPtr lParam); - - [DllImport("user32.dll")] - public static extern uint SendMessageTimeout(IntPtr hWnd, uint messageId, uint wparam, uint lparam, uint timeoutFlags, uint timeout, ref IntPtr retval); - - [DllImport("Shell32.dll", CharSet = CharSet.Auto, SetLastError = true)] - 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); - - [DllImport("user32.dll")] - public static extern bool DeregisterShellHookWindow(IntPtr hWnd); - - [DllImport("user32.dll", SetLastError = true)] - public static extern uint GetWindowThreadProcessId(IntPtr hWnd, out uint processId); - - [DllImport("kernel32.dll", SetLastError = true)] - public static extern IntPtr OpenProcess(uint processAccess, bool bInheritHandle, uint processId); - - public const uint ProcessQueryLimitedInformation = 0x1000; - - // DWM API attrib - public enum DWMWINDOWATTRIBUTE - { - DWMWA_WINDOW_CORNER_PREFERENCE = 33 - } - // Copied from dwmapi.h - public enum DWM_WINDOW_CORNER_PREFERENCE - { - DWMWCP_DEFAULT = 0, - DWMWCP_DONOTROUND = 1, - DWMWCP_ROUND = 2, - DWMWCP_ROUNDSMALL = 3 - } - // DwmSetWindowAttribute - [DllImport("dwmapi.dll", CharSet = CharSet.Unicode, PreserveSig = false)] - public static extern void DwmSetWindowAttribute(IntPtr hwnd, DWMWINDOWATTRIBUTE attribute, ref DWM_WINDOW_CORNER_PREFERENCE pvAttribute, uint cbAttribute); - - // Proc info API for unpackaged - [DllImport("kernel32.dll")] - public static extern void GetNativeSystemInfo(out SYSTEM_INFO lpSystemInfo); - - [DllImport("shell32.dll", SetLastError = true, EntryPoint = "#188")] - public static extern bool ShellDDEInit(bool init); - - [DllImport("shell32.dll", SetLastError = true, EntryPoint = "#181")] - public static extern bool RegisterShellHook(IntPtr hwnd, int fInstall); - - [StructLayout(LayoutKind.Sequential)] - public struct SYSTEM_INFO - { - public ushort wProcessorArchitecture; - public ushort wReserved; - public uint dwPageSize; - public IntPtr lpMinimumApplicationAddress; - public IntPtr lpMaximumApplicationAddress; - public IntPtr dwActiveProcessorMask; - public uint dwNumberOfProcessors; - public uint dwProcessorType; - public uint dwAllocationGranularity; - public ushort wProcessorLevel; - public ushort wProcessorRevision; - } - - // APPBAR code - [StructLayout(LayoutKind.Sequential)] - public struct APPBARDATA - { - public int cbSize; - public IntPtr hWnd; - public int uCallbackMessage; - public int uEdge; - public RECT rc; - public IntPtr lParam; - } - - public enum ABMsg : int - { - ABM_NEW = 0, - ABM_REMOVE, - ABM_QUERYPOS, - ABM_SETPOS, - ABM_GETSTATE, - ABM_GETTASKBARPOS, - ABM_ACTIVATE, - ABM_GETAUTOHIDEBAR, - ABM_SETAUTOHIDEBAR, - ABM_WINDOWPOSCHANGED, - ABM_SETSTATE - } - - public enum ABNotify : int - { - ABN_STATECHANGE = 0, - ABN_POSCHANGED, - ABN_FULLSCREENAPP, - ABN_WINDOWARRANGE - } - - public enum ABEdge : int - { - ABE_LEFT = 0, - ABE_TOP, - ABE_RIGHT, - ABE_BOTTOM - } - - public enum ABState - { - ABS_TOP = 0x00, - ABS_AUTOHIDE = 0x01 - } - - public delegate IntPtr WndProcDelegate(IntPtr hwnd, uint message, IntPtr wParam, IntPtr lParam); - - [DllImport("SHELL32", CallingConvention = CallingConvention.StdCall)] - public static extern uint SHAppBarMessage(int dwMessage, ref APPBARDATA pData); - - [DllImport("user32.dll", ExactSpelling = true, CharSet = CharSet.Auto)] - public static extern bool MoveWindow(IntPtr hWnd, int x, int y, int cx, int cy, bool repaint); - - [DllImport("user32.dll", CharSet = CharSet.Auto)] - public static extern int RegisterWindowMessage(string msg); - - [DllImport("user32.dll", SetLastError = true)] - public static extern bool SetWindowPos(IntPtr hWnd, IntPtr hWndInsertAfter, int X, int Y, int cx, int cy, uint uFlags); - - public enum SWPFlags - { - SWP_NOSIZE = 0x0001, - SWP_NOMOVE = 0x0002, - SWP_NOZORDER = 0x0004, - SWP_NOREDRAW = 0x0008, - SWP_NOACTIVATE = 0x0010, - SWP_DRAWFRAME = 0x0020, - SWP_FRAMECHANGED = 0x0020, - SWP_SHOWWINDOW = 0x0040, - SWP_HIDEWINDOW = 0x0080, - SWP_NOCOPYBITS = 0x0100, - SWP_NOOWNERZORDER = 0x0200, - SWP_NOREPOSITION = 0x0200, - SWP_NOSENDCHANGING = 0x0400, - SWP_DEFERERASE = 0x2000, - SWP_ASYNCWINDOWPOS = 0x4000 - } - - public enum WindowZOrder - { - HWND_TOP = 0, - HWND_BOTTOM = 1, - HWND_TOPMOST = -1, - HWND_NOTOPMOST = -2, - } - - [DllImport("UXTheme.dll", SetLastError = true, EntryPoint = "#138")] - public static extern bool ShouldSystemUseDarkMode(); - - - [DllImport("user32.dll", EntryPoint = "GetClassLongPtr")] - public static extern IntPtr GetClassLongPtr64(IntPtr hWnd, int nIndex); - - [StructLayout(LayoutKind.Sequential, Pack = 4)] - public struct PACKAGE_ID - { - public int reserved; - public AppxPackageArchitecture processorArchitecture; - public IntPtr version; - public IntPtr name; - public IntPtr publisher; - public IntPtr resourceId; - public IntPtr publisherId; - } - public enum AppxPackageArchitecture - { - x86 = 0, - Arm = 5, - x64 = 9, - Neutral = 11, - Arm64 = 12 - } - - [DllImport("psapi.dll")] - public static extern uint GetProcessImageFileName( - IntPtr hProcess, - [Out] StringBuilder lpImageFileName, - [In][MarshalAs(UnmanagedType.U4)] int nSize); - - [DllImport("kernel32.dll", CharSet = CharSet.Unicode, SetLastError = true)] - public static extern int GetPackagePathByFullName( - string packageFullName, - ref uint pathLength, - IntPtr path); - - [DllImport("ext-ms-win-ntuser-window-l1-1-4.dll")] - public static extern void SwitchToThisWindow(IntPtr hWnd, bool fUnknown); - - [DllImport("ole32.dll")] - public static extern int PropVariantClear(ref PropVariant pvar); - - [DllImport("shell32.dll")] - public static extern int SHGetPropertyStoreForWindow(IntPtr hwnd, ref Guid iid, [Out, MarshalAs(UnmanagedType.Interface)] out IPropertyStore propertyStore); - - [DllImport("user32.dll", EntryPoint = "#2573")] - public static extern bool IsShellFrameWindow(IntPtr hWnd); - - [DllImport("user32.dll")] - [return: MarshalAs(UnmanagedType.Bool)] - public static extern bool GetWindowBand([In] IntPtr hWnd, [Out] out UIntPtr pdwBand); - public enum ZBID : uint - { - ZBID_DEFAULT = 0, - ZBID_DESKTOP = 1, - ZBID_UIACCESS = 2, - ZBID_IMMERSIVE_IHM = 3, - ZBID_IMMERSIVE_NOTIFICATION = 4, - ZBID_IMMERSIVE_APPCHROME = 5, - ZBID_IMMERSIVE_MOGO = 6, - ZBID_IMMERSIVE_EDGY = 7, - ZBID_IMMERSIVE_INACTIVEMOBODY = 8, - ZBID_IMMERSIVE_INACTIVEDOCK = 9, - ZBID_IMMERSIVE_ACTIVEMOBODY = 10, - ZBID_IMMERSIVE_ACTIVEDOCK = 11, - ZBID_IMMERSIVE_BACKGROUND = 12, - ZBID_IMMERSIVE_SEARCH = 13, - ZBID_GENUINE_WINDOWS = 14, - ZBID_IMMERSIVE_RESTRICTED = 15, - ZBID_SYSTEM_TOOLS = 16, - ZBID_LOCK = 17, - ZBID_ABOVELOCK_UX = 18, - }; - - [DllImport("kernel32.dll", CharSet = CharSet.Unicode, SetLastError = true)] - public static extern int GetPackagesByPackageFamily( - string packageFamilyName, - ref uint count, - [Out, Optional] IntPtr packageFullNames, - ref uint bufferLength, - [Out, Optional] IntPtr buffer); - - [DllImport("user32.dll")] - [return: MarshalAs(UnmanagedType.Bool)] - public static extern bool SetForegroundWindow(IntPtr hWnd); - - [DllImport("user32.dll")] - public static extern IntPtr GetLastActivePopup(IntPtr hWnd); - - [DllImport("kernel32.dll", SetLastError = true, CharSet = CharSet.Auto)] - public static extern bool QueryFullProcessImageName(IntPtr hProcess, uint dwFlags, [Out, MarshalAs(UnmanagedType.LPTStr)] StringBuilder lpExeName, ref uint lpdwSize); - } +#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 System; +using System.Runtime.InteropServices; +using System.Text; +using static GyroShell.Library.Interfaces.IPropertyStoreAUMID; + +namespace GyroShell.Library.Helpers.Win32 +{ + public static class Win32Interop + { + [StructLayout(LayoutKind.Sequential)] + public struct NativeRect + { + public int Left; + public int Top; + public int Right; + public int Bottom; + } + + [StructLayout(LayoutKind.Sequential)] + public struct RECT + { + public int left; + public int top; + public int right; + public int bottom; + } + + public const int WM_COMMAND = 0x0111; + public const int WM_SYSCOMMAND = 0x0112; + + public const int SC_MINIMIZE = 0xF020; + public const int SC_MOVE = 0xF010; + public const int SC_RESTORE = 0xF120; + public const int SC_SIZE = 0xF000; + public const int SC_CLOSE = 0xF060; + + public const int SW_RESTORE = 9; + public const int SW_MINIMIZE = 6; + public const int SW_SHOW = 5; + public const int SW_HIDE = 0; + public const int SW_MAXIMIZE = 3; + + public const int SPI_SETWORKAREA = 0x002F; + public const int SPI_GETWORKAREA = 0x0030; + + public const int SPIF_UPDATEINIFILE = 1; + + public const int GWL_EXSTYLE = -20; + public const int GWL_STYLE = -16; + + public const int DWMWA_CLOAKED = 14; + + public const int GCL_HICONSM = -34; + public const int GCL_HICON = -14; + + public const int ICON_SMALL = 0; + public const int ICON_BIG = 1; + public const int ICON_SMALL2 = 2; + public const int WM_GETICON = 0x7F; + + public const uint GA_PARENT = 1; + public const uint GA_ROOT = 2; + public const uint GA_ROOTOWNER = 3; + + public const int WS_EX_APPWINDOW = 0x00040000; + public const int WS_EX_TOOLWINDOW = 0x00000080; + public const int WS_EX_NOACTIVATE = 0x08000000; + public const int WS_EX_WINDOWEDGE = 0x100; + public const int WS_EX_TOPMOST = 0x00000008; + public const int WS_VISIBLE = 0x10000000; + public const int WS_CHILD = 0x40000000; + + public const int HSHELL_WINDOWCREATED = 1; + public const int HSHELL_WINDOWDESTROYED = 2; + public const int HSHELL_ACTIVATESHELLWINDOW = 3; + public const int HSHELL_WINDOWACTIVATED = 4; + public const int HSHELL_RUDEAPPACTIVATED = 32772; + public const int HSHELL_GETMINRECT = 5; + public const int HSHELL_REDRAW = 6; + public const int HSHELL_TASKMAN = 7; + public const int HSHELL_LANGUAGE = 8; + public const int HSHELL_SYSMENU = 9; + public const int HSHELL_ENDTASK = 10; + public const int HSHELL_ACCESSIBILITYSTATE = 11; + public const int HSHELL_APPCOMMAND = 12; + public const int HSHELL_WINDOWREPLACED = 13; + public const int HSHELL_WINDOWREPLACING = 14; + public const int HSHELL_MONITORCHANGED = 16; //A window is moved to a different monitor. + public const int HSHELL_HIGHBIT = 0x8000; + public const int HSHELL_FLASH = 0x8006; + + public const int FAPPCOMMAND_MASK = 0xF000; + + public const int GWLP_WNDPROC = -4; + public const int SM_CXSCREEN = 0; + public const int SM_CYSCREEN = 1; + + public const int WINEVENT_OUTOFCONTEXT = 0x0000; + public const int WINEVENT_SKIPOWNTHREAD = 0x0001; + public const int EVENT_SYSTEM_DESKTOPSWITCH = 0x0020; + public const int EVENT_OBJECT_CLOAKED = 0x8017; + public const int EVENT_OBJECT_UNCLOAKED = 0x8018; + public const int EVENT_OBJECT_NAMECHANGED = 0x800C; + public const int EVENT_OBJECT_DESTROY = 0x8001; + public const int EVENT_OBJECT_CREATE = 0x8000; + public const int WINEVENT_INCONTEXT = 4; + public const int WINEVENT_SKIPOWNPROCESS = 2; + public const int EVENT_SYSTEM_FOREGROUND = 3; + public const int WH_SHELL = 10; + public const int GW_OWNER = 4; + public const long OBJID_WINDOW = 0x00000000L; + + public const uint PROCESS_QUERY_INFORMATION = 0x0400; + + public const uint EWX_LOGOFF = 0x00000000; + + public delegate bool EnumThreadProc(IntPtr hwnd, IntPtr lParam); + + [DllImport("dwmapi.dll")] + public static extern int DwmGetWindowAttribute(IntPtr hwnd, int dwAttribute, out int pvAttribute, int cbAttribute); + + [DllImport("user32.dll", ExactSpelling = true)] + public static extern IntPtr GetAncestor(IntPtr hwnd, GetAncestorFlags flags); + public enum GetAncestorFlags + { + GetParent = 1, + GetRoot = 2, + GetRootOwner = 3 + } + + [DllImport("user32.dll", SetLastError = true)] + public static extern IntPtr GetWindow(IntPtr hWnd, GetWindowType uCmd); + public enum GetWindowType : uint + { + GW_HWNDFIRST = 0, + GW_HWNDLAST = 1, + GW_HWNDNEXT = 2, + GW_HWNDPREV = 3, + GW_OWNER = 4, + GW_CHILD = 5, + GW_ENABLEDPOPUP = 6 + } + + [DllImport("user32.dll", SetLastError = true, CharSet = CharSet.Auto)] + 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); + + [DllImport("user32.dll")] + public static extern bool ExitWindowsEx(uint uFlags, uint dwReason); + + [DllImport("user32.dll")] + public static extern IntPtr GetForegroundWindow(); + + [DllImport("user32.dll")] + public static extern bool EnumWindows(EnumWindowsCallback lpEnumFunc, IntPtr lParam); + public delegate bool EnumWindowsCallback(IntPtr hwnd, IntPtr lParam); + + [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)] + public static extern bool IsWindowVisible(IntPtr hWnd); + + [DllImport("user32.dll", SetLastError = true)] + public static extern IntPtr FindWindow(string lpClassName, string lpWindowName); + + [DllImport("user32.dll")] + [return: MarshalAs(UnmanagedType.Bool)] + public static extern bool IsWindow(IntPtr hWnd); + + [DllImport("user32.dll", SetLastError = true)] + public static extern int GetWindowLong(IntPtr hWnd, int nIndex); + + [DllImport("user32.dll")] + public static extern int SetWindowLong(IntPtr hWnd, int nIndex, int dwNewLong); + + [DllImport("user32.dll", EntryPoint = "GetWindowLongPtr")] + public static extern IntPtr GetWindowLongPtr(IntPtr hWnd, int nIndex); + + public delegate void WinEventDelegate(IntPtr hWinEventHook, uint eventType, IntPtr hwnd, int idObject, int idChild, uint dwEventThread, uint dwmsEventTime); + [DllImport("user32.dll")] + public static extern IntPtr SetWinEventHook(uint eventMin, uint eventMax, IntPtr hmodWinEventProc, WinEventDelegate lpfnWinEventProc, uint idProcess, uint idThread, uint dwFlags); + + [DllImport("user32.dll")] + public static extern bool UnhookWinEvent(IntPtr hWinEventHook); + + [DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)] + public static extern int GetWindowText(IntPtr hWnd, StringBuilder lpString, int nMaxCount); + + [DllImport("user32.dll", SetLastError = true, CharSet = CharSet.Auto)] + 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); + + [DllImport("user32.dll")] + public static extern int ShowWindow(IntPtr hwnd, int nCmdShow); + + [DllImport("Kernel32.dll", SetLastError = true)] + public static extern IntPtr OpenEvent(uint dwDesiredAccess, bool bInheritHandle, string lpName); + + [DllImport("kernel32.dll")] + public static extern bool SetEvent(IntPtr hEvent); + + [DllImport("kernel32", SetLastError = true)] + public static extern bool CloseHandle(IntPtr hObject); + + [DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)] + [return: MarshalAs(UnmanagedType.Bool)] + public static extern bool SystemParametersInfoA(uint uiAction, uint uiParam, ref NativeRect pvParam, uint fWinIni); + + public delegate bool MonitorEnumProc(IntPtr hMonitor, IntPtr hdcMonitor, ref NativeRect lprcMonitor, IntPtr dwData); + + [DllImport("User32.dll")] + public static extern bool EnumDisplayMonitors(IntPtr hdc, IntPtr lprcClip, MonitorEnumProc lpfnEnum, IntPtr dwData); + + [DllImport("User32.dll")] + public static extern int GetSystemMetrics(int nIndex); + + [DllImport("user32.dll", EntryPoint = "SetWindowLong")] // 32-bit Eq. of SetWindowLongPtr + public static extern IntPtr SetWindowLong(IntPtr hWnd, int nIndex, IntPtr dwNewLong); + + [DllImport("user32.dll", EntryPoint = "SetWindowLongPtr")] + public static extern IntPtr SetWindowLongPtr(IntPtr hWnd, int nIndex, IntPtr dwNewLong); + + [DllImport("user32.dll", CharSet = CharSet.Auto)] + public static extern IntPtr CallWindowProc(IntPtr lpPrevWndFunc, IntPtr hwnd, uint msg, IntPtr wParam, IntPtr lParam); + + [DllImport("user32.dll")] + public static extern IntPtr SendMessage(IntPtr hWnd, int wMsg, IntPtr wParam, IntPtr lParam); + + [DllImport("user32.dll")] + public static extern uint SendMessageTimeout(IntPtr hWnd, uint messageId, uint wparam, uint lparam, uint timeoutFlags, uint timeout, ref IntPtr retval); + + [DllImport("Shell32.dll", CharSet = CharSet.Auto, SetLastError = true)] + 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); + + [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); + + [DllImport("user32.dll", SetLastError = true)] + public static extern uint GetWindowThreadProcessId(IntPtr hWnd, out uint processId); + + [DllImport("kernel32.dll", SetLastError = true)] + public static extern IntPtr OpenProcess(uint processAccess, bool bInheritHandle, uint processId); + + public const uint ProcessQueryLimitedInformation = 0x1000; + + // DWM API attrib + public enum DWMWINDOWATTRIBUTE + { + DWMWA_WINDOW_CORNER_PREFERENCE = 33 + } + // Copied from dwmapi.h + public enum DWM_WINDOW_CORNER_PREFERENCE + { + DWMWCP_DEFAULT = 0, + DWMWCP_DONOTROUND = 1, + DWMWCP_ROUND = 2, + DWMWCP_ROUNDSMALL = 3 + } + // DwmSetWindowAttribute + [DllImport("dwmapi.dll", CharSet = CharSet.Unicode, PreserveSig = false)] + public static extern void DwmSetWindowAttribute(IntPtr hwnd, DWMWINDOWATTRIBUTE attribute, ref DWM_WINDOW_CORNER_PREFERENCE pvAttribute, uint cbAttribute); + + // Proc info API for unpackaged + [DllImport("kernel32.dll")] + public static extern void GetNativeSystemInfo(out SYSTEM_INFO lpSystemInfo); + + [DllImport("shell32.dll", SetLastError = true, EntryPoint = "#188")] + public static extern bool ShellDDEInit(bool init); + + [DllImport("shell32.dll", SetLastError = true, EntryPoint = "#181")] + 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", SetLastError = true)] + 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 + { + public ushort wProcessorArchitecture; + public ushort wReserved; + public uint dwPageSize; + public IntPtr lpMinimumApplicationAddress; + public IntPtr lpMaximumApplicationAddress; + public IntPtr dwActiveProcessorMask; + public uint dwNumberOfProcessors; + public uint dwProcessorType; + public uint dwAllocationGranularity; + public ushort wProcessorLevel; + public ushort wProcessorRevision; + } + + // APPBAR code + [StructLayout(LayoutKind.Sequential)] + public struct APPBARDATA + { + public int cbSize; + public IntPtr hWnd; + public int uCallbackMessage; + public int uEdge; + public RECT rc; + public IntPtr lParam; + } + + public enum ABMsg : int + { + ABM_NEW = 0, + ABM_REMOVE, + ABM_QUERYPOS, + ABM_SETPOS, + ABM_GETSTATE, + ABM_GETTASKBARPOS, + ABM_ACTIVATE, + ABM_GETAUTOHIDEBAR, + ABM_SETAUTOHIDEBAR, + ABM_WINDOWPOSCHANGED, + ABM_SETSTATE + } + + public enum ABNotify : int + { + ABN_STATECHANGE = 0, + ABN_POSCHANGED, + ABN_FULLSCREENAPP, + ABN_WINDOWARRANGE + } + + public enum ABEdge : int + { + ABE_LEFT = 0, + ABE_TOP, + ABE_RIGHT, + ABE_BOTTOM + } + + public enum ABState + { + ABS_TOP = 0x00, + ABS_AUTOHIDE = 0x01 + } + + public delegate IntPtr WndProcDelegate(IntPtr hwnd, uint message, IntPtr wParam, IntPtr lParam); + + [DllImport("SHELL32", CallingConvention = CallingConvention.StdCall)] + public static extern uint SHAppBarMessage(int dwMessage, ref APPBARDATA pData); + + [DllImport("user32.dll", ExactSpelling = true, CharSet = CharSet.Auto)] + public static extern bool MoveWindow(IntPtr hWnd, int x, int y, int cx, int cy, bool repaint); + + [DllImport("user32.dll", CharSet = CharSet.Auto)] + public static extern int RegisterWindowMessage(string msg); + + [DllImport("user32.dll", SetLastError = true)] + public static extern bool SetWindowPos(IntPtr hWnd, IntPtr hWndInsertAfter, int X, int Y, int cx, int cy, uint uFlags); + + public enum SWPFlags + { + SWP_NOSIZE = 0x0001, + SWP_NOMOVE = 0x0002, + SWP_NOZORDER = 0x0004, + SWP_NOREDRAW = 0x0008, + SWP_NOACTIVATE = 0x0010, + SWP_DRAWFRAME = 0x0020, + SWP_FRAMECHANGED = 0x0020, + SWP_SHOWWINDOW = 0x0040, + SWP_HIDEWINDOW = 0x0080, + SWP_NOCOPYBITS = 0x0100, + SWP_NOOWNERZORDER = 0x0200, + SWP_NOREPOSITION = 0x0200, + SWP_NOSENDCHANGING = 0x0400, + SWP_DEFERERASE = 0x2000, + SWP_ASYNCWINDOWPOS = 0x4000 + } + + public enum WindowZOrder + { + HWND_TOP = 0, + HWND_BOTTOM = 1, + HWND_TOPMOST = -1, + HWND_NOTOPMOST = -2, + } + + [DllImport("UXTheme.dll", SetLastError = true, EntryPoint = "#138")] + 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 + { + + } + + + [DllImport("user32.dll", EntryPoint = "GetClassLongPtr")] + public static extern IntPtr GetClassLongPtr64(IntPtr hWnd, int nIndex); + + [StructLayout(LayoutKind.Sequential, Pack = 4)] + public struct PACKAGE_ID + { + public int reserved; + public AppxPackageArchitecture processorArchitecture; + public IntPtr version; + public IntPtr name; + public IntPtr publisher; + public IntPtr resourceId; + public IntPtr publisherId; + } + public enum AppxPackageArchitecture + { + x86 = 0, + Arm = 5, + x64 = 9, + Neutral = 11, + Arm64 = 12 + } + + [DllImport("psapi.dll")] + public static extern uint GetProcessImageFileName( + IntPtr hProcess, + [Out] StringBuilder lpImageFileName, + [In][MarshalAs(UnmanagedType.U4)] int nSize); + + [DllImport("kernel32.dll", CharSet = CharSet.Unicode, SetLastError = true)] + public static extern int GetPackagePathByFullName( + string packageFullName, + ref uint pathLength, + IntPtr path); + + [DllImport("ext-ms-win-ntuser-window-l1-1-4.dll")] + public static extern void SwitchToThisWindow(IntPtr hWnd, bool fUnknown); + + [DllImport("ole32.dll")] + public static extern int PropVariantClear(ref PropVariant pvar); + + [DllImport("shell32.dll")] + public static extern int SHGetPropertyStoreForWindow(IntPtr hwnd, ref Guid iid, [Out, MarshalAs(UnmanagedType.Interface)] out IPropertyStore propertyStore); + + [DllImport("user32.dll", EntryPoint = "#2573")] + public static extern bool IsShellFrameWindow(IntPtr hWnd); + + [DllImport("user32.dll")] + [return: MarshalAs(UnmanagedType.Bool)] + public static extern bool GetWindowBand([In] IntPtr hWnd, [Out] out UIntPtr pdwBand); + public enum ZBID : uint + { + ZBID_DEFAULT = 0, + ZBID_DESKTOP = 1, + ZBID_UIACCESS = 2, + ZBID_IMMERSIVE_IHM = 3, + ZBID_IMMERSIVE_NOTIFICATION = 4, + ZBID_IMMERSIVE_APPCHROME = 5, + ZBID_IMMERSIVE_MOGO = 6, + ZBID_IMMERSIVE_EDGY = 7, + ZBID_IMMERSIVE_INACTIVEMOBODY = 8, + ZBID_IMMERSIVE_INACTIVEDOCK = 9, + ZBID_IMMERSIVE_ACTIVEMOBODY = 10, + ZBID_IMMERSIVE_ACTIVEDOCK = 11, + ZBID_IMMERSIVE_BACKGROUND = 12, + ZBID_IMMERSIVE_SEARCH = 13, + ZBID_GENUINE_WINDOWS = 14, + ZBID_IMMERSIVE_RESTRICTED = 15, + ZBID_SYSTEM_TOOLS = 16, + ZBID_LOCK = 17, + ZBID_ABOVELOCK_UX = 18, + }; + + [DllImport("kernel32.dll", CharSet = CharSet.Unicode, SetLastError = true)] + public static extern int GetPackagesByPackageFamily( + string packageFamilyName, + ref uint count, + [Out, Optional] IntPtr packageFullNames, + ref uint bufferLength, + [Out, Optional] IntPtr buffer); + + [DllImport("user32.dll")] + [return: MarshalAs(UnmanagedType.Bool)] + public static extern bool SetForegroundWindow(IntPtr hWnd); + + [DllImport("user32.dll")] + public static extern IntPtr GetLastActivePopup(IntPtr hWnd); + + [DllImport("kernel32.dll", SetLastError = true, CharSet = CharSet.Auto)] + public static extern bool QueryFullProcessImageName(IntPtr hProcess, uint dwFlags, [Out, MarshalAs(UnmanagedType.LPTStr)] StringBuilder lpExeName, ref uint lpdwSize); + } } \ 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 5befc5e..bb0a2f2 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 7d3d769..acbf83c 100644 --- a/GyroShell/GyroShell.csproj +++ b/GyroShell/GyroShell.csproj @@ -14,6 +14,8 @@ -include WindowsUdk true False + true + copy /Y $(SolutionDir)$(Platform)\$(Configuration)\rmclient.dll $(SolutionDir)\GyroShell\Resources\rmclient.dll @@ -80,6 +82,19 @@ + + + True + True + Resources.resx + + + + + ResXFileCodeGenerator + Resources.Designer.cs + + 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 b9047aa..a4527dc 100644 --- a/GyroShell/Services/Helpers/IconHelperService.cs +++ b/GyroShell/Services/Helpers/IconHelperService.cs @@ -1,163 +1,163 @@ -#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; -using System.Threading.Tasks; -using WinRT; -using Microsoft.UI.Xaml.Media; -using Windows.Storage; -using Windows.Storage.Streams; -using System.IO; - -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) => IsShellFrameWindow(hWnd); - - public async Task GetUwpOrWin32Icon(IntPtr hWnd, int targetSize) - { - if (IsUwpWindow(hWnd)) - { - return m_bmpHelper.RemoveTransparentPadding(await GetUWPBitmap(hWnd)); - } - else - { - return ConvertIconBitmapToSoftwareBitmapSource(GetWin32Bitmap(hWnd, 32)); - } - } - - - #region Win32 - private Bitmap GetWin32Bitmap(IntPtr hWnd, int targetSize) - { - try - { - // get the icon from the HWND - IntPtr hIcon = SendMessage(hWnd, WM_GETICON, (IntPtr)ICON_BIG, IntPtr.Zero); - if (hIcon == IntPtr.Zero) - hIcon = SendMessage(hWnd, WM_GETICON, (IntPtr)ICON_SMALL, IntPtr.Zero); - if (hIcon == IntPtr.Zero) - hIcon = SendMessage(hWnd, WM_GETICON, (IntPtr)ICON_SMALL2, IntPtr.Zero); - if (hIcon == IntPtr.Zero) - hIcon = GetClassLongPtr64(hWnd, -14); - if (hIcon == IntPtr.Zero) - hIcon = GetClassLongPtr64(hWnd, -34); - - if (hIcon != IntPtr.Zero) - { - Icon icon = Icon.FromHandle(hIcon); - 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 async Task GetUWPBitmap(IntPtr hWnd) - { - try - { - string iconPath = m_appHelper.GetUwpAppIconPath(hWnd); - WriteableBitmap writeableBitmap; - - // Open the file as a stream - StorageFile file = await StorageFile.GetFileFromPathAsync(iconPath); - using IRandomAccessStream fileStream = await file.OpenAsync(FileAccessMode.Read); - - BitmapImage bi = new(new Uri(iconPath)); - BitmapDecoder decoder = await BitmapDecoder.CreateAsync(fileStream); - - var transform = new BitmapTransform() - { - InterpolationMode = BitmapInterpolationMode.Fant - }; - - // Get the pixel data with the applied transform - var pixelData = await decoder.GetPixelDataAsync( - decoder.BitmapPixelFormat, - BitmapAlphaMode.Premultiplied, - transform, - ExifOrientationMode.IgnoreExifOrientation, - ColorManagementMode.DoNotColorManage - ); - - writeableBitmap = new WriteableBitmap((int)decoder.PixelWidth, (int)decoder.PixelHeight); - using (Stream pixelStream = writeableBitmap.PixelBuffer.AsStream()) - { - byte[] pixels = pixelData.DetachPixelData(); - await pixelStream.WriteAsync(pixels, 0, pixels.Length); - } - return writeableBitmap; - } - catch (Exception e) - { - Debug.WriteLine(e.Message); - return null; - } - } - #endregion - - #region Common - private SoftwareBitmapSource ConvertIconBitmapToSoftwareBitmapSource(Bitmap bmp) - { - if (bmp == null) return null; - Bitmap resampledBmp = m_bmpHelper.FilterAndScaleBitmap(bmp, bmp.Width, bmp.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; +using System.Threading.Tasks; +using WinRT; +using Microsoft.UI.Xaml.Media; +using Windows.Storage; +using Windows.Storage.Streams; +using System.IO; + +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) => IsShellFrameWindow(hWnd); + + public async Task GetUwpOrWin32Icon(IntPtr hWnd, int targetSize) + { + if (IsUwpWindow(hWnd)) + { + return m_bmpHelper.RemoveTransparentPadding(await GetUWPBitmap(hWnd)); + } + else + { + return ConvertIconBitmapToSoftwareBitmapSource(GetWin32Bitmap(hWnd, 32)); + } + } + + + #region Win32 + private Bitmap GetWin32Bitmap(IntPtr hWnd, int targetSize) + { + try + { + // get the icon from the HWND + IntPtr hIcon = SendMessage(hWnd, WM_GETICON, (IntPtr)ICON_BIG, IntPtr.Zero); + if (hIcon == IntPtr.Zero) + hIcon = SendMessage(hWnd, WM_GETICON, (IntPtr)ICON_SMALL, IntPtr.Zero); + if (hIcon == IntPtr.Zero) + hIcon = SendMessage(hWnd, WM_GETICON, (IntPtr)ICON_SMALL2, IntPtr.Zero); + if (hIcon == IntPtr.Zero) + hIcon = GetClassLongPtr64(hWnd, -14); + if (hIcon == IntPtr.Zero) + hIcon = GetClassLongPtr64(hWnd, -34); + + if (hIcon != IntPtr.Zero) + { + Icon icon = Icon.FromHandle(hIcon); + 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 async Task GetUWPBitmap(IntPtr hWnd) + { + try + { + string iconPath = m_appHelper.GetUwpAppIconPath(hWnd); + WriteableBitmap writeableBitmap; + + // Open the file as a stream + StorageFile file = await StorageFile.GetFileFromPathAsync(iconPath); + using IRandomAccessStream fileStream = await file.OpenAsync(FileAccessMode.Read); + + BitmapImage bi = new(new Uri(iconPath)); + BitmapDecoder decoder = await BitmapDecoder.CreateAsync(fileStream); + + var transform = new BitmapTransform() + { + InterpolationMode = BitmapInterpolationMode.Fant + }; + + // Get the pixel data with the applied transform + var pixelData = await decoder.GetPixelDataAsync( + decoder.BitmapPixelFormat, + BitmapAlphaMode.Premultiplied, + transform, + ExifOrientationMode.IgnoreExifOrientation, + ColorManagementMode.DoNotColorManage + ); + + writeableBitmap = new WriteableBitmap((int)decoder.PixelWidth, (int)decoder.PixelHeight); + using (Stream pixelStream = writeableBitmap.PixelBuffer.AsStream()) + { + byte[] pixels = pixelData.DetachPixelData(); + await pixelStream.WriteAsync(pixels, 0, pixels.Length); + } + return writeableBitmap; + } + catch (Exception e) + { + Debug.WriteLine(e.Message); + return null; + } + } + #endregion + + #region Common + private SoftwareBitmapSource ConvertIconBitmapToSoftwareBitmapSource(Bitmap bmp) + { + if (bmp == null) return null; + Bitmap resampledBmp = m_bmpHelper.FilterAndScaleBitmap(bmp, bmp.Width, bmp.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..b57df11 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,150 @@ 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_hStartMenu = FindWindowEx(m_hStartMenu, IntPtr.Zero, "Button", "Start"); + if (m_hStartMenu == IntPtr.Zero) { m_hStartMenu = FindWindow("Button", null); - } - } - + } + + if (m_hTaskBar != IntPtr.Zero) + { + // Explorer is probably already running. + return; + } + + 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(); + } + 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(); + } + + 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;