├── detours ├── lib.X64 │ ├── syelog.lib │ └── detours.lib ├── lib.X86 │ ├── syelog.lib │ └── detours.lib ├── lib.ARM64 │ ├── syelog.lib │ └── detours.lib └── include │ ├── detver.h │ ├── syelog.h │ └── detours.h ├── EdgeWindowTabManagerBlockDll ├── exports.def ├── EdgeWindowTabManagerBlockDll.rc ├── resource.h ├── EdgeWindowTabManagerBlockDll.vcxproj.filters ├── dllmain.cpp └── EdgeWindowTabManagerBlockDll.vcxproj ├── EdgeWindowTabManagerBlock ├── resource.h ├── EdgeWindowTabManagerBlock.rc ├── packages.config ├── EdgeWindowTabManagerBlock.vcxproj.filters ├── edgeutils.cpp ├── source.cpp └── EdgeWindowTabManagerBlock.vcxproj ├── wrappers.h ├── LICENSE ├── .gitattributes ├── EdgeWindowTabManagerBlock.sln ├── README.md ├── procutils.cpp └── .gitignore /detours/lib.X64/syelog.lib: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gexgd0419/EdgeWindowTabManagerBlock/HEAD/detours/lib.X64/syelog.lib -------------------------------------------------------------------------------- /detours/lib.X86/syelog.lib: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gexgd0419/EdgeWindowTabManagerBlock/HEAD/detours/lib.X86/syelog.lib -------------------------------------------------------------------------------- /detours/lib.ARM64/syelog.lib: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gexgd0419/EdgeWindowTabManagerBlock/HEAD/detours/lib.ARM64/syelog.lib -------------------------------------------------------------------------------- /detours/lib.X64/detours.lib: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gexgd0419/EdgeWindowTabManagerBlock/HEAD/detours/lib.X64/detours.lib -------------------------------------------------------------------------------- /detours/lib.X86/detours.lib: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gexgd0419/EdgeWindowTabManagerBlock/HEAD/detours/lib.X86/detours.lib -------------------------------------------------------------------------------- /EdgeWindowTabManagerBlockDll/exports.def: -------------------------------------------------------------------------------- 1 | LIBRARY EdgeWindowTabManagerBlockDll 2 | EXPORTS 3 | DetourFinishHelperProcess @1 NONAME -------------------------------------------------------------------------------- /detours/lib.ARM64/detours.lib: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gexgd0419/EdgeWindowTabManagerBlock/HEAD/detours/lib.ARM64/detours.lib -------------------------------------------------------------------------------- /EdgeWindowTabManagerBlock/resource.h: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gexgd0419/EdgeWindowTabManagerBlock/HEAD/EdgeWindowTabManagerBlock/resource.h -------------------------------------------------------------------------------- /EdgeWindowTabManagerBlock/EdgeWindowTabManagerBlock.rc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gexgd0419/EdgeWindowTabManagerBlock/HEAD/EdgeWindowTabManagerBlock/EdgeWindowTabManagerBlock.rc -------------------------------------------------------------------------------- /EdgeWindowTabManagerBlockDll/EdgeWindowTabManagerBlockDll.rc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gexgd0419/EdgeWindowTabManagerBlock/HEAD/EdgeWindowTabManagerBlockDll/EdgeWindowTabManagerBlockDll.rc -------------------------------------------------------------------------------- /EdgeWindowTabManagerBlock/packages.config: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /EdgeWindowTabManagerBlockDll/resource.h: -------------------------------------------------------------------------------- 1 | //{{NO_DEPENDENCIES}} 2 | // Microsoft Visual C++ generated include file. 3 | // Used by EdgeWindowTabManagerBlockDll.rc 4 | 5 | // Next default values for new objects 6 | // 7 | #ifdef APSTUDIO_INVOKED 8 | #ifndef APSTUDIO_READONLY_SYMBOLS 9 | #define _APS_NEXT_RESOURCE_VALUE 101 10 | #define _APS_NEXT_COMMAND_VALUE 40001 11 | #define _APS_NEXT_CONTROL_VALUE 1001 12 | #define _APS_NEXT_SYMED_VALUE 101 13 | #endif 14 | #endif 15 | -------------------------------------------------------------------------------- /detours/include/detver.h: -------------------------------------------------------------------------------- 1 | ////////////////////////////////////////////////////////////////////////////// 2 | // 3 | // Common version parameters. 4 | // 5 | // Microsoft Research Detours Package, Version 4.0.1 6 | // 7 | // Copyright (c) Microsoft Corporation. All rights reserved. 8 | // 9 | 10 | #define _USING_V110_SDK71_ 1 11 | #include "winver.h" 12 | #if 0 13 | #include 14 | #include 15 | #else 16 | #ifndef DETOURS_STRINGIFY 17 | #define DETOURS_STRINGIFY_(x) #x 18 | #define DETOURS_STRINGIFY(x) DETOURS_STRINGIFY_(x) 19 | #endif 20 | 21 | #define VER_FILEFLAGSMASK 0x3fL 22 | #define VER_FILEFLAGS 0x0L 23 | #define VER_FILEOS 0x00040004L 24 | #define VER_FILETYPE 0x00000002L 25 | #define VER_FILESUBTYPE 0x00000000L 26 | #endif 27 | #define VER_DETOURS_BITS DETOURS_STRINGIFY(DETOURS_BITS) 28 | -------------------------------------------------------------------------------- /wrappers.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #define WIN32_LEAN_AND_MEAN 3 | #include 4 | 5 | template 6 | class HandleWrapper 7 | { 8 | private: 9 | THandle m_handle; 10 | public: 11 | HandleWrapper() : m_handle(ZeroValue) {} 12 | HandleWrapper(THandle handle) : m_handle(handle) {} 13 | ~HandleWrapper() 14 | { 15 | if (m_handle != ZeroValue) 16 | CloseFunc(m_handle); 17 | } 18 | HandleWrapper(const HandleWrapper&) = delete; 19 | HandleWrapper& operator=(const HandleWrapper&) = delete; 20 | 21 | operator THandle() { return m_handle; } 22 | THandle* operator&() { return &m_handle; } 23 | }; 24 | 25 | typedef HandleWrapper Handle; 26 | typedef HandleWrapper HFile; 27 | typedef HandleWrapper HKey; -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2023 gexgd0419 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /EdgeWindowTabManagerBlockDll/EdgeWindowTabManagerBlockDll.vcxproj.filters: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | {93995380-89BD-4b04-88EB-625FBE52EBFB} 6 | h;hh;hpp;hxx;h++;hm;inl;inc;ipp;xsd 7 | 8 | 9 | {4FC737F1-C7A5-4376-A066-2A32D752A2FF} 10 | cpp;c;cc;cxx;c++;cppm;ixx;def;odl;idl;hpj;bat;asm;asmx 11 | 12 | 13 | {67DA6AB6-F800-4c08-8B7A-83BB121AAD01} 14 | rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms 15 | 16 | 17 | 18 | 19 | Source files 20 | 21 | 22 | 23 | 24 | Source files 25 | 26 | 27 | 28 | 29 | Header files 30 | 31 | 32 | 33 | 34 | Resource files 35 | 36 | 37 | -------------------------------------------------------------------------------- /EdgeWindowTabManagerBlock/EdgeWindowTabManagerBlock.vcxproj.filters: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | {93995380-89BD-4b04-88EB-625FBE52EBFB} 6 | h;hh;hpp;hxx;h++;hm;inl;inc;ipp;xsd 7 | 8 | 9 | {4FC737F1-C7A5-4376-A066-2A32D752A2FF} 10 | cpp;c;cc;cxx;c++;cppm;ixx;def;odl;idl;hpj;bat;asm;asmx 11 | 12 | 13 | {67DA6AB6-F800-4c08-8B7A-83BB121AAD01} 14 | rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms 15 | 16 | 17 | 18 | 19 | Source files 20 | 21 | 22 | Source files 23 | 24 | 25 | Source files 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | Header files 34 | 35 | 36 | 37 | 38 | Resource files 39 | 40 | 41 | -------------------------------------------------------------------------------- /.gitattributes: -------------------------------------------------------------------------------- 1 | ############################################################################### 2 | # Set default behavior to automatically normalize line endings. 3 | ############################################################################### 4 | * text=auto 5 | 6 | ############################################################################### 7 | # Set default behavior for command prompt diff. 8 | # 9 | # This is need for earlier builds of msysgit that does not have it on by 10 | # default for csharp files. 11 | # Note: This is only used by command line 12 | ############################################################################### 13 | #*.cs diff=csharp 14 | 15 | ############################################################################### 16 | # Set the merge driver for project and solution files 17 | # 18 | # Merging from the command prompt will add diff markers to the files if there 19 | # are conflicts (Merging from VS is not affected by the settings below, in VS 20 | # the diff markers are never inserted). Diff markers may cause the following 21 | # file extensions to fail to load in VS. An alternative would be to treat 22 | # these files as binary and thus will always conflict and require user 23 | # intervention with every merge. To do so, just uncomment the entries below 24 | ############################################################################### 25 | #*.sln merge=binary 26 | #*.csproj merge=binary 27 | #*.vbproj merge=binary 28 | #*.vcxproj merge=binary 29 | #*.vcproj merge=binary 30 | #*.dbproj merge=binary 31 | #*.fsproj merge=binary 32 | #*.lsproj merge=binary 33 | #*.wixproj merge=binary 34 | #*.modelproj merge=binary 35 | #*.sqlproj merge=binary 36 | #*.wwaproj merge=binary 37 | 38 | ############################################################################### 39 | # behavior for image files 40 | # 41 | # image files are treated as binary by default. 42 | ############################################################################### 43 | #*.jpg binary 44 | #*.png binary 45 | #*.gif binary 46 | 47 | ############################################################################### 48 | # diff behavior for common document formats 49 | # 50 | # Convert binary document formats to text before diffing them. This feature 51 | # is only available from the command line. Turn it on by uncommenting the 52 | # entries below. 53 | ############################################################################### 54 | #*.doc diff=astextplain 55 | #*.DOC diff=astextplain 56 | #*.docx diff=astextplain 57 | #*.DOCX diff=astextplain 58 | #*.dot diff=astextplain 59 | #*.DOT diff=astextplain 60 | #*.pdf diff=astextplain 61 | #*.PDF diff=astextplain 62 | #*.rtf diff=astextplain 63 | #*.RTF diff=astextplain 64 | -------------------------------------------------------------------------------- /EdgeWindowTabManagerBlock.sln: -------------------------------------------------------------------------------- 1 | 2 | Microsoft Visual Studio Solution File, Format Version 12.00 3 | # Visual Studio Version 17 4 | VisualStudioVersion = 17.7.34031.279 5 | MinimumVisualStudioVersion = 10.0.40219.1 6 | Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "EdgeWindowTabManagerBlock", "EdgeWindowTabManagerBlock\EdgeWindowTabManagerBlock.vcxproj", "{A9E30655-51D2-451D-87E0-806F092DD47B}" 7 | EndProject 8 | Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "EdgeWindowTabManagerBlockDll", "EdgeWindowTabManagerBlockDll\EdgeWindowTabManagerBlockDll.vcxproj", "{73F5F261-6380-4565-A8A9-C2E3863A75B0}" 9 | EndProject 10 | Global 11 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 12 | Debug|ARM64 = Debug|ARM64 13 | Debug|x64 = Debug|x64 14 | Debug|x86 = Debug|x86 15 | Release|ARM64 = Release|ARM64 16 | Release|x64 = Release|x64 17 | Release|x86 = Release|x86 18 | EndGlobalSection 19 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 20 | {A9E30655-51D2-451D-87E0-806F092DD47B}.Debug|ARM64.ActiveCfg = Debug|ARM64 21 | {A9E30655-51D2-451D-87E0-806F092DD47B}.Debug|ARM64.Build.0 = Debug|ARM64 22 | {A9E30655-51D2-451D-87E0-806F092DD47B}.Debug|x64.ActiveCfg = Debug|x64 23 | {A9E30655-51D2-451D-87E0-806F092DD47B}.Debug|x64.Build.0 = Debug|x64 24 | {A9E30655-51D2-451D-87E0-806F092DD47B}.Debug|x86.ActiveCfg = Debug|Win32 25 | {A9E30655-51D2-451D-87E0-806F092DD47B}.Debug|x86.Build.0 = Debug|Win32 26 | {A9E30655-51D2-451D-87E0-806F092DD47B}.Release|ARM64.ActiveCfg = Release|ARM64 27 | {A9E30655-51D2-451D-87E0-806F092DD47B}.Release|ARM64.Build.0 = Release|ARM64 28 | {A9E30655-51D2-451D-87E0-806F092DD47B}.Release|x64.ActiveCfg = Release|x64 29 | {A9E30655-51D2-451D-87E0-806F092DD47B}.Release|x64.Build.0 = Release|x64 30 | {A9E30655-51D2-451D-87E0-806F092DD47B}.Release|x86.ActiveCfg = Release|Win32 31 | {A9E30655-51D2-451D-87E0-806F092DD47B}.Release|x86.Build.0 = Release|Win32 32 | {73F5F261-6380-4565-A8A9-C2E3863A75B0}.Debug|ARM64.ActiveCfg = Debug|ARM64 33 | {73F5F261-6380-4565-A8A9-C2E3863A75B0}.Debug|ARM64.Build.0 = Debug|ARM64 34 | {73F5F261-6380-4565-A8A9-C2E3863A75B0}.Debug|x64.ActiveCfg = Debug|x64 35 | {73F5F261-6380-4565-A8A9-C2E3863A75B0}.Debug|x64.Build.0 = Debug|x64 36 | {73F5F261-6380-4565-A8A9-C2E3863A75B0}.Debug|x86.ActiveCfg = Debug|Win32 37 | {73F5F261-6380-4565-A8A9-C2E3863A75B0}.Debug|x86.Build.0 = Debug|Win32 38 | {73F5F261-6380-4565-A8A9-C2E3863A75B0}.Release|ARM64.ActiveCfg = Release|ARM64 39 | {73F5F261-6380-4565-A8A9-C2E3863A75B0}.Release|ARM64.Build.0 = Release|ARM64 40 | {73F5F261-6380-4565-A8A9-C2E3863A75B0}.Release|x64.ActiveCfg = Release|x64 41 | {73F5F261-6380-4565-A8A9-C2E3863A75B0}.Release|x64.Build.0 = Release|x64 42 | {73F5F261-6380-4565-A8A9-C2E3863A75B0}.Release|x86.ActiveCfg = Release|Win32 43 | {73F5F261-6380-4565-A8A9-C2E3863A75B0}.Release|x86.Build.0 = Release|Win32 44 | EndGlobalSection 45 | GlobalSection(SolutionProperties) = preSolution 46 | HideSolutionNode = FALSE 47 | EndGlobalSection 48 | GlobalSection(ExtensibilityGlobals) = postSolution 49 | SolutionGuid = {8964981A-D98B-4FA7-AE1F-60B0E29388A7} 50 | EndGlobalSection 51 | EndGlobal 52 | -------------------------------------------------------------------------------- /detours/include/syelog.h: -------------------------------------------------------------------------------- 1 | ////////////////////////////////////////////////////////////////////////////// 2 | // 3 | // Detours Test Program (syelog.h of syelog.lib) 4 | // 5 | // Microsoft Research Detours Package 6 | // 7 | // Copyright (c) Microsoft Corporation. All rights reserved. 8 | // 9 | #pragma once 10 | #ifndef _SYELOGD_H_ 11 | #define _SYELOGD_H_ 12 | #include 13 | 14 | #pragma pack(push, 1) 15 | #pragma warning(push) 16 | #pragma warning(disable: 4200) 17 | 18 | ////////////////////////////////////////////////////////////////////////////// 19 | // 20 | // 21 | #define SYELOG_PIPE_NAMEA "\\\\.\\pipe\\syelog" 22 | #define SYELOG_PIPE_NAMEW L"\\\\.\\pipe\\syelog" 23 | #ifdef UNICODE 24 | #define SYELOG_PIPE_NAME SYELOG_PIPE_NAMEW 25 | #else 26 | #define SYELOG_PIPE_NAME SYELOG_PIPE_NAMEA 27 | #endif 28 | 29 | ////////////////////////////////////////////////////////////////////////////// 30 | // 31 | #define SYELOG_MAXIMUM_MESSAGE 4086 // 4096 - sizeof(header stuff) 32 | 33 | typedef struct _SYELOG_MESSAGE 34 | { 35 | USHORT nBytes; 36 | BYTE nFacility; 37 | BYTE nSeverity; 38 | DWORD nProcessId; 39 | FILETIME ftOccurance; 40 | BOOL fTerminate; 41 | CHAR szMessage[SYELOG_MAXIMUM_MESSAGE]; 42 | } SYELOG_MESSAGE, *PSYELOG_MESSAGE; 43 | 44 | 45 | // Facility Codes. 46 | // 47 | #define SYELOG_FACILITY_KERNEL 0x10 // OS Kernel 48 | #define SYELOG_FACILITY_SECURITY 0x20 // OS Security 49 | #define SYELOG_FACILITY_LOGGING 0x30 // OS Logging-internal 50 | #define SYELOG_FACILITY_SERVICE 0x40 // User-mode system daemon 51 | #define SYELOG_FACILITY_APPLICATION 0x50 // User-mode application 52 | #define SYELOG_FACILITY_USER 0x60 // User self-generated. 53 | #define SYELOG_FACILITY_LOCAL0 0x70 // Locally defined. 54 | #define SYELOG_FACILITY_LOCAL1 0x71 // Locally defined. 55 | #define SYELOG_FACILITY_LOCAL2 0x72 // Locally defined. 56 | #define SYELOG_FACILITY_LOCAL3 0x73 // Locally defined. 57 | #define SYELOG_FACILITY_LOCAL4 0x74 // Locally defined. 58 | #define SYELOG_FACILITY_LOCAL5 0x75 // Locally defined. 59 | #define SYELOG_FACILITY_LOCAL6 0x76 // Locally defined. 60 | #define SYELOG_FACILITY_LOCAL7 0x77 // Locally defined. 61 | #define SYELOG_FACILITY_LOCAL8 0x78 // Locally defined. 62 | #define SYELOG_FACILITY_LOCAL9 0x79 // Locally defined. 63 | 64 | // Severity Codes. 65 | // 66 | #define SYELOG_SEVERITY_FATAL 0x00 // System is dead. 67 | #define SYELOG_SEVERITY_ALERT 0x10 // Take action immediately. 68 | #define SYELOG_SEVERITY_CRITICAL 0x20 // Critical condition. 69 | #define SYELOG_SEVERITY_ERROR 0x30 // Error 70 | #define SYELOG_SEVERITY_WARNING 0x40 // Warning 71 | #define SYELOG_SEVERITY_NOTICE 0x50 // Significant condition. 72 | #define SYELOG_SEVERITY_INFORMATION 0x60 // Informational 73 | #define SYELOG_SEVERITY_AUDIT_FAIL 0x66 // Audit Failed 74 | #define SYELOG_SEVERITY_AUDIT_PASS 0x67 // Audit Succeeeded 75 | #define SYELOG_SEVERITY_DEBUG 0x70 // Debugging 76 | 77 | // Logging Functions. 78 | // 79 | VOID SyelogOpen(PCSTR pszIdentifier, BYTE nFacility); 80 | VOID Syelog(BYTE nSeverity, PCSTR pszMsgf, ...); 81 | VOID SyelogV(BYTE nSeverity, PCSTR pszMsgf, va_list args); 82 | VOID SyelogClose(BOOL fTerminate); 83 | 84 | #pragma warning(pop) 85 | #pragma pack(pop) 86 | 87 | #endif // _SYELOGD_H_ 88 | // 89 | ///////////////////////////////////////////////////////////////// End of File. 90 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # EdgeWindowTabManagerBlock 2 | 3 | A program that blocks the WindowTabManager feature of Microsoft Edge, when you launch Edge through this program. 4 | 5 | This WindowTabManager feature, supposedly, enables Microsoft Edge to show its tabs in Alt-Tab view. However, it has a bug that can slow down Explorer and make Explorer unstable when you have enough Edge tabs open. 6 | 7 | My Reddit post about this issue: https://www.reddit.com/r/edge/comments/1090h93/having_too_many_1000_microsoft_edge_tabs_open_can/ 8 | 9 | There was an experimental flag `#edge-window-tab-manager` that you could disable to disable this feature. However, the flag has been removed. This program is an alternative way to disable this feature and get around its issue. 10 | 11 | ## How to use 12 | 13 | First, download the zip file that matches the processor architecture (x86, x64, or ARM64) of the Microsoft Edge on your system, in the [Releases](https://github.com/gexgd0419/EdgeWindowTabManagerBlock/releases) section. Next, extract it and put the two files in the same directory. 14 | 15 | There are two ways to use this program. 16 | 17 | ### The automatic way: Register as a debugger for Edge (version 0.4) 18 | 19 | This program supports registering itself as the IFEO (Image File Execution Options) debugger for Microsoft Edge. This allows the program to intercept every attempt to run Microsoft Edge, so it can patch the Edge processes properly. 20 | 21 | This program will ask you if you want it to register as a debugger. You can choose to register, or to use it manually without registration. You can make this dialog show again by holding CTRL when starting the program. 22 | 23 | After registration, you can just use Microsoft Edge in the usual way. 24 | 25 | Note the following: 26 | 27 | - Registering IFEO debuggers requires adminstrator's permission. This will also affect all users on the system. If you have other user accounts, put this program in a folder that every user can access. 28 | - It's recommended to exit Edge before registration. 29 | - Modifying IFEO is seemed as a dangerous action by some antivirus/HIPS software. In fact, this program patches Edge by injecting a third-party DLL into Edge processes, which can already be seen as a dangerous action. 30 | - Do not move, rename, or delete the program after registration. Edge won't be able to run if the registered debugger does not exist. 31 | - If you want to unregister, go to Control Panel > Programs and Features, or Settings > Apps, then choose to "uninstall" EdgeWindowTabManagerBlock. This won't delete the program, this will just unregister it. 32 | - Registering as the IFEO debugger may cause some other debuggers that launch and attach to Edge processes to fail (see issue #8). 33 | 34 | ### The manual way: Start this program manually, when you want to start Edge 35 | 36 | This program works by injecting code to block the creation of the WindowTabManager into the first Edge process, which must happen before the Edge process gets a chance to run its own code. If Edge is already started, it will finish loading the WindowTabManager at startup, and it will be too late to block its creation. 37 | 38 | So, to make this program work, you need to run this program instead of the real Edge, and let it start the first Edge process for you, so that this program can have full control over the Edge process. 39 | 40 | If you launch Edge by any other method, either through task bar, the Start menu, the desktop icon, or by opening a link when Edge is the default browser, or by opening a file associated with Edge, this program will not work. If there are other Edge processes running already, this program will also not work. 41 | 42 | If you choose to register the program as an IFEO debugger, those will be taken care of by the operating system: this program will always be started before Edge. But the manual way is still possible. 43 | 44 | ## Some technical details 45 | 46 | This program uses Microsoft's [Detours](https://github.com/microsoft/Detours) library to hook two Windows API functions: [`RoGetActivationFactory`](https://learn.microsoft.com/windows/win32/api/roapi/nf-roapi-rogetactivationfactory) and [`RoActivateInstance`](https://learn.microsoft.com/windows/win32/api/roapi/nf-roapi-roactivateinstance), which are responsible for creating Windows Runtime objects. The hook functions check if the object being created belongs to class `Windows.UI.Shell.WindowTabManager`, and if it does, fail the creation by returning `E_ACCESSDENIED`. Edge will then think that the system does not have the WindowsTabManager capability, and continue without the feature. 47 | -------------------------------------------------------------------------------- /procutils.cpp: -------------------------------------------------------------------------------- 1 | #define WIN32_LEAN_AND_MEAN 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include "wrappers.h" 7 | 8 | typedef LONG NTSTATUS; 9 | 10 | typedef enum _PROCESSINFOCLASS 11 | { 12 | ProcessCommandLineInformation = 60, // q: UNICODE_STRING 13 | } PROCESSINFOCLASS; 14 | 15 | typedef struct _UNICODE_STRING { 16 | USHORT Length; 17 | USHORT MaximumLength; 18 | PWSTR Buffer; 19 | } UNICODE_STRING; 20 | typedef UNICODE_STRING* PUNICODE_STRING; 21 | typedef const UNICODE_STRING* PCUNICODE_STRING; 22 | 23 | #define STATUS_INFO_LENGTH_MISMATCH ((NTSTATUS)0xC0000004L) 24 | #define NT_SUCCESS(Status) ((NTSTATUS)(Status) >= 0) 25 | 26 | typedef NTSTATUS (NTAPI *NtQueryInformationProcess_t)( 27 | HANDLE ProcessHandle, 28 | PROCESSINFOCLASS ProcessInformationClass, 29 | PVOID ProcessInformation, 30 | ULONG ProcessInformationLength, 31 | PULONG ReturnLength 32 | ); 33 | 34 | static NtQueryInformationProcess_t NtQueryInformationProcess 35 | = (NtQueryInformationProcess_t)GetProcAddress(GetModuleHandleW(L"ntdll.dll"), "NtQueryInformationProcess"); 36 | 37 | // Gets the command line of a process. Returns empty string on failure. 38 | static std::wstring GetProcessCommandLine(DWORD pid) 39 | { 40 | if (!NtQueryInformationProcess) 41 | return std::wstring(); 42 | 43 | Handle hProc = OpenProcess(PROCESS_QUERY_LIMITED_INFORMATION, FALSE, pid); 44 | if (!hProc) 45 | return std::wstring(); 46 | 47 | ULONG cb = 0; 48 | NTSTATUS stat = NtQueryInformationProcess(hProc, ProcessCommandLineInformation, nullptr, 0, &cb); 49 | if (stat != STATUS_INFO_LENGTH_MISMATCH) 50 | return std::wstring(); 51 | 52 | std::unique_ptr pBuffer(static_cast(operator new(cb))); 53 | stat = NtQueryInformationProcess(hProc, ProcessCommandLineInformation, pBuffer.get(), cb, nullptr); 54 | if (!NT_SUCCESS(stat)) 55 | return std::wstring(); 56 | 57 | return std::wstring(pBuffer->Buffer, pBuffer->Length / sizeof(WCHAR)); 58 | } 59 | 60 | static bool DoesProcessHaveWindowTabManager(DWORD pid) 61 | { 62 | HFile hSnap = CreateToolhelp32Snapshot(TH32CS_SNAPMODULE, pid); 63 | if (hSnap == INVALID_HANDLE_VALUE) 64 | return false; 65 | MODULEENTRY32W me = { sizeof me }; 66 | if (Module32FirstW(hSnap, &me)) 67 | { 68 | do 69 | { 70 | if (_wcsicmp(me.szModule, L"Windows.Internal.UI.Shell.WindowTabManager.dll") == 0) 71 | return true; 72 | } while (Module32NextW(hSnap, &me)); 73 | } 74 | return false; 75 | } 76 | 77 | static BOOL CALLBACK EnumThreadWindowsProc(HWND hwnd, LPARAM lparam) 78 | { 79 | // either the window is visible, or the window class name is Chrome_WidgetWin_1 80 | if (!IsWindowVisible(hwnd)) 81 | { 82 | WCHAR szClass[32]; 83 | GetClassNameW(hwnd, szClass, 32); 84 | if (wcscmp(szClass, L"Chrome_WidgetWin_1") != 0) 85 | return TRUE; // continue enumeration 86 | } 87 | 88 | *reinterpret_cast(lparam) = true; 89 | return FALSE; // stop enumeration 90 | } 91 | 92 | static bool HasVisibleEdgeWindows(DWORD pid) 93 | { 94 | HFile hSnap = CreateToolhelp32Snapshot(TH32CS_SNAPTHREAD, 0); // all threads are included 95 | if (hSnap == INVALID_HANDLE_VALUE) 96 | return false; 97 | THREADENTRY32 te = { sizeof te }; 98 | if (!Thread32First(hSnap, &te)) 99 | return false; 100 | do 101 | { 102 | if (te.th32OwnerProcessID != pid) 103 | continue; 104 | bool flag = false; 105 | EnumThreadWindows(te.th32ThreadID, EnumThreadWindowsProc, reinterpret_cast(&flag)); 106 | if (flag) 107 | return true; 108 | } while (Thread32Next(hSnap, &te)); 109 | 110 | return false; 111 | } 112 | 113 | // Returns the main Edge process ID. Returns 0 if not found. 114 | DWORD FindMainEdgeProcess(bool withWindowTabManager) 115 | { 116 | HFile hSnap = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0); 117 | if (hSnap == INVALID_HANDLE_VALUE) 118 | return 0; 119 | 120 | PROCESSENTRY32W pe = { sizeof pe }; 121 | if (!Process32FirstW(hSnap, &pe)) 122 | return 0; 123 | 124 | do 125 | { 126 | if (_wcsicmp(pe.szExeFile, L"msedge.exe") != 0) 127 | continue; 128 | 129 | std::wstring cmdLine = GetProcessCommandLine(pe.th32ProcessID); 130 | if (cmdLine.empty()) 131 | continue; 132 | if (cmdLine.find(L"--type=") != std::wstring::npos) // do not include Edge subprocesses 133 | continue; 134 | 135 | if (!withWindowTabManager || DoesProcessHaveWindowTabManager(pe.th32ProcessID)) 136 | { 137 | // if it's launched by Startup Boost, and is running in the background 138 | // (there are no visible Edge windows open), 139 | // we can safely kill it to make Edge start from scratch 140 | if (cmdLine.find(L"--no-startup-window") != std::wstring::npos 141 | && !HasVisibleEdgeWindows(pe.th32ProcessID)) 142 | { 143 | Handle hProc = OpenProcess(PROCESS_TERMINATE, FALSE, pe.th32ProcessID); 144 | if (hProc) 145 | TerminateProcess(hProc, 1); 146 | } 147 | else 148 | { 149 | return pe.th32ProcessID; 150 | } 151 | } 152 | } while (Process32NextW(hSnap, &pe)); 153 | 154 | return 0; 155 | } 156 | 157 | // Returns the main Edge process which is using WindowTabManager. Returns 0 if not found. 158 | DWORD FindEdgeProcessWithWindowTabManager() 159 | { 160 | return FindMainEdgeProcess(true); 161 | } 162 | 163 | DWORD FindMainEdgeProcess() 164 | { 165 | return FindMainEdgeProcess(false); 166 | } -------------------------------------------------------------------------------- /EdgeWindowTabManagerBlockDll/dllmain.cpp: -------------------------------------------------------------------------------- 1 | #define WIN32_LEAN_AND_MEAN 2 | #include 3 | #include 4 | #include 5 | #pragma comment (lib, "runtimeobject.lib") 6 | #include 7 | #pragma comment (lib, "shlwapi.lib") 8 | 9 | #define DEFINE_HOOK(func) static decltype(func)* Real_##func = func 10 | #define ATTACH_HOOK(func) DetourAttach((PVOID*)&Real_##func, My_##func) 11 | #define DETACH_HOOK(func) DetourDetach((PVOID*)&Real_##func, My_##func) 12 | 13 | DEFINE_HOOK(RoGetActivationFactory); 14 | DEFINE_HOOK(RoActivateInstance); 15 | DEFINE_HOOK(CreateProcessW); 16 | DEFINE_HOOK(CreateProcessAsUserW); 17 | 18 | static char szThisDllPath[MAX_PATH]; 19 | 20 | bool IsRoClassBlocked(HSTRING activatableClassId) 21 | { 22 | PCWSTR pszClassId = ::WindowsGetStringRawBuffer(activatableClassId, nullptr); 23 | 24 | if (wcscmp(pszClassId, L"WindowsUdk.UI.Shell.WindowTabManager") == 0 25 | || wcscmp(pszClassId, L"Windows.UI.Shell.WindowTabManager") == 0) // case sensitive 26 | return true; 27 | 28 | return false; 29 | } 30 | 31 | HRESULT WINAPI My_RoGetActivationFactory(HSTRING activatableClassId, REFIID iid, void** factory) 32 | { 33 | if (IsRoClassBlocked(activatableClassId)) 34 | return E_ACCESSDENIED; 35 | return Real_RoGetActivationFactory(activatableClassId, iid, factory); 36 | } 37 | 38 | HRESULT WINAPI My_RoActivateInstance(HSTRING activatableClassId, IInspectable** instance) 39 | { 40 | if (IsRoClassBlocked(activatableClassId)) 41 | return E_ACCESSDENIED; 42 | return Real_RoActivateInstance(activatableClassId, instance); 43 | } 44 | 45 | bool IsEdge(LPWSTR lpCommandLine) 46 | { 47 | LPWSTR path = _wcsdup(lpCommandLine); 48 | if (!path) return false; 49 | PathRemoveArgsW(path); 50 | PathRemoveBlanksW(path); 51 | PathUnquoteSpacesW(path); 52 | int ret = StrCmpIW(PathFindFileNameW(path), L"msedge.exe"); 53 | free(path); 54 | return ret == 0; 55 | } 56 | 57 | BOOL WINAPI My_CreateProcessW( 58 | _In_opt_ LPCWSTR lpApplicationName, 59 | _Inout_opt_ LPWSTR lpCommandLine, 60 | _In_opt_ LPSECURITY_ATTRIBUTES lpProcessAttributes, 61 | _In_opt_ LPSECURITY_ATTRIBUTES lpThreadAttributes, 62 | _In_ BOOL bInheritHandles, 63 | _In_ DWORD dwCreationFlags, 64 | _In_opt_ LPVOID lpEnvironment, 65 | _In_opt_ LPCWSTR lpCurrentDirectory, 66 | _In_ LPSTARTUPINFOW lpStartupInfo, 67 | _Out_ LPPROCESS_INFORMATION lpProcessInformation 68 | ) 69 | { 70 | // We only care about Edge sub-processes 71 | if (!lpCommandLine || !IsEdge(lpCommandLine)) 72 | return Real_CreateProcessW(lpApplicationName, lpCommandLine, lpProcessAttributes, lpThreadAttributes, 73 | bInheritHandles, dwCreationFlags, 74 | lpEnvironment, lpCurrentDirectory, lpStartupInfo, lpProcessInformation); 75 | 76 | // Bypass IFEO for sub-process creation 77 | if (!Real_CreateProcessW(lpApplicationName, lpCommandLine, lpProcessAttributes, lpThreadAttributes, 78 | bInheritHandles, dwCreationFlags | DEBUG_ONLY_THIS_PROCESS | CREATE_SUSPENDED, 79 | lpEnvironment, lpCurrentDirectory, lpStartupInfo, lpProcessInformation)) 80 | return FALSE; 81 | 82 | DebugActiveProcessStop(lpProcessInformation->dwProcessId); 83 | 84 | // Inject this DLL into sub-processes as well 85 | // but not into things like renderers because they are protected 86 | if (wcsstr(lpCommandLine, L"--type=") == nullptr) 87 | { 88 | LPCSTR pDllPath = szThisDllPath; 89 | DetourUpdateProcessWithDll(lpProcessInformation->hProcess, &pDllPath, 1); 90 | } 91 | 92 | if (!(dwCreationFlags & CREATE_SUSPENDED)) 93 | ResumeThread(lpProcessInformation->hThread); 94 | 95 | return TRUE; 96 | } 97 | 98 | BOOL WINAPI My_CreateProcessAsUserW( 99 | _In_opt_ HANDLE hToken, 100 | _In_opt_ LPCWSTR lpApplicationName, 101 | _Inout_opt_ LPWSTR lpCommandLine, 102 | _In_opt_ LPSECURITY_ATTRIBUTES lpProcessAttributes, 103 | _In_opt_ LPSECURITY_ATTRIBUTES lpThreadAttributes, 104 | _In_ BOOL bInheritHandles, 105 | _In_ DWORD dwCreationFlags, 106 | _In_opt_ LPVOID lpEnvironment, 107 | _In_opt_ LPCWSTR lpCurrentDirectory, 108 | _In_ LPSTARTUPINFOW lpStartupInfo, 109 | _Out_ LPPROCESS_INFORMATION lpProcessInformation 110 | ) 111 | { 112 | // We only care about Edge sub-processes 113 | if (!lpCommandLine || !IsEdge(lpCommandLine)) 114 | return Real_CreateProcessAsUserW(hToken, lpApplicationName, lpCommandLine, lpProcessAttributes, lpThreadAttributes, 115 | bInheritHandles, dwCreationFlags, 116 | lpEnvironment, lpCurrentDirectory, lpStartupInfo, lpProcessInformation); 117 | 118 | // Bypass IFEO for sub-process creation 119 | if (!Real_CreateProcessAsUserW(hToken, lpApplicationName, lpCommandLine, lpProcessAttributes, lpThreadAttributes, 120 | bInheritHandles, dwCreationFlags | DEBUG_ONLY_THIS_PROCESS | CREATE_SUSPENDED, 121 | lpEnvironment, lpCurrentDirectory, lpStartupInfo, lpProcessInformation)) 122 | return FALSE; 123 | 124 | DebugActiveProcessStop(lpProcessInformation->dwProcessId); 125 | 126 | // Inject this DLL into sub-processes as well 127 | // but not into things like renderers because they are protected 128 | if (wcsstr(lpCommandLine, L"--type=") == nullptr) 129 | { 130 | LPCSTR pDllPath = szThisDllPath; 131 | DetourUpdateProcessWithDll(lpProcessInformation->hProcess, &pDllPath, 1); 132 | } 133 | 134 | if (!(dwCreationFlags & CREATE_SUSPENDED)) 135 | ResumeThread(lpProcessInformation->hThread); 136 | 137 | return TRUE; 138 | } 139 | 140 | BOOL APIENTRY DllMain(HMODULE hModule, DWORD ul_reason_for_call, LPVOID) 141 | { 142 | if (DetourIsHelperProcess()) 143 | return TRUE; 144 | 145 | switch (ul_reason_for_call) 146 | { 147 | case DLL_PROCESS_ATTACH: 148 | GetModuleFileNameA(hModule, szThisDllPath, MAX_PATH); 149 | DetourRestoreAfterWith(); 150 | DetourTransactionBegin(); 151 | DetourUpdateThread(GetCurrentThread()); 152 | ATTACH_HOOK(RoGetActivationFactory); 153 | ATTACH_HOOK(RoActivateInstance); 154 | ATTACH_HOOK(CreateProcessW); 155 | ATTACH_HOOK(CreateProcessAsUserW); 156 | DetourTransactionCommit(); 157 | break; 158 | 159 | case DLL_PROCESS_DETACH: 160 | DetourTransactionBegin(); 161 | DetourUpdateThread(GetCurrentThread()); 162 | DETACH_HOOK(RoGetActivationFactory); 163 | DETACH_HOOK(RoActivateInstance); 164 | DETACH_HOOK(CreateProcessW); 165 | DETACH_HOOK(CreateProcessAsUserW); 166 | DetourTransactionCommit(); 167 | break; 168 | } 169 | 170 | return TRUE; 171 | } 172 | 173 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | ## Ignore Visual Studio temporary files, build results, and 2 | ## files generated by popular Visual Studio add-ons. 3 | ## 4 | ## Get latest from https://github.com/github/gitignore/blob/master/VisualStudio.gitignore 5 | 6 | # User-specific files 7 | *.rsuser 8 | *.suo 9 | *.user 10 | *.userosscache 11 | *.sln.docstates 12 | 13 | # User-specific files (MonoDevelop/Xamarin Studio) 14 | *.userprefs 15 | 16 | # Mono auto generated files 17 | mono_crash.* 18 | 19 | # Build results 20 | [Dd]ebug/ 21 | [Dd]ebugPublic/ 22 | [Rr]elease/ 23 | [Rr]eleases/ 24 | x64/ 25 | x86/ 26 | [Ww][Ii][Nn]32/ 27 | [Aa][Rr][Mm]/ 28 | [Aa][Rr][Mm]64/ 29 | bld/ 30 | [Bb]in/ 31 | [Oo]bj/ 32 | [Oo]ut/ 33 | [Ll]og/ 34 | [Ll]ogs/ 35 | 36 | # Visual Studio 2015/2017 cache/options directory 37 | .vs/ 38 | # Uncomment if you have tasks that create the project's static files in wwwroot 39 | #wwwroot/ 40 | 41 | # Visual Studio 2017 auto generated files 42 | Generated\ Files/ 43 | 44 | # MSTest test Results 45 | [Tt]est[Rr]esult*/ 46 | [Bb]uild[Ll]og.* 47 | 48 | # NUnit 49 | *.VisualState.xml 50 | TestResult.xml 51 | nunit-*.xml 52 | 53 | # Build Results of an ATL Project 54 | [Dd]ebugPS/ 55 | [Rr]eleasePS/ 56 | dlldata.c 57 | 58 | # Benchmark Results 59 | BenchmarkDotNet.Artifacts/ 60 | 61 | # .NET Core 62 | project.lock.json 63 | project.fragment.lock.json 64 | artifacts/ 65 | 66 | # ASP.NET Scaffolding 67 | ScaffoldingReadMe.txt 68 | 69 | # StyleCop 70 | StyleCopReport.xml 71 | 72 | # Files built by Visual Studio 73 | *_i.c 74 | *_p.c 75 | *_h.h 76 | *.ilk 77 | *.meta 78 | *.obj 79 | *.iobj 80 | *.pch 81 | *.pdb 82 | *.ipdb 83 | *.pgc 84 | *.pgd 85 | *.rsp 86 | *.sbr 87 | *.tlb 88 | *.tli 89 | *.tlh 90 | *.tmp 91 | *.tmp_proj 92 | *_wpftmp.csproj 93 | *.log 94 | *.vspscc 95 | *.vssscc 96 | .builds 97 | *.pidb 98 | *.svclog 99 | *.scc 100 | 101 | # Chutzpah Test files 102 | _Chutzpah* 103 | 104 | # Visual C++ cache files 105 | ipch/ 106 | *.aps 107 | *.ncb 108 | *.opendb 109 | *.opensdf 110 | *.sdf 111 | *.cachefile 112 | *.VC.db 113 | *.VC.VC.opendb 114 | 115 | # Visual Studio profiler 116 | *.psess 117 | *.vsp 118 | *.vspx 119 | *.sap 120 | 121 | # Visual Studio Trace Files 122 | *.e2e 123 | 124 | # TFS 2012 Local Workspace 125 | $tf/ 126 | 127 | # Guidance Automation Toolkit 128 | *.gpState 129 | 130 | # ReSharper is a .NET coding add-in 131 | _ReSharper*/ 132 | *.[Rr]e[Ss]harper 133 | *.DotSettings.user 134 | 135 | # TeamCity is a build add-in 136 | _TeamCity* 137 | 138 | # DotCover is a Code Coverage Tool 139 | *.dotCover 140 | 141 | # AxoCover is a Code Coverage Tool 142 | .axoCover/* 143 | !.axoCover/settings.json 144 | 145 | # Coverlet is a free, cross platform Code Coverage Tool 146 | coverage*.json 147 | coverage*.xml 148 | coverage*.info 149 | 150 | # Visual Studio code coverage results 151 | *.coverage 152 | *.coveragexml 153 | 154 | # NCrunch 155 | _NCrunch_* 156 | .*crunch*.local.xml 157 | nCrunchTemp_* 158 | 159 | # MightyMoose 160 | *.mm.* 161 | AutoTest.Net/ 162 | 163 | # Web workbench (sass) 164 | .sass-cache/ 165 | 166 | # Installshield output folder 167 | [Ee]xpress/ 168 | 169 | # DocProject is a documentation generator add-in 170 | DocProject/buildhelp/ 171 | DocProject/Help/*.HxT 172 | DocProject/Help/*.HxC 173 | DocProject/Help/*.hhc 174 | DocProject/Help/*.hhk 175 | DocProject/Help/*.hhp 176 | DocProject/Help/Html2 177 | DocProject/Help/html 178 | 179 | # Click-Once directory 180 | publish/ 181 | 182 | # Publish Web Output 183 | *.[Pp]ublish.xml 184 | *.azurePubxml 185 | # Note: Comment the next line if you want to checkin your web deploy settings, 186 | # but database connection strings (with potential passwords) will be unencrypted 187 | *.pubxml 188 | *.publishproj 189 | 190 | # Microsoft Azure Web App publish settings. Comment the next line if you want to 191 | # checkin your Azure Web App publish settings, but sensitive information contained 192 | # in these scripts will be unencrypted 193 | PublishScripts/ 194 | 195 | # NuGet Packages 196 | *.nupkg 197 | # NuGet Symbol Packages 198 | *.snupkg 199 | # The packages folder can be ignored because of Package Restore 200 | **/[Pp]ackages/* 201 | # except build/, which is used as an MSBuild target. 202 | !**/[Pp]ackages/build/ 203 | # Uncomment if necessary however generally it will be regenerated when needed 204 | #!**/[Pp]ackages/repositories.config 205 | # NuGet v3's project.json files produces more ignorable files 206 | *.nuget.props 207 | *.nuget.targets 208 | 209 | # Microsoft Azure Build Output 210 | csx/ 211 | *.build.csdef 212 | 213 | # Microsoft Azure Emulator 214 | ecf/ 215 | rcf/ 216 | 217 | # Windows Store app package directories and files 218 | AppPackages/ 219 | BundleArtifacts/ 220 | Package.StoreAssociation.xml 221 | _pkginfo.txt 222 | *.appx 223 | *.appxbundle 224 | *.appxupload 225 | 226 | # Visual Studio cache files 227 | # files ending in .cache can be ignored 228 | *.[Cc]ache 229 | # but keep track of directories ending in .cache 230 | !?*.[Cc]ache/ 231 | 232 | # Others 233 | ClientBin/ 234 | ~$* 235 | *~ 236 | *.dbmdl 237 | *.dbproj.schemaview 238 | *.jfm 239 | *.pfx 240 | *.publishsettings 241 | orleans.codegen.cs 242 | 243 | # Including strong name files can present a security risk 244 | # (https://github.com/github/gitignore/pull/2483#issue-259490424) 245 | #*.snk 246 | 247 | # Since there are multiple workflows, uncomment next line to ignore bower_components 248 | # (https://github.com/github/gitignore/pull/1529#issuecomment-104372622) 249 | #bower_components/ 250 | 251 | # RIA/Silverlight projects 252 | Generated_Code/ 253 | 254 | # Backup & report files from converting an old project file 255 | # to a newer Visual Studio version. Backup files are not needed, 256 | # because we have git ;-) 257 | _UpgradeReport_Files/ 258 | Backup*/ 259 | UpgradeLog*.XML 260 | UpgradeLog*.htm 261 | ServiceFabricBackup/ 262 | *.rptproj.bak 263 | 264 | # SQL Server files 265 | *.mdf 266 | *.ldf 267 | *.ndf 268 | 269 | # Business Intelligence projects 270 | *.rdl.data 271 | *.bim.layout 272 | *.bim_*.settings 273 | *.rptproj.rsuser 274 | *- [Bb]ackup.rdl 275 | *- [Bb]ackup ([0-9]).rdl 276 | *- [Bb]ackup ([0-9][0-9]).rdl 277 | 278 | # Microsoft Fakes 279 | FakesAssemblies/ 280 | 281 | # GhostDoc plugin setting file 282 | *.GhostDoc.xml 283 | 284 | # Node.js Tools for Visual Studio 285 | .ntvs_analysis.dat 286 | node_modules/ 287 | 288 | # Visual Studio 6 build log 289 | *.plg 290 | 291 | # Visual Studio 6 workspace options file 292 | *.opt 293 | 294 | # Visual Studio 6 auto-generated workspace file (contains which files were open etc.) 295 | *.vbw 296 | 297 | # Visual Studio LightSwitch build output 298 | **/*.HTMLClient/GeneratedArtifacts 299 | **/*.DesktopClient/GeneratedArtifacts 300 | **/*.DesktopClient/ModelManifest.xml 301 | **/*.Server/GeneratedArtifacts 302 | **/*.Server/ModelManifest.xml 303 | _Pvt_Extensions 304 | 305 | # Paket dependency manager 306 | .paket/paket.exe 307 | paket-files/ 308 | 309 | # FAKE - F# Make 310 | .fake/ 311 | 312 | # CodeRush personal settings 313 | .cr/personal 314 | 315 | # Python Tools for Visual Studio (PTVS) 316 | __pycache__/ 317 | *.pyc 318 | 319 | # Cake - Uncomment if you are using it 320 | # tools/** 321 | # !tools/packages.config 322 | 323 | # Tabs Studio 324 | *.tss 325 | 326 | # Telerik's JustMock configuration file 327 | *.jmconfig 328 | 329 | # BizTalk build output 330 | *.btp.cs 331 | *.btm.cs 332 | *.odx.cs 333 | *.xsd.cs 334 | 335 | # OpenCover UI analysis results 336 | OpenCover/ 337 | 338 | # Azure Stream Analytics local run output 339 | ASALocalRun/ 340 | 341 | # MSBuild Binary and Structured Log 342 | *.binlog 343 | 344 | # NVidia Nsight GPU debugger configuration file 345 | *.nvuser 346 | 347 | # MFractors (Xamarin productivity tool) working folder 348 | .mfractor/ 349 | 350 | # Local History for Visual Studio 351 | .localhistory/ 352 | 353 | # BeatPulse healthcheck temp database 354 | healthchecksdb 355 | 356 | # Backup folder for Package Reference Convert tool in Visual Studio 2017 357 | MigrationBackup/ 358 | 359 | # Ionide (cross platform F# VS Code tools) working folder 360 | .ionide/ 361 | 362 | # Fody - auto-generated XML schema 363 | FodyWeavers.xsd -------------------------------------------------------------------------------- /EdgeWindowTabManagerBlock/edgeutils.cpp: -------------------------------------------------------------------------------- 1 | #define WIN32_LEAN_AND_MEAN 2 | #include 3 | #include "../wrappers.h" 4 | #include "resource.h" 5 | #include 6 | #pragma comment (lib, "dbghelp.lib") 7 | #include 8 | #pragma comment (lib, "shlwapi.lib") 9 | #include 10 | #pragma comment (lib, "comctl32.lib") 11 | #include 12 | #pragma comment (lib, "comdlg32.lib") 13 | #include 14 | #include 15 | #include 16 | #include 17 | 18 | #if defined _M_IX86 19 | #pragma comment(linker, "/manifestdependency:\"type='win32' name='Microsoft.Windows.Common-Controls' version='6.0.0.0' processorArchitecture='x86' publicKeyToken='6595b64144ccf1df' language='*'\"") 20 | #elif defined _M_IA64 21 | #pragma comment(linker, "/manifestdependency:\"type='win32' name='Microsoft.Windows.Common-Controls' version='6.0.0.0' processorArchitecture='ia64' publicKeyToken='6595b64144ccf1df' language='*'\"") 22 | #elif defined _M_X64 23 | #pragma comment(linker, "/manifestdependency:\"type='win32' name='Microsoft.Windows.Common-Controls' version='6.0.0.0' processorArchitecture='amd64' publicKeyToken='6595b64144ccf1df' language='*'\"") 24 | #else 25 | #pragma comment(linker, "/manifestdependency:\"type='win32' name='Microsoft.Windows.Common-Controls' version='6.0.0.0' processorArchitecture='*' publicKeyToken='6595b64144ccf1df' language='*'\"") 26 | #endif 27 | 28 | static std::wstring GetRegString(HKEY hKey, LPCWSTR lpSubKey, LPCWSTR lpValue) 29 | { 30 | DWORD cb = 0; 31 | LSTATUS err = RegGetValueW(hKey, lpSubKey, lpValue, RRF_RT_REG_SZ, nullptr, nullptr, &cb); 32 | if (err != ERROR_SUCCESS) 33 | return {}; 34 | 35 | auto pBuf = std::make_unique(cb); 36 | err = RegGetValueW(hKey, lpSubKey, lpValue, RRF_RT_REG_SZ, nullptr, pBuf.get(), &cb); 37 | if (err != ERROR_SUCCESS) 38 | return {}; 39 | 40 | return std::wstring(reinterpret_cast(pBuf.get())); 41 | } 42 | 43 | static bool IsEdgePath(LPCWSTR lpPath) 44 | { 45 | return StrCmpIW(PathFindFileNameW(lpPath), L"msedge.exe") == 0; 46 | } 47 | 48 | static std::wstring GetDefaultBrowserPath() 49 | { 50 | DWORD cch = 0; 51 | if (AssocQueryStringW(ASSOCF_IS_PROTOCOL, ASSOCSTR_EXECUTABLE, L"https", L"open", nullptr, &cch) != S_FALSE) 52 | return {}; 53 | 54 | auto pBuf = std::make_unique(cch); 55 | if (FAILED(AssocQueryStringW(ASSOCF_IS_PROTOCOL, ASSOCSTR_EXECUTABLE, L"https", L"open", pBuf.get(), &cch))) 56 | return {}; 57 | 58 | return std::wstring(pBuf.get()); 59 | } 60 | 61 | static std::wstring GetBrowserPath(HKEY hKeyBrowser) 62 | { 63 | DWORD cch = 0; 64 | if (AssocQueryStringByKeyW(0, ASSOCSTR_EXECUTABLE, hKeyBrowser, L"open", nullptr, &cch) != S_FALSE) 65 | return {}; 66 | 67 | auto pBuf = std::make_unique(cch); 68 | if (FAILED(AssocQueryStringByKeyW(0, ASSOCSTR_EXECUTABLE, hKeyBrowser, L"open", pBuf.get(), &cch))) 69 | return {}; 70 | 71 | return std::wstring(pBuf.get()); 72 | } 73 | 74 | struct BrowserInfo 75 | { 76 | std::wstring title; 77 | std::wstring path; 78 | }; 79 | 80 | static std::vector GetEdgeVersionList() 81 | { 82 | std::vector list; 83 | HKey hKeyBrowsers; 84 | if (RegOpenKeyExW(HKEY_LOCAL_MACHINE, L"SOFTWARE\\Clients\\StartMenuInternet", 0, KEY_ENUMERATE_SUB_KEYS, &hKeyBrowsers) 85 | != ERROR_SUCCESS) 86 | return {}; 87 | 88 | for (int index = 0; ; index++) 89 | { 90 | WCHAR szKeyName[256]; 91 | DWORD cchKeyName = 256; 92 | LRESULT err = RegEnumKeyExW(hKeyBrowsers, index, szKeyName, &cchKeyName, nullptr, nullptr, nullptr, nullptr); 93 | if (err == ERROR_NO_MORE_ITEMS) 94 | break; 95 | 96 | HKey hKeyBrowser; 97 | if (RegOpenKeyExW(hKeyBrowsers, szKeyName, 0, KEY_QUERY_VALUE, &hKeyBrowser) != ERROR_SUCCESS) 98 | continue; 99 | 100 | BrowserInfo info; 101 | 102 | info.title = GetRegString(hKeyBrowser, nullptr, nullptr); 103 | if (info.title.empty()) 104 | continue; 105 | 106 | info.path = GetBrowserPath(hKeyBrowser); 107 | if (info.path.empty() || !IsEdgePath(info.path.c_str())) 108 | continue; 109 | 110 | list.push_back(std::move(info)); 111 | } 112 | 113 | return list; 114 | } 115 | 116 | static bool HasNewEdgeVersions() 117 | { 118 | DWORD cb = 0; 119 | LSTATUS err = RegGetValueW(HKEY_CURRENT_USER, L"Software\\EdgeWindowTabManagerBlock", L"LastEdgeVersionList", RRF_RT_REG_MULTI_SZ, 120 | nullptr, nullptr, &cb); 121 | if (err != ERROR_SUCCESS) 122 | return false; // skip checking and silently continue if LastEdgeVersionList does not exist 123 | 124 | std::unique_ptr pBuf(new BYTE[cb]); 125 | err = RegGetValueW(HKEY_CURRENT_USER, L"Software\\EdgeWindowTabManagerBlock", L"LastEdgeVersionList", 126 | RRF_RT_REG_MULTI_SZ, nullptr, pBuf.get(), &cb); 127 | if (err != ERROR_SUCCESS) 128 | return false; 129 | 130 | LPCWSTR pEdgeVersions = reinterpret_cast(pBuf.get()); 131 | 132 | for (auto& edgeVersion : GetEdgeVersionList()) 133 | { 134 | bool found = false; 135 | for (LPCWSTR pEdgeVersion = pEdgeVersions; *pEdgeVersion != '\0'; pEdgeVersion += wcslen(pEdgeVersion) + 1) 136 | { 137 | if (edgeVersion.title == pEdgeVersion) 138 | { 139 | found = true; 140 | break; 141 | } 142 | } 143 | if (!found) 144 | return true; 145 | } 146 | 147 | return false; 148 | } 149 | 150 | bool ShowChooseEdgeVersionDlg() 151 | { 152 | TASKDIALOGCONFIG cfg = { sizeof cfg }; 153 | cfg.dwFlags = TDF_USE_COMMAND_LINKS | TDF_SIZE_TO_CONTENT; 154 | cfg.dwCommonButtons = TDCBF_CANCEL_BUTTON; 155 | cfg.pszWindowTitle = MAKEINTRESOURCEW(IDS_PROGRAMNAME); 156 | cfg.pszMainInstruction = MAKEINTRESOURCEW(IDS_CHOOSE_EDGE_VER); 157 | cfg.pszFooter = MAKEINTRESOURCEW(IDS_CHOOSE_EDGE_DLG_TIP); 158 | cfg.pszFooterIcon = TD_INFORMATION_ICON; 159 | 160 | TASKDIALOG_BUTTON btn; 161 | std::vector btns; 162 | std::vector btntexts; // store button strings to be passed to the API 163 | 164 | btn.nButtonID = 50; 165 | btn.pszButtonText = MAKEINTRESOURCEW(IDS_FOLLOW_DEFAULT_BROWSER); 166 | btns.push_back(btn); 167 | 168 | btn.nButtonID = 100; // Edge version button IDs start from 100 169 | 170 | auto edgeVersions = GetEdgeVersionList(); 171 | 172 | for (auto& edgeVersion : edgeVersions) 173 | { 174 | btntexts.push_back(edgeVersion.title + L"\r\n" + edgeVersion.path); 175 | btn.pszButtonText = btntexts.back().c_str(); 176 | btns.push_back(btn); 177 | btn.nButtonID++; // increase button ID 178 | } 179 | 180 | btn.nButtonID = 51; 181 | btn.pszButtonText = MAKEINTRESOURCEW(IDS_BROWSE_FOR_EDGE_EXE); 182 | btns.push_back(btn); 183 | 184 | cfg.cButtons = btns.size(); 185 | cfg.pButtons = btns.data(); 186 | 187 | int sel = 0; 188 | TaskDialogIndirect(&cfg, &sel, nullptr, nullptr); 189 | 190 | if (sel >= 100) // an Edge version button 191 | { 192 | auto& path = edgeVersions[sel - 100].path; 193 | RegSetKeyValueW(HKEY_CURRENT_USER, L"Software\\EdgeWindowTabManagerBlock", L"EdgePath", REG_SZ, 194 | path.c_str(), (path.size() + 1) * sizeof(wchar_t)); 195 | 196 | // store the current installed Edge version list 197 | std::wstring edgeVerStr; 198 | for (auto& edgeVersion : edgeVersions) 199 | { 200 | edgeVerStr += edgeVersion.title; 201 | edgeVerStr += L'\0'; 202 | } 203 | 204 | RegSetKeyValueW(HKEY_CURRENT_USER, L"Software\\EdgeWindowTabManagerBlock", L"LastEdgeVersionList", REG_MULTI_SZ, 205 | edgeVerStr.c_str(), (edgeVerStr.size() + 1) * sizeof(wchar_t)); 206 | } 207 | else if (sel == 50) // follow default button 208 | { 209 | RegSetKeyValueW(HKEY_CURRENT_USER, L"Software\\EdgeWindowTabManagerBlock", L"EdgePath", REG_SZ, 210 | L"", sizeof(L"")); // a special value for default 211 | RegDeleteKeyValueW(HKEY_CURRENT_USER, L"Software\\EdgeWindowTabManagerBlock", L"LastEdgeVersionList"); 212 | } 213 | else if (sel == 51) // browse... button 214 | { 215 | OPENFILENAMEW ofn = { sizeof ofn }; 216 | WCHAR filename[MAX_PATH] = { 0 }; 217 | ofn.lpstrFilter = L"msedge.exe\0msedge.exe\0*.exe\0*.exe\0"; 218 | ofn.nFilterIndex = 1; 219 | ofn.lpstrFile = filename; 220 | ofn.nMaxFile = MAX_PATH; 221 | ofn.lpstrInitialDir = L"%ProgramFiles%"; 222 | ofn.Flags = OFN_EXPLORER | OFN_FILEMUSTEXIST | OFN_PATHMUSTEXIST | OFN_HIDEREADONLY; 223 | 224 | if (!GetOpenFileNameW(&ofn)) 225 | return false; 226 | 227 | RegSetKeyValueW(HKEY_CURRENT_USER, L"Software\\EdgeWindowTabManagerBlock", L"EdgePath", REG_SZ, 228 | ofn.lpstrFile, (wcslen(ofn.lpstrFile) + 1) * sizeof(wchar_t)); 229 | RegDeleteKeyValueW(HKEY_CURRENT_USER, L"Software\\EdgeWindowTabManagerBlock", L"LastEdgeVersionList"); 230 | } 231 | else 232 | { 233 | return false; 234 | } 235 | return true; 236 | } 237 | 238 | std::wstring GetEdgePath() 239 | { 240 | auto userSelectedPath = GetRegString(HKEY_CURRENT_USER, L"Software\\EdgeWindowTabManagerBlock", L"EdgePath"); 241 | auto edgeVers = GetEdgeVersionList(); 242 | 243 | if (!userSelectedPath.empty()) 244 | { 245 | if (userSelectedPath == L"") 246 | { 247 | auto defaultBrowser = GetDefaultBrowserPath(); 248 | if (IsEdgePath(defaultBrowser.c_str())) 249 | return defaultBrowser; 250 | } 251 | else if (PathFileExistsW(userSelectedPath.c_str()) && !HasNewEdgeVersions()) 252 | return userSelectedPath; 253 | else 254 | return {}; // make user select another one 255 | } 256 | 257 | // exactly one Edge version, use it 258 | if (edgeVers.size() == 1) 259 | return edgeVers[0].path; 260 | 261 | return {}; 262 | } -------------------------------------------------------------------------------- /EdgeWindowTabManagerBlockDll/EdgeWindowTabManagerBlockDll.vcxproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Debug 6 | ARM64 7 | 8 | 9 | Debug 10 | Win32 11 | 12 | 13 | Release 14 | ARM64 15 | 16 | 17 | Release 18 | Win32 19 | 20 | 21 | Debug 22 | x64 23 | 24 | 25 | Release 26 | x64 27 | 28 | 29 | 30 | 17.0 31 | Win32Proj 32 | {73f5f261-6380-4565-a8a9-c2e3863a75b0} 33 | EdgeWindowTabManagerBlockDll 34 | 10.0 35 | 36 | 37 | 38 | DynamicLibrary 39 | true 40 | v143 41 | Unicode 42 | 43 | 44 | DynamicLibrary 45 | false 46 | v143 47 | true 48 | Unicode 49 | 50 | 51 | DynamicLibrary 52 | true 53 | v143 54 | Unicode 55 | 56 | 57 | DynamicLibrary 58 | true 59 | v143 60 | Unicode 61 | 62 | 63 | DynamicLibrary 64 | false 65 | v143 66 | true 67 | Unicode 68 | 69 | 70 | DynamicLibrary 71 | false 72 | v143 73 | true 74 | Unicode 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | $(SolutionDir)detours\include;$(ExternalIncludePath) 102 | $(SolutionDir)detours\lib.$(LibrariesArchitecture);$(LibraryPath) 103 | 104 | 105 | $(SolutionDir)detours\include;$(ExternalIncludePath) 106 | $(SolutionDir)detours\lib.$(LibrariesArchitecture);$(LibraryPath) 107 | 108 | 109 | $(SolutionDir)detours\include;$(ExternalIncludePath) 110 | $(SolutionDir)detours\lib.$(LibrariesArchitecture);$(LibraryPath) 111 | 112 | 113 | $(SolutionDir)detours\include;$(ExternalIncludePath) 114 | $(SolutionDir)detours\lib.$(LibrariesArchitecture);$(LibraryPath) 115 | 116 | 117 | $(SolutionDir)detours\include;$(ExternalIncludePath) 118 | $(SolutionDir)detours\lib.$(LibrariesArchitecture);$(LibraryPath) 119 | 120 | 121 | $(SolutionDir)detours\include;$(ExternalIncludePath) 122 | $(SolutionDir)detours\lib.$(LibrariesArchitecture);$(LibraryPath) 123 | 124 | 125 | 126 | Level3 127 | true 128 | WIN32;_DEBUG;EDGEWINDOWTABMANAGERBLOCKDLL_EXPORTS;_WINDOWS;_USRDLL;%(PreprocessorDefinitions) 129 | true 130 | MultiThreadedDebug 131 | 132 | 133 | Windows 134 | true 135 | false 136 | exports.def 137 | /PDBALTPATH:%_PDB% %(AdditionalOptions) 138 | detours.lib;%(AdditionalDependencies) 139 | 140 | 141 | 142 | 143 | Level3 144 | true 145 | true 146 | true 147 | WIN32;NDEBUG;EDGEWINDOWTABMANAGERBLOCKDLL_EXPORTS;_WINDOWS;_USRDLL;%(PreprocessorDefinitions) 148 | true 149 | MultiThreaded 150 | 151 | 152 | Windows 153 | true 154 | true 155 | true 156 | false 157 | exports.def 158 | /PDBALTPATH:%_PDB% %(AdditionalOptions) 159 | detours.lib;%(AdditionalDependencies) 160 | 161 | 162 | 163 | 164 | Level3 165 | true 166 | _DEBUG;EDGEWINDOWTABMANAGERBLOCKDLL_EXPORTS;_WINDOWS;_USRDLL;%(PreprocessorDefinitions) 167 | true 168 | MultiThreadedDebug 169 | 170 | 171 | Windows 172 | true 173 | false 174 | exports.def 175 | /PDBALTPATH:%_PDB% %(AdditionalOptions) 176 | detours.lib;%(AdditionalDependencies) 177 | 178 | 179 | 180 | 181 | Level3 182 | true 183 | _DEBUG;EDGEWINDOWTABMANAGERBLOCKDLL_EXPORTS;_WINDOWS;_USRDLL;%(PreprocessorDefinitions) 184 | true 185 | MultiThreadedDebug 186 | 187 | 188 | Windows 189 | true 190 | false 191 | exports.def 192 | /PDBALTPATH:%_PDB% %(AdditionalOptions) 193 | detours.lib;%(AdditionalDependencies) 194 | 195 | 196 | 197 | 198 | Level3 199 | true 200 | true 201 | true 202 | NDEBUG;EDGEWINDOWTABMANAGERBLOCKDLL_EXPORTS;_WINDOWS;_USRDLL;%(PreprocessorDefinitions) 203 | true 204 | MultiThreaded 205 | 206 | 207 | Windows 208 | true 209 | true 210 | true 211 | false 212 | exports.def 213 | /PDBALTPATH:%_PDB% %(AdditionalOptions) 214 | detours.lib;%(AdditionalDependencies) 215 | 216 | 217 | 218 | 219 | Level3 220 | true 221 | true 222 | true 223 | NDEBUG;EDGEWINDOWTABMANAGERBLOCKDLL_EXPORTS;_WINDOWS;_USRDLL;%(PreprocessorDefinitions) 224 | true 225 | MultiThreaded 226 | 227 | 228 | Windows 229 | true 230 | true 231 | true 232 | false 233 | exports.def 234 | /PDBALTPATH:%_PDB% %(AdditionalOptions) 235 | detours.lib;%(AdditionalDependencies) 236 | 237 | 238 | 239 | 240 | 241 | 242 | 243 | 244 | 245 | 246 | 247 | 248 | 249 | 250 | 251 | 252 | -------------------------------------------------------------------------------- /EdgeWindowTabManagerBlock/source.cpp: -------------------------------------------------------------------------------- 1 | #define WIN32_LEAN_AND_MEAN 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include "resource.h" 11 | #pragma comment (lib, "dbghelp.lib") 12 | #pragma comment (lib, "shlwapi.lib") 13 | 14 | std::wstring LoadResString(UINT id) 15 | { 16 | LPCWSTR p; 17 | int cch = LoadStringW(nullptr, id, (LPWSTR)&p, 0); 18 | return std::wstring(p, cch); 19 | } 20 | 21 | void ReportError(UINT idMessage, DWORD errorCode = 0) 22 | { 23 | WCHAR buffer[1024] = { 0 }; 24 | LoadStringW(NULL, idMessage, buffer, 1024); 25 | 26 | if (errorCode != 0) 27 | { 28 | LPWSTR pStr; 29 | if (FormatMessageW(FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_IGNORE_INSERTS, NULL, 30 | errorCode, LANG_USER_DEFAULT, (LPWSTR)&pStr, 0, NULL) != 0) 31 | { 32 | wcscat_s(buffer, L"\r\n\r\n"); 33 | wcscat_s(buffer, pStr); 34 | LocalFree(pStr); 35 | } 36 | } 37 | 38 | MessageBoxW(NULL, buffer, L"EdgeWindowTabManagerBlock", MB_OK + MB_ICONEXCLAMATION); 39 | } 40 | 41 | WORD GetExecutableMachineType(HANDLE hFile) 42 | { 43 | WORD result = 0; 44 | 45 | HANDLE hMap = CreateFileMappingW(hFile, NULL, PAGE_READONLY | SEC_IMAGE, 0, 0, NULL); 46 | if (hMap) 47 | { 48 | LPVOID pData = MapViewOfFile(hMap, FILE_MAP_READ, 0, 0, 0); 49 | if (pData) 50 | { 51 | PIMAGE_NT_HEADERS pHdr = ImageNtHeader(pData); 52 | if (pHdr) 53 | result = pHdr->FileHeader.Machine; 54 | UnmapViewOfFile(pData); 55 | } 56 | CloseHandle(hMap); 57 | } 58 | 59 | return result; 60 | } 61 | 62 | WORD GetExecutableMachineType(LPCWSTR lpFile) 63 | { 64 | HANDLE hFile = CreateFileW(lpFile, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, NULL); 65 | if (hFile == INVALID_HANDLE_VALUE) 66 | return 0; 67 | WORD result = GetExecutableMachineType(hFile); 68 | CloseHandle(hFile); 69 | return result; 70 | } 71 | 72 | WORD GetExecutableMachineType(LPCSTR lpFile) 73 | { 74 | HANDLE hFile = CreateFileA(lpFile, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, NULL); 75 | if (hFile == INVALID_HANDLE_VALUE) 76 | return 0; 77 | WORD result = GetExecutableMachineType(hFile); 78 | CloseHandle(hFile); 79 | return result; 80 | } 81 | 82 | DWORD FindEdgeProcessWithWindowTabManager(); 83 | DWORD FindMainEdgeProcess(); 84 | bool ShowChooseEdgeVersionDlg(); 85 | std::wstring GetEdgePath(); 86 | 87 | inline LSTATUS WriteRegSZ(HKEY hKey, LPCWSTR lpValueName, LPCWSTR szData) 88 | { 89 | return RegSetValueExW(hKey, lpValueName, 0, REG_SZ, (const BYTE*)szData, (wcslen(szData) + 1) * sizeof(WCHAR)); 90 | } 91 | 92 | LSTATUS AddUninstallRegistryKey() 93 | { 94 | HKEY hKey; 95 | LSTATUS err; 96 | err = RegCreateKeyExW(HKEY_LOCAL_MACHINE, 97 | L"Software\\Microsoft\\Windows\\CurrentVersion\\Uninstall\\EdgeWindowTabManagerBlock", 98 | 0, nullptr, 0, KEY_SET_VALUE, nullptr, &hKey, nullptr); 99 | if (err != ERROR_SUCCESS) 100 | return err; 101 | 102 | WCHAR uninstallCmdLine[MAX_PATH + 11]; 103 | GetModuleFileNameW(nullptr, uninstallCmdLine, MAX_PATH); 104 | PathQuoteSpacesW(uninstallCmdLine); 105 | wcscat_s(uninstallCmdLine, L" --uninstall-ifeo-debugger"); 106 | 107 | if (err == ERROR_SUCCESS) err = WriteRegSZ(hKey, L"DisplayName", L"EdgeWindowTabManagerBlock (as Edge debugger)"); 108 | if (err == ERROR_SUCCESS) err = WriteRegSZ(hKey, L"DisplayVersion", L"0.4"); 109 | if (err == ERROR_SUCCESS) err = WriteRegSZ(hKey, L"Publisher", L"gexgd0419 on GitHub"); 110 | if (err == ERROR_SUCCESS) err = WriteRegSZ(hKey, L"UninstallString", uninstallCmdLine); 111 | if (err == ERROR_SUCCESS) err = WriteRegSZ(hKey, L"HelpLink", L"https://github.com/gexgd0419/EdgeWindowTabManagerBlock"); 112 | if (err == ERROR_SUCCESS) err = WriteRegSZ(hKey, L"URLInfoAbout", L"https://github.com/gexgd0419/EdgeWindowTabManagerBlock"); 113 | if (err == ERROR_SUCCESS) err = WriteRegSZ(hKey, L"URLUpdateInfo", L"https://github.com/gexgd0419/EdgeWindowTabManagerBlock/releases"); 114 | 115 | RegCloseKey(hKey); 116 | return err; 117 | } 118 | 119 | bool ShowInstallDebuggerDlg(bool force) 120 | { 121 | DWORD cb = 0; 122 | if (RegGetValueW(HKEY_LOCAL_MACHINE, 123 | L"SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\Image File Execution Options\\msedge.exe", 124 | L"Debugger", RRF_RT_REG_SZ, nullptr, nullptr, &cb) == ERROR_SUCCESS) 125 | { 126 | // already installed 127 | return true; 128 | } 129 | 130 | DWORD fDoNotAsk = 0; 131 | cb = sizeof(DWORD); 132 | if (!force) 133 | { 134 | RegGetValueW(HKEY_CURRENT_USER, L"Software\\EdgeWindowTabManagerBlock", L"DebuggerInstallDoNotAsk", RRF_RT_DWORD, 135 | nullptr, &fDoNotAsk, &cb); 136 | if (fDoNotAsk) 137 | return true; 138 | } 139 | 140 | TASKDIALOGCONFIG cfg = { sizeof cfg }; 141 | cfg.dwFlags = TDF_USE_COMMAND_LINKS | TDF_SIZE_TO_CONTENT; 142 | cfg.pszWindowTitle = MAKEINTRESOURCEW(IDS_PROGRAMNAME); 143 | cfg.pszMainInstruction = MAKEINTRESOURCEW(IDS_REGISTER_DEBUGGER_ASK); 144 | cfg.pszContent = MAKEINTRESOURCEW(IDS_REGISTER_DEBUGGER_REASON); 145 | cfg.pszFooter = MAKEINTRESOURCEW(IDS_REGISTER_DLG_TIP); 146 | cfg.pszFooterIcon = TD_INFORMATION_ICON; 147 | 148 | TASKDIALOG_BUTTON btns[] = 149 | { 150 | { IDYES, MAKEINTRESOURCEW(IDS_REGISTER_AS_DEBUGGER) }, 151 | { IDNO, MAKEINTRESOURCEW(IDS_DO_NOT_REGISTER) }, 152 | { IDIGNORE, MAKEINTRESOURCEW(IDS_ASK_ME_LATER) }, 153 | }; 154 | 155 | cfg.cButtons = std::size(btns); 156 | cfg.pButtons = btns; 157 | 158 | cfg.pfCallback = [](HWND hwnd, UINT msg, WPARAM, LPARAM, LONG_PTR) -> HRESULT 159 | { 160 | if (msg == TDN_DIALOG_CONSTRUCTED) 161 | { 162 | SendMessageW(hwnd, TDM_SET_BUTTON_ELEVATION_REQUIRED_STATE, IDYES, TRUE); 163 | } 164 | return S_OK; 165 | }; 166 | 167 | int sel = 0; 168 | TaskDialogIndirect(&cfg, &sel, nullptr, nullptr); 169 | 170 | switch (sel) 171 | { 172 | case IDYES: 173 | if (FindMainEdgeProcess() != 0) 174 | { 175 | std::wstring msg = LoadResString(IDS_REGISTER_EXIT_EDGE); 176 | do 177 | { 178 | int ret = MessageBoxW(NULL, msg.c_str(), L"EdgeWindowTabManagerBlock", MB_CANCELTRYCONTINUE + MB_ICONEXCLAMATION); 179 | if (ret == IDCANCEL) 180 | return false; 181 | else if (ret == IDCONTINUE) 182 | break; 183 | } while (FindMainEdgeProcess() != 0); 184 | } 185 | 186 | // launch itself elevated to perform installation 187 | WCHAR path[MAX_PATH]; 188 | GetModuleFileNameW(nullptr, path, MAX_PATH); 189 | ShellExecuteW(nullptr, L"runas", path, L"--install-ifeo-debugger", nullptr, SW_SHOWNORMAL); 190 | fDoNotAsk = FALSE; 191 | RegSetKeyValueW(HKEY_CURRENT_USER, L"Software\\EdgeWindowTabManagerBlock", L"DebuggerInstallDoNotAsk", REG_DWORD, 192 | &fDoNotAsk, sizeof(DWORD)); 193 | return false; 194 | 195 | case IDNO: 196 | fDoNotAsk = TRUE; 197 | RegSetKeyValueW(HKEY_CURRENT_USER, L"Software\\EdgeWindowTabManagerBlock", L"DebuggerInstallDoNotAsk", REG_DWORD, 198 | &fDoNotAsk, sizeof(DWORD)); 199 | return true; // continue launching Edge 200 | 201 | case IDIGNORE: 202 | fDoNotAsk = FALSE; 203 | RegSetKeyValueW(HKEY_CURRENT_USER, L"Software\\EdgeWindowTabManagerBlock", L"DebuggerInstallDoNotAsk", REG_DWORD, 204 | &fDoNotAsk, sizeof(DWORD)); 205 | return true; // continue launching Edge 206 | 207 | case IDCANCEL: 208 | default: 209 | return false; 210 | } 211 | } 212 | 213 | int DoInstall() 214 | { 215 | WCHAR cmdline[MAX_PATH + 13]; 216 | GetModuleFileNameW(nullptr, cmdline, MAX_PATH); 217 | PathQuoteSpacesW(cmdline); 218 | wcscat_s(cmdline, L" --ifeo-debug"); 219 | 220 | LSTATUS err = AddUninstallRegistryKey(); 221 | 222 | if (err == ERROR_SUCCESS) 223 | err = RegSetKeyValueW(HKEY_LOCAL_MACHINE, L"SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\Image File Execution Options\\msedge.exe", 224 | L"Debugger", REG_SZ, cmdline, (wcslen(cmdline) + 1) * sizeof(WCHAR)); 225 | 226 | if (err != ERROR_SUCCESS) 227 | { 228 | RegDeleteKeyExW(HKEY_LOCAL_MACHINE, L"Software\\Microsoft\\Windows\\CurrentVersion\\Uninstall\\EdgeWindowTabManagerBlock", 0, 0); 229 | ReportError(IDS_REGISTRATION_FAILED, err); 230 | return HRESULT_FROM_WIN32(err); 231 | } 232 | 233 | MessageBoxW(NULL, LoadResString(IDS_REGISTRATION_COMPLETED).c_str(), L"EdgeWindowTabManagerBlock", MB_ICONINFORMATION); 234 | return 0; 235 | } 236 | 237 | int DoUninstall() 238 | { 239 | HKEY hKey; 240 | LSTATUS err = RegOpenKeyExW(HKEY_LOCAL_MACHINE, L"SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\Image File Execution Options\\msedge.exe", 241 | 0, KEY_QUERY_VALUE | KEY_SET_VALUE, &hKey); 242 | 243 | if (err == ERROR_SUCCESS) 244 | err = RegDeleteValueW(hKey, L"Debugger"); 245 | 246 | if (err == ERROR_SUCCESS) 247 | { 248 | DWORD valueCount = 1; 249 | RegQueryInfoKeyW(hKey, nullptr, nullptr, nullptr, &valueCount, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr); 250 | RegCloseKey(hKey); 251 | if (valueCount == 0) // when there's no value, remove the entire key 252 | RegDeleteKeyExW(HKEY_LOCAL_MACHINE, L"SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\Image File Execution Options\\msedge.exe", 0, 0); 253 | } 254 | else if (err != ERROR_FILE_NOT_FOUND) // Ignore when key not found 255 | { 256 | ReportError(IDS_UNREGISTRATION_FAILED, err); 257 | return HRESULT_FROM_WIN32(err); 258 | } 259 | 260 | err = RegDeleteKeyExW(HKEY_LOCAL_MACHINE, L"Software\\Microsoft\\Windows\\CurrentVersion\\Uninstall\\EdgeWindowTabManagerBlock", 0, 0); 261 | if (err != 0 && err != ERROR_FILE_NOT_FOUND) // Ignore when key not found 262 | { 263 | ReportError(IDS_UNREGISTRATION_FAILED, err); 264 | return HRESULT_FROM_WIN32(err); 265 | } 266 | 267 | MessageBoxW(NULL, LoadResString(IDS_UNREGISTRATION_COMPLETED).c_str(), L"EdgeWindowTabManagerBlock", MB_ICONINFORMATION); 268 | return 0; 269 | } 270 | 271 | int WINAPI wWinMain(HINSTANCE, HINSTANCE, LPWSTR lpCmdLine, int nShowCmd) 272 | { 273 | WCHAR szEdgePath[MAX_PATH] = { 0 }; 274 | DWORD cb = sizeof szEdgePath; 275 | 276 | // The first parameter can be a msedge.exe path. Check whether it is or not 277 | 278 | bool edgePathInCmdLine = false; 279 | bool ifeoDebug = false; 280 | LPWSTR lpRemainCmdLine = PathGetArgsW(lpCmdLine); // points to the 2nd parameter 281 | 282 | wcsncpy_s(szEdgePath, lpCmdLine, lpRemainCmdLine - lpCmdLine); // copy the first parameter 283 | PathRemoveBlanksW(szEdgePath); 284 | PathUnquoteSpacesW(szEdgePath); 285 | 286 | if (StrCmpIW(szEdgePath, L"--install-ifeo-debugger") == 0) 287 | { 288 | return DoInstall(); 289 | } 290 | else if (StrCmpIW(szEdgePath, L"--uninstall-ifeo-debugger") == 0) 291 | { 292 | return DoUninstall(); 293 | } 294 | else if (StrCmpIW(szEdgePath, L"--ifeo-debug") == 0) 295 | { 296 | ifeoDebug = true; 297 | // shifts all arguments 298 | lpCmdLine = lpRemainCmdLine; 299 | lpRemainCmdLine = PathGetArgsW(lpCmdLine); 300 | wcsncpy_s(szEdgePath, lpCmdLine, lpRemainCmdLine - lpCmdLine); 301 | PathRemoveBlanksW(szEdgePath); 302 | PathUnquoteSpacesW(szEdgePath); 303 | } 304 | 305 | // Check if the first parameter is a path to msedge.exe 306 | if (StrCmpIW(PathFindFileNameW(szEdgePath), L"msedge.exe") == 0) 307 | { 308 | lpCmdLine = lpRemainCmdLine; 309 | edgePathInCmdLine = true; 310 | } 311 | 312 | bool ctrlDown = false; 313 | if (!ifeoDebug && (GetAsyncKeyState(VK_CONTROL) & 0x8000)) // check CTRL key state only when launched directly 314 | { 315 | Sleep(1000); // if CTRL pressed now, wait for a second to test again 316 | if (GetAsyncKeyState(VK_CONTROL) & 0x8000) 317 | ctrlDown = true; 318 | } 319 | 320 | if (!edgePathInCmdLine) 321 | { 322 | // try to fetch Edge path from the registry 323 | std::wstring edgePath; 324 | 325 | if (!ctrlDown) 326 | edgePath = GetEdgePath(); // if CTRL not pressed, fetch Edge path from the registry 327 | 328 | while (edgePath.empty()) // loop until a valid path is selected 329 | { 330 | if (!ShowChooseEdgeVersionDlg()) 331 | return HRESULT_FROM_WIN32(ERROR_CANCELLED); // quit on dialog cancellation 332 | edgePath = GetEdgePath(); 333 | } 334 | wcscpy_s(szEdgePath, edgePath.c_str()); 335 | } 336 | 337 | LSTATUS err; 338 | WORD wEdgeBinaryType = GetExecutableMachineType(szEdgePath); 339 | if (wEdgeBinaryType == 0) 340 | { 341 | err = GetLastError(); 342 | ReportError(IDS_GET_EDGE_BIN_TYPE_FAILED, err); 343 | return HRESULT_FROM_WIN32(err); 344 | } 345 | 346 | char szDllPath[MAX_PATH]; 347 | GetModuleFileNameA(NULL, szDllPath, MAX_PATH); 348 | PathRemoveFileSpecA(szDllPath); 349 | PathAppendA(szDllPath, "EdgeWindowTabManagerBlockDll.dll"); 350 | 351 | WORD wDllBinaryType = GetExecutableMachineType(szDllPath); 352 | if (wDllBinaryType == 0) 353 | { 354 | err = GetLastError(); 355 | if (err == ERROR_FILE_NOT_FOUND) 356 | ReportError(IDS_DLL_NOT_FOUND); 357 | else 358 | ReportError(IDS_GET_DLL_BIN_TYPE_FAILED, err); 359 | return HRESULT_FROM_WIN32(err); 360 | } 361 | if (wEdgeBinaryType != wDllBinaryType) 362 | { 363 | if (wEdgeBinaryType == IMAGE_FILE_MACHINE_AMD64) 364 | ReportError(IDS_EDGE_64BIT_NOT_MATCH); 365 | else if (wEdgeBinaryType == IMAGE_FILE_MACHINE_I386) 366 | ReportError(IDS_EDGE_32BIT_NOT_MATCH); 367 | else if (wEdgeBinaryType == IMAGE_FILE_MACHINE_ARM64) 368 | ReportError(IDS_EDGE_ARM64_NOT_MATCH); 369 | else 370 | ReportError(IDS_EDGE_UNKNOWN_BIN_TYPE); 371 | return HRESULT_FROM_WIN32(ERROR_BAD_EXE_FORMAT); 372 | } 373 | 374 | // Show install debugger dialog after checking bitness 375 | if (!ifeoDebug && !ShowInstallDebuggerDlg(ctrlDown)) 376 | return 0; 377 | 378 | if (FindEdgeProcessWithWindowTabManager() != 0) 379 | { 380 | std::wstring msg = LoadResString(IDS_EDGE_WITH_WTM_RUNNING); 381 | do 382 | { 383 | int ret = MessageBoxW(NULL, msg.c_str(), L"EdgeWindowTabManagerBlock", MB_CANCELTRYCONTINUE + MB_ICONEXCLAMATION); 384 | if (ret == IDCANCEL) 385 | return HRESULT_FROM_WIN32(ERROR_CANCELLED); 386 | else if (ret == IDCONTINUE) 387 | break; 388 | } while (FindEdgeProcessWithWindowTabManager() != 0); 389 | } 390 | 391 | LPWSTR cmdLine = new WCHAR[8192](); 392 | swprintf_s(cmdLine, 8192, L"\"%s\" %s", szEdgePath, lpCmdLine); 393 | 394 | STARTUPINFOW si = { sizeof si }; 395 | GetStartupInfoW(&si); 396 | si.lpTitle = nullptr; 397 | si.lpReserved = nullptr; 398 | si.cbReserved2 = 0; 399 | si.lpReserved2 = 0; 400 | PROCESS_INFORMATION pi; 401 | 402 | if (!DetourCreateProcessWithDllW(szEdgePath, cmdLine, NULL, NULL, TRUE, 403 | DEBUG_ONLY_THIS_PROCESS, // avoid recursively launching itself when set as the IFEO debugger of msedge 404 | NULL, NULL, &si, &pi, 405 | szDllPath, NULL)) 406 | { 407 | err = GetLastError(); 408 | delete[] cmdLine; 409 | ReportError(IDS_INJECT_DLL_FAILED, err); 410 | return HRESULT_FROM_WIN32(err); 411 | } 412 | 413 | delete[] cmdLine; 414 | 415 | // we don't want to actually debug, so detach it immediately 416 | DebugActiveProcessStop(pi.dwProcessId); 417 | 418 | CloseHandle(pi.hThread); 419 | CloseHandle(pi.hProcess); 420 | 421 | return 0; 422 | } -------------------------------------------------------------------------------- /EdgeWindowTabManagerBlock/EdgeWindowTabManagerBlock.vcxproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Debug 6 | ARM64 7 | 8 | 9 | Debug 10 | Win32 11 | 12 | 13 | Release 14 | ARM64 15 | 16 | 17 | Release 18 | Win32 19 | 20 | 21 | Debug 22 | x64 23 | 24 | 25 | Release 26 | x64 27 | 28 | 29 | 30 | 17.0 31 | Win32Proj 32 | {a9e30655-51d2-451d-87e0-806f092dd47b} 33 | EdgeWindowTabManagerBlock 34 | 10.0 35 | 36 | 37 | 38 | Application 39 | true 40 | v143 41 | Unicode 42 | 43 | 44 | Application 45 | false 46 | v143 47 | true 48 | Unicode 49 | 50 | 51 | Application 52 | true 53 | v143 54 | Unicode 55 | 56 | 57 | Application 58 | true 59 | v143 60 | Unicode 61 | 62 | 63 | Application 64 | false 65 | v143 66 | true 67 | Unicode 68 | 69 | 70 | Application 71 | false 72 | v143 73 | true 74 | Unicode 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | $(SolutionDir)detours\include;$(ExternalIncludePath) 102 | $(SolutionDir)detours\lib.$(LibrariesArchitecture);$(LibraryPath) 103 | 104 | 105 | $(SolutionDir)detours\include;$(ExternalIncludePath) 106 | $(SolutionDir)detours\lib.$(LibrariesArchitecture);$(LibraryPath) 107 | 108 | 109 | $(SolutionDir)detours\include;$(ExternalIncludePath) 110 | $(SolutionDir)detours\lib.$(LibrariesArchitecture);$(LibraryPath) 111 | 112 | 113 | $(SolutionDir)detours\include;$(ExternalIncludePath) 114 | $(SolutionDir)detours\lib.$(LibrariesArchitecture);$(LibraryPath) 115 | 116 | 117 | $(SolutionDir)detours\include;$(ExternalIncludePath) 118 | $(SolutionDir)detours\lib.$(LibrariesArchitecture);$(LibraryPath) 119 | 120 | 121 | $(SolutionDir)detours\include;$(ExternalIncludePath) 122 | $(SolutionDir)detours\lib.$(LibrariesArchitecture);$(LibraryPath) 123 | 124 | 125 | 126 | Level3 127 | true 128 | WIN32;_DEBUG;_WINDOWS;%(PreprocessorDefinitions) 129 | true 130 | MultiThreadedDebug 131 | 132 | 133 | Windows 134 | true 135 | /PDBALTPATH:%_PDB% %(AdditionalOptions) 136 | detours.lib;%(AdditionalDependencies) 137 | 138 | 139 | true 140 | 141 | 142 | 143 | 144 | Level3 145 | true 146 | true 147 | true 148 | WIN32;NDEBUG;_WINDOWS;%(PreprocessorDefinitions) 149 | true 150 | MultiThreaded 151 | 152 | 153 | Windows 154 | true 155 | true 156 | true 157 | /PDBALTPATH:%_PDB% %(AdditionalOptions) 158 | detours.lib;%(AdditionalDependencies) 159 | 160 | 161 | true 162 | 163 | 164 | 165 | 166 | Level3 167 | true 168 | _DEBUG;_WINDOWS;%(PreprocessorDefinitions) 169 | true 170 | MultiThreadedDebug 171 | 172 | 173 | Windows 174 | true 175 | /PDBALTPATH:%_PDB% %(AdditionalOptions) 176 | detours.lib;%(AdditionalDependencies) 177 | 178 | 179 | true 180 | 181 | 182 | 183 | 184 | Level3 185 | true 186 | _DEBUG;_WINDOWS;%(PreprocessorDefinitions) 187 | true 188 | MultiThreadedDebug 189 | 190 | 191 | Windows 192 | true 193 | /PDBALTPATH:%_PDB% %(AdditionalOptions) 194 | detours.lib;%(AdditionalDependencies) 195 | 196 | 197 | true 198 | 199 | 200 | 201 | 202 | Level3 203 | true 204 | true 205 | true 206 | NDEBUG;_WINDOWS;%(PreprocessorDefinitions) 207 | true 208 | MultiThreaded 209 | 210 | 211 | Windows 212 | true 213 | true 214 | true 215 | /PDBALTPATH:%_PDB% %(AdditionalOptions) 216 | detours.lib;%(AdditionalDependencies) 217 | 218 | 219 | true 220 | 221 | 222 | 223 | 224 | Level3 225 | true 226 | true 227 | true 228 | NDEBUG;_WINDOWS;%(PreprocessorDefinitions) 229 | true 230 | MultiThreaded 231 | 232 | 233 | Windows 234 | true 235 | true 236 | true 237 | /PDBALTPATH:%_PDB% %(AdditionalOptions) 238 | detours.lib;%(AdditionalDependencies) 239 | 240 | 241 | true 242 | 243 | 244 | 245 | 246 | 247 | 248 | 249 | 250 | 251 | 252 | 253 | 254 | {73f5f261-6380-4565-a8a9-c2e3863a75b0} 255 | 256 | 257 | 258 | 259 | 260 | 261 | 262 | 263 | 264 | 265 | 266 | 267 | 268 | 269 | This project references NuGet package(s) that are missing on this computer. Use NuGet Package Restore to download them. The missing file is {name}. 270 | 271 | 272 | 273 | -------------------------------------------------------------------------------- /detours/include/detours.h: -------------------------------------------------------------------------------- 1 | ///////////////////////////////////////////////////////////////////////////// 2 | // 3 | // Core Detours Functionality (detours.h of detours.lib) 4 | // 5 | // Microsoft Research Detours Package, Version 4.0.1 6 | // 7 | // Copyright (c) Microsoft Corporation. All rights reserved. 8 | // 9 | 10 | #pragma once 11 | #ifndef _DETOURS_H_ 12 | #define _DETOURS_H_ 13 | 14 | #define DETOURS_VERSION 0x4c0c1 // 0xMAJORcMINORcPATCH 15 | 16 | ////////////////////////////////////////////////////////////////////////////// 17 | // 18 | 19 | #ifdef DETOURS_INTERNAL 20 | 21 | #define _CRT_STDIO_ARBITRARY_WIDE_SPECIFIERS 1 22 | #define _ARM_WINAPI_PARTITION_DESKTOP_SDK_AVAILABLE 1 23 | 24 | #pragma warning(disable:4068) // unknown pragma (suppress) 25 | 26 | #if _MSC_VER >= 1900 27 | #pragma warning(push) 28 | #pragma warning(disable:4091) // empty typedef 29 | #endif 30 | 31 | // Suppress declspec(dllimport) for the sake of Detours 32 | // users that provide kernel32 functionality themselves. 33 | // This is ok in the mainstream case, it will just cost 34 | // an extra instruction calling some functions, which 35 | // LTCG optimizes away. 36 | // 37 | #define _KERNEL32_ 1 38 | #define _USER32_ 1 39 | 40 | #include 41 | #if (_MSC_VER < 1310) 42 | #else 43 | #pragma warning(push) 44 | #if _MSC_VER > 1400 45 | #pragma warning(disable:6102 6103) // /analyze warnings 46 | #endif 47 | #include 48 | #include 49 | #pragma warning(pop) 50 | #endif 51 | #include 52 | 53 | // Allow Detours to cleanly compile with the MingW toolchain. 54 | // 55 | #ifdef __GNUC__ 56 | #define __try 57 | #define __except(x) if (0) 58 | #include 59 | #include 60 | #endif 61 | 62 | // From winerror.h, as this error isn't found in some SDKs: 63 | // 64 | // MessageId: ERROR_DYNAMIC_CODE_BLOCKED 65 | // 66 | // MessageText: 67 | // 68 | // The operation was blocked as the process prohibits dynamic code generation. 69 | // 70 | #define ERROR_DYNAMIC_CODE_BLOCKED 1655L 71 | 72 | #endif // DETOURS_INTERNAL 73 | 74 | ////////////////////////////////////////////////////////////////////////////// 75 | // 76 | 77 | #undef DETOURS_X64 78 | #undef DETOURS_X86 79 | #undef DETOURS_IA64 80 | #undef DETOURS_ARM 81 | #undef DETOURS_ARM64 82 | #undef DETOURS_BITS 83 | #undef DETOURS_32BIT 84 | #undef DETOURS_64BIT 85 | 86 | #if defined(_X86_) 87 | #define DETOURS_X86 88 | #define DETOURS_OPTION_BITS 64 89 | 90 | #elif defined(_AMD64_) 91 | #define DETOURS_X64 92 | #define DETOURS_OPTION_BITS 32 93 | 94 | #elif defined(_IA64_) 95 | #define DETOURS_IA64 96 | #define DETOURS_OPTION_BITS 32 97 | 98 | #elif defined(_ARM_) 99 | #define DETOURS_ARM 100 | 101 | #elif defined(_ARM64_) 102 | #define DETOURS_ARM64 103 | 104 | #else 105 | #error Unknown architecture (x86, amd64, ia64, arm, arm64) 106 | #endif 107 | 108 | #ifdef _WIN64 109 | #undef DETOURS_32BIT 110 | #define DETOURS_64BIT 1 111 | #define DETOURS_BITS 64 112 | // If all 64bit kernels can run one and only one 32bit architecture. 113 | //#define DETOURS_OPTION_BITS 32 114 | #else 115 | #define DETOURS_32BIT 1 116 | #undef DETOURS_64BIT 117 | #define DETOURS_BITS 32 118 | // If all 64bit kernels can run one and only one 32bit architecture. 119 | //#define DETOURS_OPTION_BITS 32 120 | #endif 121 | 122 | /////////////////////////////////////////////////////////////// Helper Macros. 123 | // 124 | #define DETOURS_STRINGIFY_(x) #x 125 | #define DETOURS_STRINGIFY(x) DETOURS_STRINGIFY_(x) 126 | 127 | #define VER_DETOURS_BITS DETOURS_STRINGIFY(DETOURS_BITS) 128 | 129 | ////////////////////////////////////////////////////////////////////////////// 130 | // 131 | 132 | #if (_MSC_VER < 1299) && !defined(__MINGW32__) 133 | typedef LONG LONG_PTR; 134 | typedef ULONG ULONG_PTR; 135 | #endif 136 | 137 | ///////////////////////////////////////////////// SAL 2.0 Annotations w/o SAL. 138 | // 139 | // These definitions are include so that Detours will build even if the 140 | // compiler doesn't have full SAL 2.0 support. 141 | // 142 | #ifndef DETOURS_DONT_REMOVE_SAL_20 143 | 144 | #ifdef DETOURS_TEST_REMOVE_SAL_20 145 | #undef _Analysis_assume_ 146 | #undef _Benign_race_begin_ 147 | #undef _Benign_race_end_ 148 | #undef _Field_range_ 149 | #undef _Field_size_ 150 | #undef _In_ 151 | #undef _In_bytecount_ 152 | #undef _In_count_ 153 | #undef __in_ecount 154 | #undef _In_opt_ 155 | #undef _In_opt_bytecount_ 156 | #undef _In_opt_count_ 157 | #undef _In_opt_z_ 158 | #undef _In_range_ 159 | #undef _In_reads_ 160 | #undef _In_reads_bytes_ 161 | #undef _In_reads_opt_ 162 | #undef _In_reads_opt_bytes_ 163 | #undef _In_reads_or_z_ 164 | #undef _In_z_ 165 | #undef _Inout_ 166 | #undef _Inout_opt_ 167 | #undef _Inout_z_count_ 168 | #undef _Out_ 169 | #undef _Out_opt_ 170 | #undef _Out_writes_ 171 | #undef _Outptr_result_maybenull_ 172 | #undef _Readable_bytes_ 173 | #undef _Success_ 174 | #undef _Writable_bytes_ 175 | #undef _Pre_notnull_ 176 | #endif 177 | 178 | #if defined(_Deref_out_opt_z_) && !defined(_Outptr_result_maybenull_) 179 | #define _Outptr_result_maybenull_ _Deref_out_opt_z_ 180 | #endif 181 | 182 | #if defined(_In_count_) && !defined(_In_reads_) 183 | #define _In_reads_(x) _In_count_(x) 184 | #endif 185 | 186 | #if defined(_In_opt_count_) && !defined(_In_reads_opt_) 187 | #define _In_reads_opt_(x) _In_opt_count_(x) 188 | #endif 189 | 190 | #if defined(_In_opt_bytecount_) && !defined(_In_reads_opt_bytes_) 191 | #define _In_reads_opt_bytes_(x) _In_opt_bytecount_(x) 192 | #endif 193 | 194 | #if defined(_In_bytecount_) && !defined(_In_reads_bytes_) 195 | #define _In_reads_bytes_(x) _In_bytecount_(x) 196 | #endif 197 | 198 | #ifndef _In_ 199 | #define _In_ 200 | #endif 201 | 202 | #ifndef _In_bytecount_ 203 | #define _In_bytecount_(x) 204 | #endif 205 | 206 | #ifndef _In_count_ 207 | #define _In_count_(x) 208 | #endif 209 | 210 | #ifndef __in_ecount 211 | #define __in_ecount(x) 212 | #endif 213 | 214 | #ifndef _In_opt_ 215 | #define _In_opt_ 216 | #endif 217 | 218 | #ifndef _In_opt_bytecount_ 219 | #define _In_opt_bytecount_(x) 220 | #endif 221 | 222 | #ifndef _In_opt_count_ 223 | #define _In_opt_count_(x) 224 | #endif 225 | 226 | #ifndef _In_opt_z_ 227 | #define _In_opt_z_ 228 | #endif 229 | 230 | #ifndef _In_range_ 231 | #define _In_range_(x,y) 232 | #endif 233 | 234 | #ifndef _In_reads_ 235 | #define _In_reads_(x) 236 | #endif 237 | 238 | #ifndef _In_reads_bytes_ 239 | #define _In_reads_bytes_(x) 240 | #endif 241 | 242 | #ifndef _In_reads_opt_ 243 | #define _In_reads_opt_(x) 244 | #endif 245 | 246 | #ifndef _In_reads_opt_bytes_ 247 | #define _In_reads_opt_bytes_(x) 248 | #endif 249 | 250 | #ifndef _In_reads_or_z_ 251 | #define _In_reads_or_z_ 252 | #endif 253 | 254 | #ifndef _In_z_ 255 | #define _In_z_ 256 | #endif 257 | 258 | #ifndef _Inout_ 259 | #define _Inout_ 260 | #endif 261 | 262 | #ifndef _Inout_opt_ 263 | #define _Inout_opt_ 264 | #endif 265 | 266 | #ifndef _Inout_z_count_ 267 | #define _Inout_z_count_(x) 268 | #endif 269 | 270 | #ifndef _Out_ 271 | #define _Out_ 272 | #endif 273 | 274 | #ifndef _Out_opt_ 275 | #define _Out_opt_ 276 | #endif 277 | 278 | #ifndef _Out_writes_ 279 | #define _Out_writes_(x) 280 | #endif 281 | 282 | #ifndef _Outptr_result_maybenull_ 283 | #define _Outptr_result_maybenull_ 284 | #endif 285 | 286 | #ifndef _Writable_bytes_ 287 | #define _Writable_bytes_(x) 288 | #endif 289 | 290 | #ifndef _Readable_bytes_ 291 | #define _Readable_bytes_(x) 292 | #endif 293 | 294 | #ifndef _Success_ 295 | #define _Success_(x) 296 | #endif 297 | 298 | #ifndef _Pre_notnull_ 299 | #define _Pre_notnull_ 300 | #endif 301 | 302 | #ifdef DETOURS_INTERNAL 303 | 304 | #pragma warning(disable:4615) // unknown warning type (suppress with older compilers) 305 | 306 | #ifndef _Benign_race_begin_ 307 | #define _Benign_race_begin_ 308 | #endif 309 | 310 | #ifndef _Benign_race_end_ 311 | #define _Benign_race_end_ 312 | #endif 313 | 314 | #ifndef _Field_size_ 315 | #define _Field_size_(x) 316 | #endif 317 | 318 | #ifndef _Field_range_ 319 | #define _Field_range_(x,y) 320 | #endif 321 | 322 | #ifndef _Analysis_assume_ 323 | #define _Analysis_assume_(x) 324 | #endif 325 | 326 | #endif // DETOURS_INTERNAL 327 | #endif // DETOURS_DONT_REMOVE_SAL_20 328 | 329 | ////////////////////////////////////////////////////////////////////////////// 330 | // 331 | #ifndef GUID_DEFINED 332 | #define GUID_DEFINED 333 | typedef struct _GUID 334 | { 335 | DWORD Data1; 336 | WORD Data2; 337 | WORD Data3; 338 | BYTE Data4[ 8 ]; 339 | } GUID; 340 | 341 | #ifdef INITGUID 342 | #define DEFINE_GUID(name, l, w1, w2, b1, b2, b3, b4, b5, b6, b7, b8) \ 343 | const GUID name \ 344 | = { l, w1, w2, { b1, b2, b3, b4, b5, b6, b7, b8 } } 345 | #else 346 | #define DEFINE_GUID(name, l, w1, w2, b1, b2, b3, b4, b5, b6, b7, b8) \ 347 | const GUID name 348 | #endif // INITGUID 349 | #endif // !GUID_DEFINED 350 | 351 | #if defined(__cplusplus) 352 | #ifndef _REFGUID_DEFINED 353 | #define _REFGUID_DEFINED 354 | #define REFGUID const GUID & 355 | #endif // !_REFGUID_DEFINED 356 | #else // !__cplusplus 357 | #ifndef _REFGUID_DEFINED 358 | #define _REFGUID_DEFINED 359 | #define REFGUID const GUID * const 360 | #endif // !_REFGUID_DEFINED 361 | #endif // !__cplusplus 362 | 363 | #ifndef ARRAYSIZE 364 | #define ARRAYSIZE(x) (sizeof(x)/sizeof(x[0])) 365 | #endif 366 | 367 | // 368 | ////////////////////////////////////////////////////////////////////////////// 369 | 370 | #ifdef __cplusplus 371 | extern "C" { 372 | #endif // __cplusplus 373 | 374 | /////////////////////////////////////////////////// Instruction Target Macros. 375 | // 376 | #define DETOUR_INSTRUCTION_TARGET_NONE ((PVOID)0) 377 | #define DETOUR_INSTRUCTION_TARGET_DYNAMIC ((PVOID)(LONG_PTR)-1) 378 | #define DETOUR_SECTION_HEADER_SIGNATURE 0x00727444 // "Dtr\0" 379 | 380 | extern const GUID DETOUR_EXE_RESTORE_GUID; 381 | extern const GUID DETOUR_EXE_HELPER_GUID; 382 | 383 | #define DETOUR_TRAMPOLINE_SIGNATURE 0x21727444 // Dtr! 384 | typedef struct _DETOUR_TRAMPOLINE DETOUR_TRAMPOLINE, *PDETOUR_TRAMPOLINE; 385 | 386 | #ifndef DETOUR_MAX_SUPPORTED_IMAGE_SECTION_HEADERS 387 | #define DETOUR_MAX_SUPPORTED_IMAGE_SECTION_HEADERS 32 388 | #endif // !DETOUR_MAX_SUPPORTED_IMAGE_SECTION_HEADERS 389 | 390 | /////////////////////////////////////////////////////////// Binary Structures. 391 | // 392 | #pragma pack(push, 8) 393 | typedef struct _DETOUR_SECTION_HEADER 394 | { 395 | DWORD cbHeaderSize; 396 | DWORD nSignature; 397 | DWORD nDataOffset; 398 | DWORD cbDataSize; 399 | 400 | DWORD nOriginalImportVirtualAddress; 401 | DWORD nOriginalImportSize; 402 | DWORD nOriginalBoundImportVirtualAddress; 403 | DWORD nOriginalBoundImportSize; 404 | 405 | DWORD nOriginalIatVirtualAddress; 406 | DWORD nOriginalIatSize; 407 | DWORD nOriginalSizeOfImage; 408 | DWORD cbPrePE; 409 | 410 | DWORD nOriginalClrFlags; 411 | DWORD reserved1; 412 | DWORD reserved2; 413 | DWORD reserved3; 414 | 415 | // Followed by cbPrePE bytes of data. 416 | } DETOUR_SECTION_HEADER, *PDETOUR_SECTION_HEADER; 417 | 418 | typedef struct _DETOUR_SECTION_RECORD 419 | { 420 | DWORD cbBytes; 421 | DWORD nReserved; 422 | GUID guid; 423 | } DETOUR_SECTION_RECORD, *PDETOUR_SECTION_RECORD; 424 | 425 | typedef struct _DETOUR_CLR_HEADER 426 | { 427 | // Header versioning 428 | ULONG cb; 429 | USHORT MajorRuntimeVersion; 430 | USHORT MinorRuntimeVersion; 431 | 432 | // Symbol table and startup information 433 | IMAGE_DATA_DIRECTORY MetaData; 434 | ULONG Flags; 435 | 436 | // Followed by the rest of the IMAGE_COR20_HEADER 437 | } DETOUR_CLR_HEADER, *PDETOUR_CLR_HEADER; 438 | 439 | typedef struct _DETOUR_EXE_RESTORE 440 | { 441 | DWORD cb; 442 | DWORD cbidh; 443 | DWORD cbinh; 444 | DWORD cbclr; 445 | 446 | PBYTE pidh; 447 | PBYTE pinh; 448 | PBYTE pclr; 449 | 450 | IMAGE_DOS_HEADER idh; 451 | union { 452 | IMAGE_NT_HEADERS inh; // all environments have this 453 | #ifdef IMAGE_NT_OPTIONAL_HDR32_MAGIC // some environments do not have this 454 | IMAGE_NT_HEADERS32 inh32; 455 | #endif 456 | #ifdef IMAGE_NT_OPTIONAL_HDR64_MAGIC // some environments do not have this 457 | IMAGE_NT_HEADERS64 inh64; 458 | #endif 459 | #ifdef IMAGE_NT_OPTIONAL_HDR64_MAGIC // some environments do not have this 460 | BYTE raw[sizeof(IMAGE_NT_HEADERS64) + 461 | sizeof(IMAGE_SECTION_HEADER) * DETOUR_MAX_SUPPORTED_IMAGE_SECTION_HEADERS]; 462 | #else 463 | BYTE raw[0x108 + sizeof(IMAGE_SECTION_HEADER) * DETOUR_MAX_SUPPORTED_IMAGE_SECTION_HEADERS]; 464 | #endif 465 | }; 466 | DETOUR_CLR_HEADER clr; 467 | 468 | } DETOUR_EXE_RESTORE, *PDETOUR_EXE_RESTORE; 469 | 470 | #ifdef IMAGE_NT_OPTIONAL_HDR64_MAGIC 471 | C_ASSERT(sizeof(IMAGE_NT_HEADERS64) == 0x108); 472 | #endif 473 | 474 | // The size can change, but assert for clarity due to the muddying #ifdefs. 475 | #ifdef _WIN64 476 | C_ASSERT(sizeof(DETOUR_EXE_RESTORE) == 0x688); 477 | #else 478 | C_ASSERT(sizeof(DETOUR_EXE_RESTORE) == 0x678); 479 | #endif 480 | 481 | typedef struct _DETOUR_EXE_HELPER 482 | { 483 | DWORD cb; 484 | DWORD pid; 485 | DWORD nDlls; 486 | CHAR rDlls[4]; 487 | } DETOUR_EXE_HELPER, *PDETOUR_EXE_HELPER; 488 | 489 | #pragma pack(pop) 490 | 491 | #define DETOUR_SECTION_HEADER_DECLARE(cbSectionSize) \ 492 | { \ 493 | sizeof(DETOUR_SECTION_HEADER),\ 494 | DETOUR_SECTION_HEADER_SIGNATURE,\ 495 | sizeof(DETOUR_SECTION_HEADER),\ 496 | (cbSectionSize),\ 497 | \ 498 | 0,\ 499 | 0,\ 500 | 0,\ 501 | 0,\ 502 | \ 503 | 0,\ 504 | 0,\ 505 | 0,\ 506 | 0,\ 507 | } 508 | 509 | ///////////////////////////////////////////////////////////// Binary Typedefs. 510 | // 511 | typedef BOOL (CALLBACK *PF_DETOUR_BINARY_BYWAY_CALLBACK)( 512 | _In_opt_ PVOID pContext, 513 | _In_opt_ LPCSTR pszFile, 514 | _Outptr_result_maybenull_ LPCSTR *ppszOutFile); 515 | 516 | typedef BOOL (CALLBACK *PF_DETOUR_BINARY_FILE_CALLBACK)( 517 | _In_opt_ PVOID pContext, 518 | _In_ LPCSTR pszOrigFile, 519 | _In_ LPCSTR pszFile, 520 | _Outptr_result_maybenull_ LPCSTR *ppszOutFile); 521 | 522 | typedef BOOL (CALLBACK *PF_DETOUR_BINARY_SYMBOL_CALLBACK)( 523 | _In_opt_ PVOID pContext, 524 | _In_ ULONG nOrigOrdinal, 525 | _In_ ULONG nOrdinal, 526 | _Out_ ULONG *pnOutOrdinal, 527 | _In_opt_ LPCSTR pszOrigSymbol, 528 | _In_opt_ LPCSTR pszSymbol, 529 | _Outptr_result_maybenull_ LPCSTR *ppszOutSymbol); 530 | 531 | typedef BOOL (CALLBACK *PF_DETOUR_BINARY_COMMIT_CALLBACK)( 532 | _In_opt_ PVOID pContext); 533 | 534 | typedef BOOL (CALLBACK *PF_DETOUR_ENUMERATE_EXPORT_CALLBACK)(_In_opt_ PVOID pContext, 535 | _In_ ULONG nOrdinal, 536 | _In_opt_ LPCSTR pszName, 537 | _In_opt_ PVOID pCode); 538 | 539 | typedef BOOL (CALLBACK *PF_DETOUR_IMPORT_FILE_CALLBACK)(_In_opt_ PVOID pContext, 540 | _In_opt_ HMODULE hModule, 541 | _In_opt_ LPCSTR pszFile); 542 | 543 | typedef BOOL (CALLBACK *PF_DETOUR_IMPORT_FUNC_CALLBACK)(_In_opt_ PVOID pContext, 544 | _In_ DWORD nOrdinal, 545 | _In_opt_ LPCSTR pszFunc, 546 | _In_opt_ PVOID pvFunc); 547 | 548 | // Same as PF_DETOUR_IMPORT_FUNC_CALLBACK but extra indirection on last parameter. 549 | typedef BOOL (CALLBACK *PF_DETOUR_IMPORT_FUNC_CALLBACK_EX)(_In_opt_ PVOID pContext, 550 | _In_ DWORD nOrdinal, 551 | _In_opt_ LPCSTR pszFunc, 552 | _In_opt_ PVOID* ppvFunc); 553 | 554 | typedef VOID * PDETOUR_BINARY; 555 | typedef VOID * PDETOUR_LOADED_BINARY; 556 | 557 | //////////////////////////////////////////////////////////// Transaction APIs. 558 | // 559 | LONG WINAPI DetourTransactionBegin(VOID); 560 | LONG WINAPI DetourTransactionAbort(VOID); 561 | LONG WINAPI DetourTransactionCommit(VOID); 562 | LONG WINAPI DetourTransactionCommitEx(_Out_opt_ PVOID **pppFailedPointer); 563 | 564 | LONG WINAPI DetourUpdateThread(_In_ HANDLE hThread); 565 | 566 | LONG WINAPI DetourAttach(_Inout_ PVOID *ppPointer, 567 | _In_ PVOID pDetour); 568 | 569 | LONG WINAPI DetourAttachEx(_Inout_ PVOID *ppPointer, 570 | _In_ PVOID pDetour, 571 | _Out_opt_ PDETOUR_TRAMPOLINE *ppRealTrampoline, 572 | _Out_opt_ PVOID *ppRealTarget, 573 | _Out_opt_ PVOID *ppRealDetour); 574 | 575 | LONG WINAPI DetourDetach(_Inout_ PVOID *ppPointer, 576 | _In_ PVOID pDetour); 577 | 578 | BOOL WINAPI DetourSetIgnoreTooSmall(_In_ BOOL fIgnore); 579 | BOOL WINAPI DetourSetRetainRegions(_In_ BOOL fRetain); 580 | PVOID WINAPI DetourSetSystemRegionLowerBound(_In_ PVOID pSystemRegionLowerBound); 581 | PVOID WINAPI DetourSetSystemRegionUpperBound(_In_ PVOID pSystemRegionUpperBound); 582 | 583 | ////////////////////////////////////////////////////////////// Code Functions. 584 | // 585 | PVOID WINAPI DetourFindFunction(_In_ LPCSTR pszModule, 586 | _In_ LPCSTR pszFunction); 587 | PVOID WINAPI DetourCodeFromPointer(_In_ PVOID pPointer, 588 | _Out_opt_ PVOID *ppGlobals); 589 | PVOID WINAPI DetourCopyInstruction(_In_opt_ PVOID pDst, 590 | _Inout_opt_ PVOID *ppDstPool, 591 | _In_ PVOID pSrc, 592 | _Out_opt_ PVOID *ppTarget, 593 | _Out_opt_ LONG *plExtra); 594 | BOOL WINAPI DetourSetCodeModule(_In_ HMODULE hModule, 595 | _In_ BOOL fLimitReferencesToModule); 596 | PVOID WINAPI DetourAllocateRegionWithinJumpBounds(_In_ LPCVOID pbTarget, 597 | _Out_ PDWORD pcbAllocatedSize); 598 | BOOL WINAPI DetourIsFunctionImported(_In_ PBYTE pbCode, 599 | _In_ PBYTE pbAddress); 600 | 601 | ///////////////////////////////////////////////////// Loaded Binary Functions. 602 | // 603 | HMODULE WINAPI DetourGetContainingModule(_In_ PVOID pvAddr); 604 | HMODULE WINAPI DetourEnumerateModules(_In_opt_ HMODULE hModuleLast); 605 | PVOID WINAPI DetourGetEntryPoint(_In_opt_ HMODULE hModule); 606 | ULONG WINAPI DetourGetModuleSize(_In_opt_ HMODULE hModule); 607 | BOOL WINAPI DetourEnumerateExports(_In_ HMODULE hModule, 608 | _In_opt_ PVOID pContext, 609 | _In_ PF_DETOUR_ENUMERATE_EXPORT_CALLBACK pfExport); 610 | BOOL WINAPI DetourEnumerateImports(_In_opt_ HMODULE hModule, 611 | _In_opt_ PVOID pContext, 612 | _In_opt_ PF_DETOUR_IMPORT_FILE_CALLBACK pfImportFile, 613 | _In_opt_ PF_DETOUR_IMPORT_FUNC_CALLBACK pfImportFunc); 614 | 615 | BOOL WINAPI DetourEnumerateImportsEx(_In_opt_ HMODULE hModule, 616 | _In_opt_ PVOID pContext, 617 | _In_opt_ PF_DETOUR_IMPORT_FILE_CALLBACK pfImportFile, 618 | _In_opt_ PF_DETOUR_IMPORT_FUNC_CALLBACK_EX pfImportFuncEx); 619 | 620 | _Writable_bytes_(*pcbData) 621 | _Readable_bytes_(*pcbData) 622 | _Success_(return != NULL) 623 | PVOID WINAPI DetourFindPayload(_In_opt_ HMODULE hModule, 624 | _In_ REFGUID rguid, 625 | _Out_opt_ DWORD *pcbData); 626 | 627 | _Writable_bytes_(*pcbData) 628 | _Readable_bytes_(*pcbData) 629 | _Success_(return != NULL) 630 | PVOID WINAPI DetourFindPayloadEx(_In_ REFGUID rguid, 631 | _Out_opt_ DWORD *pcbData); 632 | 633 | DWORD WINAPI DetourGetSizeOfPayloads(_In_opt_ HMODULE hModule); 634 | 635 | BOOL WINAPI DetourFreePayload(_In_ PVOID pvData); 636 | ///////////////////////////////////////////////// Persistent Binary Functions. 637 | // 638 | 639 | PDETOUR_BINARY WINAPI DetourBinaryOpen(_In_ HANDLE hFile); 640 | 641 | _Writable_bytes_(*pcbData) 642 | _Readable_bytes_(*pcbData) 643 | _Success_(return != NULL) 644 | PVOID WINAPI DetourBinaryEnumeratePayloads(_In_ PDETOUR_BINARY pBinary, 645 | _Out_opt_ GUID *pGuid, 646 | _Out_ DWORD *pcbData, 647 | _Inout_ DWORD *pnIterator); 648 | 649 | _Writable_bytes_(*pcbData) 650 | _Readable_bytes_(*pcbData) 651 | _Success_(return != NULL) 652 | PVOID WINAPI DetourBinaryFindPayload(_In_ PDETOUR_BINARY pBinary, 653 | _In_ REFGUID rguid, 654 | _Out_ DWORD *pcbData); 655 | 656 | PVOID WINAPI DetourBinarySetPayload(_In_ PDETOUR_BINARY pBinary, 657 | _In_ REFGUID rguid, 658 | _In_reads_opt_(cbData) PVOID pData, 659 | _In_ DWORD cbData); 660 | BOOL WINAPI DetourBinaryDeletePayload(_In_ PDETOUR_BINARY pBinary, _In_ REFGUID rguid); 661 | BOOL WINAPI DetourBinaryPurgePayloads(_In_ PDETOUR_BINARY pBinary); 662 | BOOL WINAPI DetourBinaryResetImports(_In_ PDETOUR_BINARY pBinary); 663 | BOOL WINAPI DetourBinaryEditImports(_In_ PDETOUR_BINARY pBinary, 664 | _In_opt_ PVOID pContext, 665 | _In_opt_ PF_DETOUR_BINARY_BYWAY_CALLBACK pfByway, 666 | _In_opt_ PF_DETOUR_BINARY_FILE_CALLBACK pfFile, 667 | _In_opt_ PF_DETOUR_BINARY_SYMBOL_CALLBACK pfSymbol, 668 | _In_opt_ PF_DETOUR_BINARY_COMMIT_CALLBACK pfCommit); 669 | BOOL WINAPI DetourBinaryWrite(_In_ PDETOUR_BINARY pBinary, _In_ HANDLE hFile); 670 | BOOL WINAPI DetourBinaryClose(_In_ PDETOUR_BINARY pBinary); 671 | 672 | /////////////////////////////////////////////////// Create Process & Load Dll. 673 | // 674 | _Success_(return != NULL) 675 | PVOID WINAPI DetourFindRemotePayload(_In_ HANDLE hProcess, 676 | _In_ REFGUID rguid, 677 | _Out_opt_ DWORD *pcbData); 678 | 679 | typedef BOOL (WINAPI *PDETOUR_CREATE_PROCESS_ROUTINEA)( 680 | _In_opt_ LPCSTR lpApplicationName, 681 | _Inout_opt_ LPSTR lpCommandLine, 682 | _In_opt_ LPSECURITY_ATTRIBUTES lpProcessAttributes, 683 | _In_opt_ LPSECURITY_ATTRIBUTES lpThreadAttributes, 684 | _In_ BOOL bInheritHandles, 685 | _In_ DWORD dwCreationFlags, 686 | _In_opt_ LPVOID lpEnvironment, 687 | _In_opt_ LPCSTR lpCurrentDirectory, 688 | _In_ LPSTARTUPINFOA lpStartupInfo, 689 | _Out_ LPPROCESS_INFORMATION lpProcessInformation); 690 | 691 | typedef BOOL (WINAPI *PDETOUR_CREATE_PROCESS_ROUTINEW)( 692 | _In_opt_ LPCWSTR lpApplicationName, 693 | _Inout_opt_ LPWSTR lpCommandLine, 694 | _In_opt_ LPSECURITY_ATTRIBUTES lpProcessAttributes, 695 | _In_opt_ LPSECURITY_ATTRIBUTES lpThreadAttributes, 696 | _In_ BOOL bInheritHandles, 697 | _In_ DWORD dwCreationFlags, 698 | _In_opt_ LPVOID lpEnvironment, 699 | _In_opt_ LPCWSTR lpCurrentDirectory, 700 | _In_ LPSTARTUPINFOW lpStartupInfo, 701 | _Out_ LPPROCESS_INFORMATION lpProcessInformation); 702 | 703 | BOOL WINAPI DetourCreateProcessWithDllA(_In_opt_ LPCSTR lpApplicationName, 704 | _Inout_opt_ LPSTR lpCommandLine, 705 | _In_opt_ LPSECURITY_ATTRIBUTES lpProcessAttributes, 706 | _In_opt_ LPSECURITY_ATTRIBUTES lpThreadAttributes, 707 | _In_ BOOL bInheritHandles, 708 | _In_ DWORD dwCreationFlags, 709 | _In_opt_ LPVOID lpEnvironment, 710 | _In_opt_ LPCSTR lpCurrentDirectory, 711 | _In_ LPSTARTUPINFOA lpStartupInfo, 712 | _Out_ LPPROCESS_INFORMATION lpProcessInformation, 713 | _In_ LPCSTR lpDllName, 714 | _In_opt_ PDETOUR_CREATE_PROCESS_ROUTINEA pfCreateProcessA); 715 | 716 | BOOL WINAPI DetourCreateProcessWithDllW(_In_opt_ LPCWSTR lpApplicationName, 717 | _Inout_opt_ LPWSTR lpCommandLine, 718 | _In_opt_ LPSECURITY_ATTRIBUTES lpProcessAttributes, 719 | _In_opt_ LPSECURITY_ATTRIBUTES lpThreadAttributes, 720 | _In_ BOOL bInheritHandles, 721 | _In_ DWORD dwCreationFlags, 722 | _In_opt_ LPVOID lpEnvironment, 723 | _In_opt_ LPCWSTR lpCurrentDirectory, 724 | _In_ LPSTARTUPINFOW lpStartupInfo, 725 | _Out_ LPPROCESS_INFORMATION lpProcessInformation, 726 | _In_ LPCSTR lpDllName, 727 | _In_opt_ PDETOUR_CREATE_PROCESS_ROUTINEW pfCreateProcessW); 728 | 729 | #ifdef UNICODE 730 | #define DetourCreateProcessWithDll DetourCreateProcessWithDllW 731 | #define PDETOUR_CREATE_PROCESS_ROUTINE PDETOUR_CREATE_PROCESS_ROUTINEW 732 | #else 733 | #define DetourCreateProcessWithDll DetourCreateProcessWithDllA 734 | #define PDETOUR_CREATE_PROCESS_ROUTINE PDETOUR_CREATE_PROCESS_ROUTINEA 735 | #endif // !UNICODE 736 | 737 | BOOL WINAPI DetourCreateProcessWithDllExA(_In_opt_ LPCSTR lpApplicationName, 738 | _Inout_opt_ LPSTR lpCommandLine, 739 | _In_opt_ LPSECURITY_ATTRIBUTES lpProcessAttributes, 740 | _In_opt_ LPSECURITY_ATTRIBUTES lpThreadAttributes, 741 | _In_ BOOL bInheritHandles, 742 | _In_ DWORD dwCreationFlags, 743 | _In_opt_ LPVOID lpEnvironment, 744 | _In_opt_ LPCSTR lpCurrentDirectory, 745 | _In_ LPSTARTUPINFOA lpStartupInfo, 746 | _Out_ LPPROCESS_INFORMATION lpProcessInformation, 747 | _In_ LPCSTR lpDllName, 748 | _In_opt_ PDETOUR_CREATE_PROCESS_ROUTINEA pfCreateProcessA); 749 | 750 | BOOL WINAPI DetourCreateProcessWithDllExW(_In_opt_ LPCWSTR lpApplicationName, 751 | _Inout_opt_ LPWSTR lpCommandLine, 752 | _In_opt_ LPSECURITY_ATTRIBUTES lpProcessAttributes, 753 | _In_opt_ LPSECURITY_ATTRIBUTES lpThreadAttributes, 754 | _In_ BOOL bInheritHandles, 755 | _In_ DWORD dwCreationFlags, 756 | _In_opt_ LPVOID lpEnvironment, 757 | _In_opt_ LPCWSTR lpCurrentDirectory, 758 | _In_ LPSTARTUPINFOW lpStartupInfo, 759 | _Out_ LPPROCESS_INFORMATION lpProcessInformation, 760 | _In_ LPCSTR lpDllName, 761 | _In_opt_ PDETOUR_CREATE_PROCESS_ROUTINEW pfCreateProcessW); 762 | 763 | #ifdef UNICODE 764 | #define DetourCreateProcessWithDllEx DetourCreateProcessWithDllExW 765 | #else 766 | #define DetourCreateProcessWithDllEx DetourCreateProcessWithDllExA 767 | #endif // !UNICODE 768 | 769 | BOOL WINAPI DetourCreateProcessWithDllsA(_In_opt_ LPCSTR lpApplicationName, 770 | _Inout_opt_ LPSTR lpCommandLine, 771 | _In_opt_ LPSECURITY_ATTRIBUTES lpProcessAttributes, 772 | _In_opt_ LPSECURITY_ATTRIBUTES lpThreadAttributes, 773 | _In_ BOOL bInheritHandles, 774 | _In_ DWORD dwCreationFlags, 775 | _In_opt_ LPVOID lpEnvironment, 776 | _In_opt_ LPCSTR lpCurrentDirectory, 777 | _In_ LPSTARTUPINFOA lpStartupInfo, 778 | _Out_ LPPROCESS_INFORMATION lpProcessInformation, 779 | _In_ DWORD nDlls, 780 | _In_reads_(nDlls) LPCSTR *rlpDlls, 781 | _In_opt_ PDETOUR_CREATE_PROCESS_ROUTINEA pfCreateProcessA); 782 | 783 | BOOL WINAPI DetourCreateProcessWithDllsW(_In_opt_ LPCWSTR lpApplicationName, 784 | _Inout_opt_ LPWSTR lpCommandLine, 785 | _In_opt_ LPSECURITY_ATTRIBUTES lpProcessAttributes, 786 | _In_opt_ LPSECURITY_ATTRIBUTES lpThreadAttributes, 787 | _In_ BOOL bInheritHandles, 788 | _In_ DWORD dwCreationFlags, 789 | _In_opt_ LPVOID lpEnvironment, 790 | _In_opt_ LPCWSTR lpCurrentDirectory, 791 | _In_ LPSTARTUPINFOW lpStartupInfo, 792 | _Out_ LPPROCESS_INFORMATION lpProcessInformation, 793 | _In_ DWORD nDlls, 794 | _In_reads_(nDlls) LPCSTR *rlpDlls, 795 | _In_opt_ PDETOUR_CREATE_PROCESS_ROUTINEW pfCreateProcessW); 796 | 797 | #ifdef UNICODE 798 | #define DetourCreateProcessWithDlls DetourCreateProcessWithDllsW 799 | #else 800 | #define DetourCreateProcessWithDlls DetourCreateProcessWithDllsA 801 | #endif // !UNICODE 802 | 803 | BOOL WINAPI DetourProcessViaHelperA(_In_ DWORD dwTargetPid, 804 | _In_ LPCSTR lpDllName, 805 | _In_ PDETOUR_CREATE_PROCESS_ROUTINEA pfCreateProcessA); 806 | 807 | BOOL WINAPI DetourProcessViaHelperW(_In_ DWORD dwTargetPid, 808 | _In_ LPCSTR lpDllName, 809 | _In_ PDETOUR_CREATE_PROCESS_ROUTINEW pfCreateProcessW); 810 | 811 | #ifdef UNICODE 812 | #define DetourProcessViaHelper DetourProcessViaHelperW 813 | #else 814 | #define DetourProcessViaHelper DetourProcessViaHelperA 815 | #endif // !UNICODE 816 | 817 | BOOL WINAPI DetourProcessViaHelperDllsA(_In_ DWORD dwTargetPid, 818 | _In_ DWORD nDlls, 819 | _In_reads_(nDlls) LPCSTR *rlpDlls, 820 | _In_ PDETOUR_CREATE_PROCESS_ROUTINEA pfCreateProcessA); 821 | 822 | BOOL WINAPI DetourProcessViaHelperDllsW(_In_ DWORD dwTargetPid, 823 | _In_ DWORD nDlls, 824 | _In_reads_(nDlls) LPCSTR *rlpDlls, 825 | _In_ PDETOUR_CREATE_PROCESS_ROUTINEW pfCreateProcessW); 826 | 827 | #ifdef UNICODE 828 | #define DetourProcessViaHelperDlls DetourProcessViaHelperDllsW 829 | #else 830 | #define DetourProcessViaHelperDlls DetourProcessViaHelperDllsA 831 | #endif // !UNICODE 832 | 833 | BOOL WINAPI DetourUpdateProcessWithDll(_In_ HANDLE hProcess, 834 | _In_reads_(nDlls) LPCSTR *rlpDlls, 835 | _In_ DWORD nDlls); 836 | 837 | BOOL WINAPI DetourUpdateProcessWithDllEx(_In_ HANDLE hProcess, 838 | _In_ HMODULE hImage, 839 | _In_ BOOL bIs32Bit, 840 | _In_reads_(nDlls) LPCSTR *rlpDlls, 841 | _In_ DWORD nDlls); 842 | 843 | BOOL WINAPI DetourCopyPayloadToProcess(_In_ HANDLE hProcess, 844 | _In_ REFGUID rguid, 845 | _In_reads_bytes_(cbData) LPCVOID pvData, 846 | _In_ DWORD cbData); 847 | _Success_(return != NULL) 848 | PVOID WINAPI DetourCopyPayloadToProcessEx(_In_ HANDLE hProcess, 849 | _In_ REFGUID rguid, 850 | _In_reads_bytes_(cbData) LPCVOID pvData, 851 | _In_ DWORD cbData); 852 | 853 | BOOL WINAPI DetourRestoreAfterWith(VOID); 854 | BOOL WINAPI DetourRestoreAfterWithEx(_In_reads_bytes_(cbData) PVOID pvData, 855 | _In_ DWORD cbData); 856 | BOOL WINAPI DetourIsHelperProcess(VOID); 857 | VOID CALLBACK DetourFinishHelperProcess(_In_ HWND, 858 | _In_ HINSTANCE, 859 | _In_ LPSTR, 860 | _In_ INT); 861 | 862 | // 863 | ////////////////////////////////////////////////////////////////////////////// 864 | #ifdef __cplusplus 865 | } 866 | #endif // __cplusplus 867 | 868 | /////////////////////////////////////////////////// Type-safe overloads for C++ 869 | // 870 | #if __cplusplus >= 201103L || _MSVC_LANG >= 201103L 871 | #include 872 | 873 | template 874 | struct DetoursIsFunctionPointer : std::false_type {}; 875 | 876 | template 877 | struct DetoursIsFunctionPointer : std::is_function::type> {}; 878 | 879 | template< 880 | typename T, 881 | typename std::enable_if::value, int>::type = 0> 882 | LONG DetourAttach(_Inout_ T *ppPointer, 883 | _In_ T pDetour) noexcept 884 | { 885 | return DetourAttach( 886 | reinterpret_cast(ppPointer), 887 | reinterpret_cast(pDetour)); 888 | } 889 | 890 | template< 891 | typename T, 892 | typename std::enable_if::value, int>::type = 0> 893 | LONG DetourAttachEx(_Inout_ T *ppPointer, 894 | _In_ T pDetour, 895 | _Out_opt_ PDETOUR_TRAMPOLINE *ppRealTrampoline, 896 | _Out_opt_ T *ppRealTarget, 897 | _Out_opt_ T *ppRealDetour) noexcept 898 | { 899 | return DetourAttachEx( 900 | reinterpret_cast(ppPointer), 901 | reinterpret_cast(pDetour), 902 | ppRealTrampoline, 903 | reinterpret_cast(ppRealTarget), 904 | reinterpret_cast(ppRealDetour)); 905 | } 906 | 907 | template< 908 | typename T, 909 | typename std::enable_if::value, int>::type = 0> 910 | LONG DetourDetach(_Inout_ T *ppPointer, 911 | _In_ T pDetour) noexcept 912 | { 913 | return DetourDetach( 914 | reinterpret_cast(ppPointer), 915 | reinterpret_cast(pDetour)); 916 | } 917 | 918 | #endif // __cplusplus >= 201103L || _MSVC_LANG >= 201103L 919 | // 920 | ////////////////////////////////////////////////////////////////////////////// 921 | 922 | //////////////////////////////////////////////// Detours Internal Definitions. 923 | // 924 | #ifdef __cplusplus 925 | #ifdef DETOURS_INTERNAL 926 | 927 | #define NOTHROW 928 | // #define NOTHROW (nothrow) 929 | 930 | ////////////////////////////////////////////////////////////////////////////// 931 | // 932 | #if (_MSC_VER < 1299) && !defined(__GNUC__) 933 | #include 934 | typedef IMAGEHLP_MODULE IMAGEHLP_MODULE64; 935 | typedef PIMAGEHLP_MODULE PIMAGEHLP_MODULE64; 936 | typedef IMAGEHLP_SYMBOL SYMBOL_INFO; 937 | typedef PIMAGEHLP_SYMBOL PSYMBOL_INFO; 938 | 939 | static inline 940 | LONG InterlockedCompareExchange(_Inout_ LONG *ptr, _In_ LONG nval, _In_ LONG oval) 941 | { 942 | return (LONG)::InterlockedCompareExchange((PVOID*)ptr, (PVOID)nval, (PVOID)oval); 943 | } 944 | #else 945 | #pragma warning(push) 946 | #pragma warning(disable:4091) // empty typedef 947 | #include 948 | #pragma warning(pop) 949 | #endif 950 | 951 | #ifdef IMAGEAPI // defined by DBGHELP.H 952 | typedef LPAPI_VERSION (NTAPI *PF_ImagehlpApiVersionEx)(_In_ LPAPI_VERSION AppVersion); 953 | 954 | typedef BOOL (NTAPI *PF_SymInitialize)(_In_ HANDLE hProcess, 955 | _In_opt_ LPCSTR UserSearchPath, 956 | _In_ BOOL fInvadeProcess); 957 | typedef DWORD (NTAPI *PF_SymSetOptions)(_In_ DWORD SymOptions); 958 | typedef DWORD (NTAPI *PF_SymGetOptions)(VOID); 959 | typedef DWORD64 (NTAPI *PF_SymLoadModule64)(_In_ HANDLE hProcess, 960 | _In_opt_ HANDLE hFile, 961 | _In_opt_ LPSTR ImageName, 962 | _In_opt_ LPSTR ModuleName, 963 | _In_ DWORD64 BaseOfDll, 964 | _In_ DWORD SizeOfDll); 965 | typedef BOOL (NTAPI *PF_SymGetModuleInfo64)(_In_ HANDLE hProcess, 966 | _In_ DWORD64 qwAddr, 967 | _Out_ PIMAGEHLP_MODULE64 ModuleInfo); 968 | typedef BOOL (NTAPI *PF_SymFromName)(_In_ HANDLE hProcess, 969 | _In_ LPSTR Name, 970 | _Out_ PSYMBOL_INFO Symbol); 971 | 972 | typedef struct _DETOUR_SYM_INFO 973 | { 974 | HANDLE hProcess; 975 | HMODULE hDbgHelp; 976 | PF_ImagehlpApiVersionEx pfImagehlpApiVersionEx; 977 | PF_SymInitialize pfSymInitialize; 978 | PF_SymSetOptions pfSymSetOptions; 979 | PF_SymGetOptions pfSymGetOptions; 980 | PF_SymLoadModule64 pfSymLoadModule64; 981 | PF_SymGetModuleInfo64 pfSymGetModuleInfo64; 982 | PF_SymFromName pfSymFromName; 983 | } DETOUR_SYM_INFO, *PDETOUR_SYM_INFO; 984 | 985 | PDETOUR_SYM_INFO DetourLoadImageHlp(VOID); 986 | 987 | #endif // IMAGEAPI 988 | 989 | #if defined(_INC_STDIO) && !defined(_CRT_STDIO_ARBITRARY_WIDE_SPECIFIERS) 990 | #error detours.h must be included before stdio.h (or at least define _CRT_STDIO_ARBITRARY_WIDE_SPECIFIERS earlier) 991 | #endif 992 | #define _CRT_STDIO_ARBITRARY_WIDE_SPECIFIERS 1 993 | 994 | #ifdef _DEBUG 995 | 996 | int Detour_AssertExprWithFunctionName(int reportType, const char* filename, int linenumber, const char* FunctionName, const char* msg); 997 | 998 | #define DETOUR_ASSERT_EXPR_WITH_FUNCTION(expr, msg) \ 999 | (void) ((expr) || \ 1000 | (1 != Detour_AssertExprWithFunctionName(_CRT_ASSERT, __FILE__, __LINE__,__FUNCTION__, msg)) || \ 1001 | (_CrtDbgBreak(), 0)) 1002 | 1003 | #define DETOUR_ASSERT(expr) DETOUR_ASSERT_EXPR_WITH_FUNCTION((expr), #expr) 1004 | 1005 | #else// _DEBUG 1006 | #define DETOUR_ASSERT(expr) 1007 | #endif// _DEBUG 1008 | 1009 | #ifndef DETOUR_TRACE 1010 | #if DETOUR_DEBUG 1011 | #define DETOUR_TRACE(x) printf x 1012 | #define DETOUR_BREAK() __debugbreak() 1013 | #include 1014 | #include 1015 | #else 1016 | #define DETOUR_TRACE(x) 1017 | #define DETOUR_BREAK() 1018 | #endif 1019 | #endif 1020 | 1021 | #if 1 || defined(DETOURS_IA64) 1022 | 1023 | // 1024 | // IA64 instructions are 41 bits, 3 per bundle, plus 5 bit bundle template => 128 bits per bundle. 1025 | // 1026 | 1027 | #define DETOUR_IA64_INSTRUCTIONS_PER_BUNDLE (3) 1028 | 1029 | #define DETOUR_IA64_TEMPLATE_OFFSET (0) 1030 | #define DETOUR_IA64_TEMPLATE_SIZE (5) 1031 | 1032 | #define DETOUR_IA64_INSTRUCTION_SIZE (41) 1033 | #define DETOUR_IA64_INSTRUCTION0_OFFSET (DETOUR_IA64_TEMPLATE_SIZE) 1034 | #define DETOUR_IA64_INSTRUCTION1_OFFSET (DETOUR_IA64_TEMPLATE_SIZE + DETOUR_IA64_INSTRUCTION_SIZE) 1035 | #define DETOUR_IA64_INSTRUCTION2_OFFSET (DETOUR_IA64_TEMPLATE_SIZE + DETOUR_IA64_INSTRUCTION_SIZE + DETOUR_IA64_INSTRUCTION_SIZE) 1036 | 1037 | C_ASSERT(DETOUR_IA64_TEMPLATE_SIZE + DETOUR_IA64_INSTRUCTIONS_PER_BUNDLE * DETOUR_IA64_INSTRUCTION_SIZE == 128); 1038 | 1039 | __declspec(align(16)) struct DETOUR_IA64_BUNDLE 1040 | { 1041 | public: 1042 | union 1043 | { 1044 | BYTE data[16]; 1045 | UINT64 wide[2]; 1046 | }; 1047 | 1048 | enum { 1049 | A_UNIT = 1u, 1050 | I_UNIT = 2u, 1051 | M_UNIT = 3u, 1052 | B_UNIT = 4u, 1053 | F_UNIT = 5u, 1054 | L_UNIT = 6u, 1055 | X_UNIT = 7u, 1056 | }; 1057 | struct DETOUR_IA64_METADATA 1058 | { 1059 | ULONG nTemplate : 8; // Instruction template. 1060 | ULONG nUnit0 : 4; // Unit for slot 0 1061 | ULONG nUnit1 : 4; // Unit for slot 1 1062 | ULONG nUnit2 : 4; // Unit for slot 2 1063 | }; 1064 | 1065 | protected: 1066 | static const DETOUR_IA64_METADATA s_rceCopyTable[33]; 1067 | 1068 | UINT RelocateBundle(_Inout_ DETOUR_IA64_BUNDLE* pDst, _Inout_opt_ DETOUR_IA64_BUNDLE* pBundleExtra) const; 1069 | 1070 | bool RelocateInstruction(_Inout_ DETOUR_IA64_BUNDLE* pDst, 1071 | _In_ BYTE slot, 1072 | _Inout_opt_ DETOUR_IA64_BUNDLE* pBundleExtra) const; 1073 | 1074 | // 120 112 104 96 88 80 72 64 56 48 40 32 24 16 8 0 1075 | // f. e. d. c. b. a. 9. 8. 7. 6. 5. 4. 3. 2. 1. 0. 1076 | 1077 | // 00 1078 | // f.e. d.c. b.a. 9.8. 7.6. 5.4. 3.2. 1.0. 1079 | // 0000 0000 0000 0000 0000 0000 0000 001f : Template [4..0] 1080 | // 0000 0000 0000 0000 0000 03ff ffff ffe0 : Zero [ 41.. 5] 1081 | // 0000 0000 0000 0000 0000 3c00 0000 0000 : Zero [ 45.. 42] 1082 | // 0000 0000 0007 ffff ffff c000 0000 0000 : One [ 82.. 46] 1083 | // 0000 0000 0078 0000 0000 0000 0000 0000 : One [ 86.. 83] 1084 | // 0fff ffff ff80 0000 0000 0000 0000 0000 : Two [123.. 87] 1085 | // f000 0000 0000 0000 0000 0000 0000 0000 : Two [127..124] 1086 | BYTE GetTemplate() const; 1087 | // Get 4 bit opcodes. 1088 | BYTE GetInst0() const; 1089 | BYTE GetInst1() const; 1090 | BYTE GetInst2() const; 1091 | BYTE GetUnit(BYTE slot) const; 1092 | BYTE GetUnit0() const; 1093 | BYTE GetUnit1() const; 1094 | BYTE GetUnit2() const; 1095 | // Get 37 bit data. 1096 | UINT64 GetData0() const; 1097 | UINT64 GetData1() const; 1098 | UINT64 GetData2() const; 1099 | 1100 | // Get/set the full 41 bit instructions. 1101 | UINT64 GetInstruction(BYTE slot) const; 1102 | UINT64 GetInstruction0() const; 1103 | UINT64 GetInstruction1() const; 1104 | UINT64 GetInstruction2() const; 1105 | void SetInstruction(BYTE slot, UINT64 instruction); 1106 | void SetInstruction0(UINT64 instruction); 1107 | void SetInstruction1(UINT64 instruction); 1108 | void SetInstruction2(UINT64 instruction); 1109 | 1110 | // Get/set bitfields. 1111 | static UINT64 GetBits(UINT64 Value, UINT64 Offset, UINT64 Count); 1112 | static UINT64 SetBits(UINT64 Value, UINT64 Offset, UINT64 Count, UINT64 Field); 1113 | 1114 | // Get specific read-only fields. 1115 | static UINT64 GetOpcode(UINT64 instruction); // 4bit opcode 1116 | static UINT64 GetX(UINT64 instruction); // 1bit opcode extension 1117 | static UINT64 GetX3(UINT64 instruction); // 3bit opcode extension 1118 | static UINT64 GetX6(UINT64 instruction); // 6bit opcode extension 1119 | 1120 | // Get/set specific fields. 1121 | static UINT64 GetImm7a(UINT64 instruction); 1122 | static UINT64 SetImm7a(UINT64 instruction, UINT64 imm7a); 1123 | static UINT64 GetImm13c(UINT64 instruction); 1124 | static UINT64 SetImm13c(UINT64 instruction, UINT64 imm13c); 1125 | static UINT64 GetSignBit(UINT64 instruction); 1126 | static UINT64 SetSignBit(UINT64 instruction, UINT64 signBit); 1127 | static UINT64 GetImm20a(UINT64 instruction); 1128 | static UINT64 SetImm20a(UINT64 instruction, UINT64 imm20a); 1129 | static UINT64 GetImm20b(UINT64 instruction); 1130 | static UINT64 SetImm20b(UINT64 instruction, UINT64 imm20b); 1131 | 1132 | static UINT64 SignExtend(UINT64 Value, UINT64 Offset); 1133 | 1134 | BOOL IsMovlGp() const; 1135 | 1136 | VOID SetInst(BYTE Slot, BYTE nInst); 1137 | VOID SetInst0(BYTE nInst); 1138 | VOID SetInst1(BYTE nInst); 1139 | VOID SetInst2(BYTE nInst); 1140 | VOID SetData(BYTE Slot, UINT64 nData); 1141 | VOID SetData0(UINT64 nData); 1142 | VOID SetData1(UINT64 nData); 1143 | VOID SetData2(UINT64 nData); 1144 | BOOL SetNop(BYTE Slot); 1145 | BOOL SetNop0(); 1146 | BOOL SetNop1(); 1147 | BOOL SetNop2(); 1148 | 1149 | public: 1150 | BOOL IsBrl() const; 1151 | VOID SetBrl(); 1152 | VOID SetBrl(UINT64 target); 1153 | UINT64 GetBrlTarget() const; 1154 | VOID SetBrlTarget(UINT64 target); 1155 | VOID SetBrlImm(UINT64 imm); 1156 | UINT64 GetBrlImm() const; 1157 | 1158 | UINT64 GetMovlGp() const; 1159 | VOID SetMovlGp(UINT64 gp); 1160 | 1161 | VOID SetStop(); 1162 | 1163 | UINT Copy(_Out_ DETOUR_IA64_BUNDLE *pDst, _Inout_opt_ DETOUR_IA64_BUNDLE* pBundleExtra = NULL) const; 1164 | }; 1165 | #endif // DETOURS_IA64 1166 | 1167 | #ifdef DETOURS_ARM 1168 | 1169 | #define DETOURS_PFUNC_TO_PBYTE(p) ((PBYTE)(((ULONG_PTR)(p)) & ~(ULONG_PTR)1)) 1170 | #define DETOURS_PBYTE_TO_PFUNC(p) ((PBYTE)(((ULONG_PTR)(p)) | (ULONG_PTR)1)) 1171 | 1172 | #endif // DETOURS_ARM 1173 | 1174 | ////////////////////////////////////////////////////////////////////////////// 1175 | 1176 | #ifdef __cplusplus 1177 | extern "C" { 1178 | #endif // __cplusplus 1179 | 1180 | #define DETOUR_OFFLINE_LIBRARY(x) \ 1181 | PVOID WINAPI DetourCopyInstruction##x(_In_opt_ PVOID pDst, \ 1182 | _Inout_opt_ PVOID *ppDstPool, \ 1183 | _In_ PVOID pSrc, \ 1184 | _Out_opt_ PVOID *ppTarget, \ 1185 | _Out_opt_ LONG *plExtra); \ 1186 | \ 1187 | BOOL WINAPI DetourSetCodeModule##x(_In_ HMODULE hModule, \ 1188 | _In_ BOOL fLimitReferencesToModule); \ 1189 | 1190 | DETOUR_OFFLINE_LIBRARY(X86) 1191 | DETOUR_OFFLINE_LIBRARY(X64) 1192 | DETOUR_OFFLINE_LIBRARY(ARM) 1193 | DETOUR_OFFLINE_LIBRARY(ARM64) 1194 | DETOUR_OFFLINE_LIBRARY(IA64) 1195 | 1196 | #undef DETOUR_OFFLINE_LIBRARY 1197 | 1198 | ////////////////////////////////////////////////////////////////////////////// 1199 | // 1200 | // Helpers for manipulating page protection. 1201 | // 1202 | 1203 | _Success_(return != FALSE) 1204 | BOOL WINAPI DetourVirtualProtectSameExecuteEx(_In_ HANDLE hProcess, 1205 | _In_ PVOID pAddress, 1206 | _In_ SIZE_T nSize, 1207 | _In_ DWORD dwNewProtect, 1208 | _Out_ PDWORD pdwOldProtect); 1209 | 1210 | _Success_(return != FALSE) 1211 | BOOL WINAPI DetourVirtualProtectSameExecute(_In_ PVOID pAddress, 1212 | _In_ SIZE_T nSize, 1213 | _In_ DWORD dwNewProtect, 1214 | _Out_ PDWORD pdwOldProtect); 1215 | 1216 | // Detours must depend only on kernel32.lib, so we cannot use IsEqualGUID 1217 | BOOL WINAPI DetourAreSameGuid(_In_ REFGUID left, _In_ REFGUID right); 1218 | #ifdef __cplusplus 1219 | } 1220 | #endif // __cplusplus 1221 | 1222 | ////////////////////////////////////////////////////////////////////////////// 1223 | 1224 | #define MM_ALLOCATION_GRANULARITY 0x10000 1225 | 1226 | ////////////////////////////////////////////////////////////////////////////// 1227 | 1228 | #endif // DETOURS_INTERNAL 1229 | #endif // __cplusplus 1230 | 1231 | #endif // _DETOURS_H_ 1232 | // 1233 | //////////////////////////////////////////////////////////////// End of File. 1234 | --------------------------------------------------------------------------------