├── 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 |
--------------------------------------------------------------------------------