Compare commits

..

2 Commits

Author SHA1 Message Date
Mr_Goldberg c162ca79d5
Update detours library to latest. 2021-05-16 21:04:54 -04:00
Mr_Goldberg 5495f36ed6
Update imgui library to latest. 2021-05-16 21:04:18 -04:00
27 changed files with 10081 additions and 3693 deletions

View File

@ -20,7 +20,9 @@
//#define IM_ASSERT(_EXPR) ((void)(_EXPR)) // Disable asserts //#define IM_ASSERT(_EXPR) ((void)(_EXPR)) // Disable asserts
//---- Define attributes of all API symbols declarations, e.g. for DLL under Windows //---- Define attributes of all API symbols declarations, e.g. for DLL under Windows
// Using dear imgui via a shared library is not recommended, because of function call overhead and because we don't guarantee backward nor forward ABI compatibility. // Using Dear ImGui via a shared library is not recommended, because of function call overhead and because we don't guarantee backward nor forward ABI compatibility.
// DLL users: heaps and globals are not shared across DLL boundaries! You will need to call SetCurrentContext() + SetAllocatorFunctions()
// for each static/DLL boundary you are calling from. Read "Context and Memory Allocators" section of imgui.cpp for more details.
//#define IMGUI_API __declspec( dllexport ) //#define IMGUI_API __declspec( dllexport )
//#define IMGUI_API __declspec( dllimport ) //#define IMGUI_API __declspec( dllimport )
@ -31,11 +33,11 @@
// It is very strongly recommended to NOT disable the demo windows during development. Please read comments in imgui_demo.cpp. // It is very strongly recommended to NOT disable the demo windows during development. Please read comments in imgui_demo.cpp.
//#define IMGUI_DISABLE // Disable everything: all headers and source files will be empty. //#define IMGUI_DISABLE // Disable everything: all headers and source files will be empty.
#define IMGUI_DISABLE_DEMO_WINDOWS // Disable demo windows: ShowDemoWindow()/ShowStyleEditor() will be empty. Not recommended. #define IMGUI_DISABLE_DEMO_WINDOWS // Disable demo windows: ShowDemoWindow()/ShowStyleEditor() will be empty. Not recommended.
#define IMGUI_DISABLE_METRICS_WINDOW // Disable debug/metrics window: ShowMetricsWindow() will be empty. #define IMGUI_DISABLE_METRICS_WINDOW // Disable metrics/debugger window: ShowMetricsWindow() will be empty.
//---- Don't implement some functions to reduce linkage requirements. //---- Don't implement some functions to reduce linkage requirements.
//#define IMGUI_DISABLE_WIN32_DEFAULT_CLIPBOARD_FUNCTIONS // [Win32] Don't implement default clipboard handler. Won't use and link with OpenClipboard/GetClipboardData/CloseClipboard etc. //#define IMGUI_DISABLE_WIN32_DEFAULT_CLIPBOARD_FUNCTIONS // [Win32] Don't implement default clipboard handler. Won't use and link with OpenClipboard/GetClipboardData/CloseClipboard etc. (user32.lib/.a, kernel32.lib/.a)
#define IMGUI_DISABLE_WIN32_DEFAULT_IME_FUNCTIONS // [Win32] Don't implement default IME handler. Won't use and link with ImmGetContext/ImmSetCompositionWindow. #define IMGUI_DISABLE_WIN32_DEFAULT_IME_FUNCTIONS // [Win32] Don't implement default IME handler. Won't use and link with ImmGetContext/ImmSetCompositionWindow. (imm32.lib/.a)
//#define IMGUI_DISABLE_WIN32_FUNCTIONS // [Win32] Won't use and link with any Win32 function (clipboard, ime). //#define IMGUI_DISABLE_WIN32_FUNCTIONS // [Win32] Won't use and link with any Win32 function (clipboard, ime).
//#define IMGUI_ENABLE_OSX_DEFAULT_CLIPBOARD_FUNCTIONS // [OSX] Implement default OSX clipboard handler (need to link with '-framework ApplicationServices', this is why this is not the default). //#define IMGUI_ENABLE_OSX_DEFAULT_CLIPBOARD_FUNCTIONS // [OSX] Implement default OSX clipboard handler (need to link with '-framework ApplicationServices', this is why this is not the default).
//#define IMGUI_DISABLE_DEFAULT_FORMAT_FUNCTIONS // Don't implement ImFormatString/ImFormatStringV so you can implement them yourself (e.g. if you don't want to link with vsnprintf) //#define IMGUI_DISABLE_DEFAULT_FORMAT_FUNCTIONS // Don't implement ImFormatString/ImFormatStringV so you can implement them yourself (e.g. if you don't want to link with vsnprintf)
@ -49,20 +51,29 @@
//---- Pack colors to BGRA8 instead of RGBA8 (to avoid converting from one to another) //---- Pack colors to BGRA8 instead of RGBA8 (to avoid converting from one to another)
//#define IMGUI_USE_BGRA_PACKED_COLOR //#define IMGUI_USE_BGRA_PACKED_COLOR
//---- Use 32-bit for ImWchar (default is 16-bit) to support full unicode code points. //---- Use 32-bit for ImWchar (default is 16-bit) to support unicode planes 1-16. (e.g. point beyond 0xFFFF like emoticons, dingbats, symbols, shapes, ancient languages, etc...)
//#define IMGUI_USE_WCHAR32 //#define IMGUI_USE_WCHAR32
//---- Avoid multiple STB libraries implementations, or redefine path/filenames to prioritize another version //---- Avoid multiple STB libraries implementations, or redefine path/filenames to prioritize another version
// By default the embedded implementations are declared static and not available outside of imgui cpp files. // By default the embedded implementations are declared static and not available outside of Dear ImGui sources files.
//#define IMGUI_STB_TRUETYPE_FILENAME "my_folder/stb_truetype.h" //#define IMGUI_STB_TRUETYPE_FILENAME "my_folder/stb_truetype.h"
//#define IMGUI_STB_RECT_PACK_FILENAME "my_folder/stb_rect_pack.h" //#define IMGUI_STB_RECT_PACK_FILENAME "my_folder/stb_rect_pack.h"
//#define IMGUI_DISABLE_STB_TRUETYPE_IMPLEMENTATION //#define IMGUI_DISABLE_STB_TRUETYPE_IMPLEMENTATION
//#define IMGUI_DISABLE_STB_RECT_PACK_IMPLEMENTATION //#define IMGUI_DISABLE_STB_RECT_PACK_IMPLEMENTATION
//---- Unless IMGUI_DISABLE_DEFAULT_FORMAT_FUNCTIONS is defined, use the much faster STB sprintf library implementation of vsnprintf instead of the one from the default C library. //---- Use stb_printf's faster implementation of vsnprintf instead of the one from libc (unless IMGUI_DISABLE_DEFAULT_FORMAT_FUNCTIONS is defined)
// Note that stb_sprintf.h is meant to be provided by the user and available in the include path at compile time. Also, the compatibility checks of the arguments and formats done by clang and GCC will be disabled in order to support the extra formats provided by STB sprintf. // Requires 'stb_sprintf.h' to be available in the include path. Compatibility checks of arguments and formats done by clang and GCC will be disabled in order to support the extra formats provided by STB sprintf.
// #define IMGUI_USE_STB_SPRINTF // #define IMGUI_USE_STB_SPRINTF
//---- Use FreeType to build and rasterize the font atlas (instead of stb_truetype which is embedded by default in Dear ImGui)
// Requires FreeType headers to be available in the include path. Requires program to be compiled with 'misc/freetype/imgui_freetype.cpp' (in this repository) + the FreeType library (not provided).
// On Windows you may use vcpkg with 'vcpkg install freetype' + 'vcpkg integrate install'.
//#define IMGUI_ENABLE_FREETYPE
//---- Use stb_truetype to build and rasterize the font atlas (default)
// The only purpose of this define is if you want force compilation of the stb_truetype backend ALONG with the FreeType backend.
//#define IMGUI_ENABLE_STB_TRUETYPE
//---- Define constructor and implicit cast operators to convert back<>forth between your math types and ImVec2/ImVec4. //---- Define constructor and implicit cast operators to convert back<>forth between your math types and ImVec2/ImVec4.
// This will be inlined as part of ImVec2 and ImVec4 class declarations. // This will be inlined as part of ImVec2 and ImVec4 class declarations.
/* /*
@ -76,12 +87,12 @@
*/ */
//---- Use 32-bit vertex indices (default is 16-bit) is one way to allow large meshes with more than 64K vertices. //---- Use 32-bit vertex indices (default is 16-bit) is one way to allow large meshes with more than 64K vertices.
// Your renderer back-end will need to support it (most example renderer back-ends support both 16/32-bit indices). // Your renderer backend will need to support it (most example renderer backends support both 16/32-bit indices).
// Another way to allow large meshes while keeping 16-bit indices is to handle ImDrawCmd::VtxOffset in your renderer. // Another way to allow large meshes while keeping 16-bit indices is to handle ImDrawCmd::VtxOffset in your renderer.
// Read about ImGuiBackendFlags_RendererHasVtxOffset for details. // Read about ImGuiBackendFlags_RendererHasVtxOffset for details.
//#define ImDrawIdx unsigned int //#define ImDrawIdx unsigned int
//---- Override ImDrawCallback signature (will need to modify renderer back-ends accordingly) //---- Override ImDrawCallback signature (will need to modify renderer backends accordingly)
//struct ImDrawList; //struct ImDrawList;
//struct ImDrawCmd; //struct ImDrawCmd;
//typedef void (*MyImDrawCallback)(const ImDrawList* draw_list, const ImDrawCmd* cmd, void* my_renderer_user_data); //typedef void (*MyImDrawCallback)(const ImDrawList* draw_list, const ImDrawCmd* cmd, void* my_renderer_user_data);
@ -99,6 +110,7 @@
//---- Debug Tools: Enable slower asserts //---- Debug Tools: Enable slower asserts
//#define IMGUI_DEBUG_PARANOID //#define IMGUI_DEBUG_PARANOID
//---- Tip: You can add extra functions within the ImGui:: namespace, here or in your own headers files. //---- Tip: You can add extra functions within the ImGui:: namespace, here or in your own headers files.
/* /*
namespace ImGui namespace ImGui

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

4004
ImGui/imgui_tables.cpp Normal file

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -1,18 +1,23 @@
// dear imgui: Renderer for modern OpenGL with shaders / programmatic pipeline // dear imgui: Renderer Backend for modern OpenGL with shaders / programmatic pipeline
// - Desktop GL: 2.x 3.x 4.x // - Desktop GL: 2.x 3.x 4.x
// - Embedded GL: ES 2.0 (WebGL 1.0), ES 3.0 (WebGL 2.0) // - Embedded GL: ES 2.0 (WebGL 1.0), ES 3.0 (WebGL 2.0)
// This needs to be used along with a Platform Binding (e.g. GLFW, SDL, Win32, custom..) // This needs to be used along with a Platform Backend (e.g. GLFW, SDL, Win32, custom..)
// Implemented features: // Implemented features:
// [X] Renderer: User texture binding. Use 'GLuint' OpenGL texture identifier as void*/ImTextureID. Read the FAQ about ImTextureID! // [X] Renderer: User texture binding. Use 'GLuint' OpenGL texture identifier as void*/ImTextureID. Read the FAQ about ImTextureID!
// [x] Renderer: Desktop GL only: Support for large meshes (64k+ vertices) with 16-bit indices. // [x] Renderer: Desktop GL only: Support for large meshes (64k+ vertices) with 16-bit indices.
// You can copy and use unmodified imgui_impl_* files in your project. See main.cpp for an example of using this. // You can copy and use unmodified imgui_impl_* files in your project. See examples/ folder for examples of using this.
// If you are new to dear imgui, read examples/README.txt and read the documentation at the top of imgui.cpp. // If you are new to Dear ImGui, read documentation from the docs/ folder + read the top of imgui.cpp.
// https://github.com/ocornut/imgui // Read online: https://github.com/ocornut/imgui/tree/master/docs
// CHANGELOG // CHANGELOG
// (minor and older changes stripped away, please see git history for details) // (minor and older changes stripped away, please see git history for details)
// 2021-04-06: OpenGL: Don't try to read GL_CLIP_ORIGIN unless we're OpenGL 4.5 or greater.
// 2021-02-18: OpenGL: Change blending equation to preserve alpha in output buffer.
// 2021-01-03: OpenGL: Backup, setup and restore GL_STENCIL_TEST state.
// 2020-10-23: OpenGL: Backup, setup and restore GL_PRIMITIVE_RESTART state.
// 2020-10-15: OpenGL: Use glGetString(GL_VERSION) instead of glGetIntegerv(GL_MAJOR_VERSION, ...) when the later returns zero (e.g. Desktop GL 2.x)
// 2020-09-17: OpenGL: Fix to avoid compiling/calling glBindSampler() on ES or pre 3.3 context which have the defines set by a loader. // 2020-09-17: OpenGL: Fix to avoid compiling/calling glBindSampler() on ES or pre 3.3 context which have the defines set by a loader.
// 2020-07-10: OpenGL: Added support for glad2 OpenGL loader. // 2020-07-10: OpenGL: Added support for glad2 OpenGL loader.
// 2020-05-08: OpenGL: Made default GLSL version 150 (instead of 130) on OSX. // 2020-05-08: OpenGL: Made default GLSL version 150 (instead of 130) on OSX.
@ -73,7 +78,7 @@
#define _CRT_SECURE_NO_WARNINGS #define _CRT_SECURE_NO_WARNINGS
#endif #endif
#include "../imgui.h" #include "imgui.h"
#include "imgui_impl_opengl3.h" #include "imgui_impl_opengl3.h"
#include <stdio.h> #include <stdio.h>
#if defined(_MSC_VER) && _MSC_VER <= 1500 // MSVC 2008 or earlier #if defined(_MSC_VER) && _MSC_VER <= 1500 // MSVC 2008 or earlier
@ -133,6 +138,11 @@ using namespace gl;
#define IMGUI_IMPL_OPENGL_MAY_HAVE_BIND_SAMPLER #define IMGUI_IMPL_OPENGL_MAY_HAVE_BIND_SAMPLER
#endif #endif
// Desktop GL 3.1+ has GL_PRIMITIVE_RESTART state
#if !defined(IMGUI_IMPL_OPENGL_ES2) && !defined(IMGUI_IMPL_OPENGL_ES3) && defined(GL_VERSION_3_1)
#define IMGUI_IMPL_OPENGL_MAY_HAVE_PRIMITIVE_RESTART
#endif
// OpenGL Data // OpenGL Data
static GLuint g_GlVersion = 0; // Extracted at runtime using GL_MAJOR_VERSION, GL_MINOR_VERSION queries (e.g. 320 for GL 3.2) static GLuint g_GlVersion = 0; // Extracted at runtime using GL_MAJOR_VERSION, GL_MINOR_VERSION queries (e.g. 320 for GL 3.2)
static char g_GlslVersionString[32] = ""; // Specified by user or detected based on compile time GL settings. static char g_GlslVersionString[32] = ""; // Specified by user or detected based on compile time GL settings.
@ -147,15 +157,22 @@ bool ImGui_ImplOpenGL3_Init(const char* glsl_version)
{ {
// Query for GL version (e.g. 320 for GL 3.2) // Query for GL version (e.g. 320 for GL 3.2)
#if !defined(IMGUI_IMPL_OPENGL_ES2) #if !defined(IMGUI_IMPL_OPENGL_ES2)
GLint major, minor; GLint major = 0;
GLint minor = 0;
glGetIntegerv(GL_MAJOR_VERSION, &major); glGetIntegerv(GL_MAJOR_VERSION, &major);
glGetIntegerv(GL_MINOR_VERSION, &minor); glGetIntegerv(GL_MINOR_VERSION, &minor);
if (major == 0 && minor == 0)
{
// Query GL_VERSION in desktop GL 2.x, the string will start with "<major>.<minor>"
const char* gl_version = (const char*)glGetString(GL_VERSION);
sscanf(gl_version, "%d.%d", &major, &minor);
}
g_GlVersion = (GLuint)(major * 100 + minor * 10); g_GlVersion = (GLuint)(major * 100 + minor * 10);
#else #else
g_GlVersion = 200; // GLES 2 g_GlVersion = 200; // GLES 2
#endif #endif
// Setup back-end capabilities flags // Setup backend capabilities flags
ImGuiIO& io = ImGui::GetIO(); ImGuiIO& io = ImGui::GetIO();
io.BackendRendererName = "imgui_impl_opengl3"; io.BackendRendererName = "imgui_impl_opengl3";
#ifdef IMGUI_IMPL_OPENGL_MAY_HAVE_VTX_OFFSET #ifdef IMGUI_IMPL_OPENGL_MAY_HAVE_VTX_OFFSET
@ -233,20 +250,28 @@ static void ImGui_ImplOpenGL3_SetupRenderState(ImDrawData* draw_data, int fb_wid
// Setup render state: alpha-blending enabled, no face culling, no depth testing, scissor enabled, polygon fill // Setup render state: alpha-blending enabled, no face culling, no depth testing, scissor enabled, polygon fill
glEnable(GL_BLEND); glEnable(GL_BLEND);
glBlendEquation(GL_FUNC_ADD); glBlendEquation(GL_FUNC_ADD);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); glBlendFuncSeparate(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, GL_ONE, GL_ONE_MINUS_SRC_ALPHA);
glDisable(GL_CULL_FACE); glDisable(GL_CULL_FACE);
glDisable(GL_DEPTH_TEST); glDisable(GL_DEPTH_TEST);
glDisable(GL_STENCIL_TEST);
glEnable(GL_SCISSOR_TEST); glEnable(GL_SCISSOR_TEST);
#ifdef IMGUI_IMPL_OPENGL_MAY_HAVE_PRIMITIVE_RESTART
if (g_GlVersion >= 310)
glDisable(GL_PRIMITIVE_RESTART);
#endif
#ifdef GL_POLYGON_MODE #ifdef GL_POLYGON_MODE
glPolygonMode(GL_FRONT_AND_BACK, GL_FILL); glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
#endif #endif
// Support for GL 4.5 rarely used glClipControl(GL_UPPER_LEFT) // Support for GL 4.5 rarely used glClipControl(GL_UPPER_LEFT)
#if defined(GL_CLIP_ORIGIN)
bool clip_origin_lower_left = true; bool clip_origin_lower_left = true;
#if defined(GL_CLIP_ORIGIN) && !defined(__APPLE__) if (g_GlVersion >= 450)
{
GLenum current_clip_origin = 0; glGetIntegerv(GL_CLIP_ORIGIN, (GLint*)&current_clip_origin); GLenum current_clip_origin = 0; glGetIntegerv(GL_CLIP_ORIGIN, (GLint*)&current_clip_origin);
if (current_clip_origin == GL_UPPER_LEFT) if (current_clip_origin == GL_UPPER_LEFT)
clip_origin_lower_left = false; clip_origin_lower_left = false;
}
#endif #endif
// Setup viewport, orthographic projection matrix // Setup viewport, orthographic projection matrix
@ -256,7 +281,9 @@ static void ImGui_ImplOpenGL3_SetupRenderState(ImDrawData* draw_data, int fb_wid
float R = draw_data->DisplayPos.x + draw_data->DisplaySize.x; float R = draw_data->DisplayPos.x + draw_data->DisplaySize.x;
float T = draw_data->DisplayPos.y; float T = draw_data->DisplayPos.y;
float B = draw_data->DisplayPos.y + draw_data->DisplaySize.y; float B = draw_data->DisplayPos.y + draw_data->DisplaySize.y;
#if defined(GL_CLIP_ORIGIN)
if (!clip_origin_lower_left) { float tmp = T; T = B; B = tmp; } // Swap top and bottom if origin is upper left if (!clip_origin_lower_left) { float tmp = T; T = B; B = tmp; } // Swap top and bottom if origin is upper left
#endif
const float ortho_projection[4][4] = const float ortho_projection[4][4] =
{ {
{ 2.0f/(R-L), 0.0f, 0.0f, 0.0f }, { 2.0f/(R-L), 0.0f, 0.0f, 0.0f },
@ -290,8 +317,8 @@ static void ImGui_ImplOpenGL3_SetupRenderState(ImDrawData* draw_data, int fb_wid
} }
// OpenGL3 Render function. // OpenGL3 Render function.
// (this used to be set in io.RenderDrawListsFn and called by ImGui::Render(), but you can now call this directly from your main loop) // Note that this implementation is little overcomplicated because we are saving/setting up/restoring every OpenGL state explicitly.
// Note that this implementation is little overcomplicated because we are saving/setting up/restoring every OpenGL state explicitly, in order to be able to run within any OpenGL engine that doesn't do so. // This is in order to be able to run within an OpenGL engine that doesn't do so.
void ImGui_ImplOpenGL3_RenderDrawData(ImDrawData* draw_data) void ImGui_ImplOpenGL3_RenderDrawData(ImDrawData* draw_data)
{ {
// Avoid rendering when minimized, scale coordinates for retina displays (screen coordinates != framebuffer coordinates) // Avoid rendering when minimized, scale coordinates for retina displays (screen coordinates != framebuffer coordinates)
@ -326,7 +353,11 @@ void ImGui_ImplOpenGL3_RenderDrawData(ImDrawData* draw_data)
GLboolean last_enable_blend = glIsEnabled(GL_BLEND); GLboolean last_enable_blend = glIsEnabled(GL_BLEND);
GLboolean last_enable_cull_face = glIsEnabled(GL_CULL_FACE); GLboolean last_enable_cull_face = glIsEnabled(GL_CULL_FACE);
GLboolean last_enable_depth_test = glIsEnabled(GL_DEPTH_TEST); GLboolean last_enable_depth_test = glIsEnabled(GL_DEPTH_TEST);
GLboolean last_enable_stencil_test = glIsEnabled(GL_STENCIL_TEST);
GLboolean last_enable_scissor_test = glIsEnabled(GL_SCISSOR_TEST); GLboolean last_enable_scissor_test = glIsEnabled(GL_SCISSOR_TEST);
#ifdef IMGUI_IMPL_OPENGL_MAY_HAVE_PRIMITIVE_RESTART
GLboolean last_enable_primitive_restart = (g_GlVersion >= 310) ? glIsEnabled(GL_PRIMITIVE_RESTART) : GL_FALSE;
#endif
// Setup desired GL state // Setup desired GL state
// Recreate the VAO every time (this is to easily allow multiple GL contexts to be rendered to. VAO are not shared among GL contexts) // Recreate the VAO every time (this is to easily allow multiple GL contexts to be rendered to. VAO are not shared among GL contexts)
@ -411,7 +442,12 @@ void ImGui_ImplOpenGL3_RenderDrawData(ImDrawData* draw_data)
if (last_enable_blend) glEnable(GL_BLEND); else glDisable(GL_BLEND); if (last_enable_blend) glEnable(GL_BLEND); else glDisable(GL_BLEND);
if (last_enable_cull_face) glEnable(GL_CULL_FACE); else glDisable(GL_CULL_FACE); if (last_enable_cull_face) glEnable(GL_CULL_FACE); else glDisable(GL_CULL_FACE);
if (last_enable_depth_test) glEnable(GL_DEPTH_TEST); else glDisable(GL_DEPTH_TEST); if (last_enable_depth_test) glEnable(GL_DEPTH_TEST); else glDisable(GL_DEPTH_TEST);
if (last_enable_stencil_test) glEnable(GL_STENCIL_TEST); else glDisable(GL_STENCIL_TEST);
if (last_enable_scissor_test) glEnable(GL_SCISSOR_TEST); else glDisable(GL_SCISSOR_TEST); if (last_enable_scissor_test) glEnable(GL_SCISSOR_TEST); else glDisable(GL_SCISSOR_TEST);
#ifdef IMGUI_IMPL_OPENGL_MAY_HAVE_PRIMITIVE_RESTART
if (g_GlVersion >= 310) { if (last_enable_primitive_restart) glEnable(GL_PRIMITIVE_RESTART); else glDisable(GL_PRIMITIVE_RESTART); }
#endif
#ifdef GL_POLYGON_MODE #ifdef GL_POLYGON_MODE
glPolygonMode(GL_FRONT_AND_BACK, (GLenum)last_polygon_mode[0]); glPolygonMode(GL_FRONT_AND_BACK, (GLenum)last_polygon_mode[0]);
#endif #endif
@ -440,7 +476,7 @@ bool ImGui_ImplOpenGL3_CreateFontsTexture()
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, pixels); glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, pixels);
// Store our identifier // Store our identifier
io.Fonts->TexID = (ImTextureID)(intptr_t)g_FontTexture; io.Fonts->SetTexID((ImTextureID)(intptr_t)g_FontTexture);
// Restore state // Restore state
glBindTexture(GL_TEXTURE_2D, last_texture); glBindTexture(GL_TEXTURE_2D, last_texture);
@ -454,7 +490,7 @@ void ImGui_ImplOpenGL3_DestroyFontsTexture()
{ {
ImGuiIO& io = ImGui::GetIO(); ImGuiIO& io = ImGui::GetIO();
glDeleteTextures(1, &g_FontTexture); glDeleteTextures(1, &g_FontTexture);
io.Fonts->TexID = 0; io.Fonts->SetTexID(0);
g_FontTexture = 0; g_FontTexture = 0;
} }
} }

View File

@ -1,15 +1,15 @@
// dear imgui: Renderer for modern OpenGL with shaders / programmatic pipeline // dear imgui: Renderer Backend for modern OpenGL with shaders / programmatic pipeline
// - Desktop GL: 2.x 3.x 4.x // - Desktop GL: 2.x 3.x 4.x
// - Embedded GL: ES 2.0 (WebGL 1.0), ES 3.0 (WebGL 2.0) // - Embedded GL: ES 2.0 (WebGL 1.0), ES 3.0 (WebGL 2.0)
// This needs to be used along with a Platform Binding (e.g. GLFW, SDL, Win32, custom..) // This needs to be used along with a Platform Backend (e.g. GLFW, SDL, Win32, custom..)
// Implemented features: // Implemented features:
// [X] Renderer: User texture binding. Use 'GLuint' OpenGL texture identifier as void*/ImTextureID. Read the FAQ about ImTextureID! // [X] Renderer: User texture binding. Use 'GLuint' OpenGL texture identifier as void*/ImTextureID. Read the FAQ about ImTextureID!
// [x] Renderer: Desktop GL only: Support for large meshes (64k+ vertices) with 16-bit indices. // [x] Renderer: Desktop GL only: Support for large meshes (64k+ vertices) with 16-bit indices.
// You can copy and use unmodified imgui_impl_* files in your project. See main.cpp for an example of using this. // You can copy and use unmodified imgui_impl_* files in your project. See examples/ folder for examples of using this.
// If you are new to dear imgui, read examples/README.txt and read the documentation at the top of imgui.cpp. // If you are new to Dear ImGui, read documentation from the docs/ folder + read the top of imgui.cpp.
// https://github.com/ocornut/imgui // Read online: https://github.com/ocornut/imgui/tree/master/docs
// About Desktop OpenGL function loaders: // About Desktop OpenGL function loaders:
// Modern Desktop OpenGL doesn't have a standard portable header file to load OpenGL function pointers. // Modern Desktop OpenGL doesn't have a standard portable header file to load OpenGL function pointers.
@ -22,7 +22,7 @@
// Only override if your GL version doesn't handle this GLSL version. See GLSL version table at the top of imgui_impl_opengl3.cpp. // Only override if your GL version doesn't handle this GLSL version. See GLSL version table at the top of imgui_impl_opengl3.cpp.
#pragma once #pragma once
#include "../imgui.h" // IMGUI_IMPL_API #include "imgui.h" // IMGUI_IMPL_API
// Backend API // Backend API
IMGUI_IMPL_API bool ImGui_ImplOpenGL3_Init(const char* glsl_version = NULL); IMGUI_IMPL_API bool ImGui_ImplOpenGL3_Init(const char* glsl_version = NULL);

View File

@ -1,16 +1,17 @@
// dear imgui: Renderer for DirectX10 // dear imgui: Renderer Backend for DirectX10
// This needs to be used along with a Platform Binding (e.g. Win32) // This needs to be used along with a Platform Backend (e.g. Win32)
// Implemented features: // Implemented features:
// [X] Renderer: User texture binding. Use 'ID3D10ShaderResourceView*' as ImTextureID. Read the FAQ about ImTextureID! // [X] Renderer: User texture backend. Use 'ID3D10ShaderResourceView*' as ImTextureID. Read the FAQ about ImTextureID!
// [X] Renderer: Support for large meshes (64k+ vertices) with 16-bit indices. // [X] Renderer: Support for large meshes (64k+ vertices) with 16-bit indices.
// You can copy and use unmodified imgui_impl_* files in your project. See main.cpp for an example of using this. // You can copy and use unmodified imgui_impl_* files in your project. See examples/ folder for examples of using this.
// If you are new to dear imgui, read examples/README.txt and read the documentation at the top of imgui.cpp. // If you are new to Dear ImGui, read documentation from the docs/ folder + read the top of imgui.cpp.
// https://github.com/ocornut/imgui // Read online: https://github.com/ocornut/imgui/tree/master/docs
// CHANGELOG // CHANGELOG
// (minor and older changes stripped away, please see git history for details) // (minor and older changes stripped away, please see git history for details)
// 2021-02-18: DirectX10: Change blending equation to preserve alpha in output buffer.
// 2019-07-21: DirectX10: Backup, clear and restore Geometry Shader is any is bound when calling ImGui_ImplDX10_RenderDrawData(). // 2019-07-21: DirectX10: Backup, clear and restore Geometry Shader is any is bound when calling ImGui_ImplDX10_RenderDrawData().
// 2019-05-29: DirectX10: Added support for large mesh (64K+ vertices), enable ImGuiBackendFlags_RendererHasVtxOffset flag. // 2019-05-29: DirectX10: Added support for large mesh (64K+ vertices), enable ImGuiBackendFlags_RendererHasVtxOffset flag.
// 2019-04-30: DirectX10: Added support for special ImDrawCallback_ResetRenderState callback to reset render state. // 2019-04-30: DirectX10: Added support for special ImDrawCallback_ResetRenderState callback to reset render state.
@ -19,12 +20,12 @@
// 2018-07-13: DirectX10: Fixed unreleased resources in Init and Shutdown functions. // 2018-07-13: DirectX10: Fixed unreleased resources in Init and Shutdown functions.
// 2018-06-08: Misc: Extracted imgui_impl_dx10.cpp/.h away from the old combined DX10+Win32 example. // 2018-06-08: Misc: Extracted imgui_impl_dx10.cpp/.h away from the old combined DX10+Win32 example.
// 2018-06-08: DirectX10: Use draw_data->DisplayPos and draw_data->DisplaySize to setup projection matrix and clipping rectangle. // 2018-06-08: DirectX10: Use draw_data->DisplayPos and draw_data->DisplaySize to setup projection matrix and clipping rectangle.
// 2018-04-09: Misc: Fixed erroneous call to io.Fonts->ClearInputData() + ClearTexData() that was left in DX10 example but removed in 1.47 (Nov 2015) on other back-ends. // 2018-04-09: Misc: Fixed erroneous call to io.Fonts->ClearInputData() + ClearTexData() that was left in DX10 example but removed in 1.47 (Nov 2015) on other backends.
// 2018-02-16: Misc: Obsoleted the io.RenderDrawListsFn callback and exposed ImGui_ImplDX10_RenderDrawData() in the .h file so you can call it yourself. // 2018-02-16: Misc: Obsoleted the io.RenderDrawListsFn callback and exposed ImGui_ImplDX10_RenderDrawData() in the .h file so you can call it yourself.
// 2018-02-06: Misc: Removed call to ImGui::Shutdown() which is not available from 1.60 WIP, user needs to call CreateContext/DestroyContext themselves. // 2018-02-06: Misc: Removed call to ImGui::Shutdown() which is not available from 1.60 WIP, user needs to call CreateContext/DestroyContext themselves.
// 2016-05-07: DirectX10: Disabling depth-write. // 2016-05-07: DirectX10: Disabling depth-write.
#include "../../imgui.h" #include "imgui.h"
#include "imgui_impl_dx10.h" #include "imgui_impl_dx10.h"
// DirectX // DirectX
@ -88,7 +89,6 @@ static void ImGui_ImplDX10_SetupRenderState(ImDrawData* draw_data, ID3D10Device*
} }
// Render function // Render function
// (this used to be set in io.RenderDrawListsFn and called by ImGui::Render(), but you can now call this directly from your main loop)
void ImGui_ImplDX10_RenderDrawData(ImDrawData* draw_data) void ImGui_ImplDX10_RenderDrawData(ImDrawData* draw_data)
{ {
// Avoid rendering when minimized // Avoid rendering when minimized
@ -291,6 +291,7 @@ static void ImGui_ImplDX10_CreateFontsTexture()
subResource.SysMemPitch = desc.Width * 4; subResource.SysMemPitch = desc.Width * 4;
subResource.SysMemSlicePitch = 0; subResource.SysMemSlicePitch = 0;
g_pd3dDevice->CreateTexture2D(&desc, &subResource, &pTexture); g_pd3dDevice->CreateTexture2D(&desc, &subResource, &pTexture);
IM_ASSERT(pTexture != NULL);
// Create texture view // Create texture view
D3D10_SHADER_RESOURCE_VIEW_DESC srv_desc; D3D10_SHADER_RESOURCE_VIEW_DESC srv_desc;
@ -304,7 +305,7 @@ static void ImGui_ImplDX10_CreateFontsTexture()
} }
// Store our identifier // Store our identifier
io.Fonts->TexID = (ImTextureID)g_pFontTextureView; io.Fonts->SetTexID((ImTextureID)g_pFontTextureView);
// Create texture sampler // Create texture sampler
{ {
@ -378,8 +379,8 @@ bool ImGui_ImplDX10_CreateDeviceObjects()
desc.SrcBlend = D3D10_BLEND_SRC_ALPHA; desc.SrcBlend = D3D10_BLEND_SRC_ALPHA;
desc.DestBlend = D3D10_BLEND_INV_SRC_ALPHA; desc.DestBlend = D3D10_BLEND_INV_SRC_ALPHA;
desc.BlendOp = D3D10_BLEND_OP_ADD; desc.BlendOp = D3D10_BLEND_OP_ADD;
desc.SrcBlendAlpha = D3D10_BLEND_INV_SRC_ALPHA; desc.SrcBlendAlpha = D3D10_BLEND_ONE;
desc.DestBlendAlpha = D3D10_BLEND_ZERO; desc.DestBlendAlpha = D3D10_BLEND_INV_SRC_ALPHA;
desc.BlendOpAlpha = D3D10_BLEND_OP_ADD; desc.BlendOpAlpha = D3D10_BLEND_OP_ADD;
desc.RenderTargetWriteMask[0] = D3D10_COLOR_WRITE_ENABLE_ALL; desc.RenderTargetWriteMask[0] = D3D10_COLOR_WRITE_ENABLE_ALL;
g_pd3dDevice->CreateBlendState(&desc, &g_pBlendState); g_pd3dDevice->CreateBlendState(&desc, &g_pBlendState);
@ -421,7 +422,7 @@ void ImGui_ImplDX10_InvalidateDeviceObjects()
return; return;
if (g_pFontSampler) { g_pFontSampler->Release(); g_pFontSampler = NULL; } if (g_pFontSampler) { g_pFontSampler->Release(); g_pFontSampler = NULL; }
if (g_pFontTextureView) { g_pFontTextureView->Release(); g_pFontTextureView = NULL; ImGui::GetIO().Fonts->TexID = NULL; } // We copied g_pFontTextureView to io.Fonts->TexID so let's clear that as well. if (g_pFontTextureView) { g_pFontTextureView->Release(); g_pFontTextureView = NULL; ImGui::GetIO().Fonts->SetTexID(NULL); } // We copied g_pFontTextureView to io.Fonts->TexID so let's clear that as well.
if (g_pIB) { g_pIB->Release(); g_pIB = NULL; } if (g_pIB) { g_pIB->Release(); g_pIB = NULL; }
if (g_pVB) { g_pVB->Release(); g_pVB = NULL; } if (g_pVB) { g_pVB->Release(); g_pVB = NULL; }
@ -436,7 +437,7 @@ void ImGui_ImplDX10_InvalidateDeviceObjects()
bool ImGui_ImplDX10_Init(ID3D10Device* device) bool ImGui_ImplDX10_Init(ID3D10Device* device)
{ {
// Setup back-end capabilities flags // Setup backend capabilities flags
ImGuiIO& io = ImGui::GetIO(); ImGuiIO& io = ImGui::GetIO();
io.BackendRendererName = "imgui_impl_dx10"; io.BackendRendererName = "imgui_impl_dx10";
io.BackendFlags |= ImGuiBackendFlags_RendererHasVtxOffset; // We can honor the ImDrawCmd::VtxOffset field, allowing for large meshes. io.BackendFlags |= ImGuiBackendFlags_RendererHasVtxOffset; // We can honor the ImDrawCmd::VtxOffset field, allowing for large meshes.

View File

@ -1,16 +1,16 @@
// dear imgui: Renderer for DirectX10 // dear imgui: Renderer Backend for DirectX10
// This needs to be used along with a Platform Binding (e.g. Win32) // This needs to be used along with a Platform Backend (e.g. Win32)
// Implemented features: // Implemented features:
// [X] Renderer: User texture binding. Use 'ID3D10ShaderResourceView*' as ImTextureID. Read the FAQ about ImTextureID! // [X] Renderer: User texture backend. Use 'ID3D10ShaderResourceView*' as ImTextureID. Read the FAQ about ImTextureID!
// [X] Renderer: Support for large meshes (64k+ vertices) with 16-bit indices. // [X] Renderer: Support for large meshes (64k+ vertices) with 16-bit indices.
// You can copy and use unmodified imgui_impl_* files in your project. See main.cpp for an example of using this. // You can copy and use unmodified imgui_impl_* files in your project. See examples/ folder for examples of using this.
// If you are new to dear imgui, read examples/README.txt and read the documentation at the top of imgui.cpp. // If you are new to Dear ImGui, read documentation from the docs/ folder + read the top of imgui.cpp.
// https://github.com/ocornut/imgui // Read online: https://github.com/ocornut/imgui/tree/master/docs
#pragma once #pragma once
#include "../../imgui.h" // IMGUI_IMPL_API #include "imgui.h" // IMGUI_IMPL_API
struct ID3D10Device; struct ID3D10Device;

View File

@ -1,16 +1,17 @@
// dear imgui: Renderer for DirectX11 // dear imgui: Renderer Backend for DirectX11
// This needs to be used along with a Platform Binding (e.g. Win32) // This needs to be used along with a Platform Backend (e.g. Win32)
// Implemented features: // Implemented features:
// [X] Renderer: User texture binding. Use 'ID3D11ShaderResourceView*' as ImTextureID. Read the FAQ about ImTextureID! // [X] Renderer: User texture binding. Use 'ID3D11ShaderResourceView*' as ImTextureID. Read the FAQ about ImTextureID!
// [X] Renderer: Support for large meshes (64k+ vertices) with 16-bit indices. // [X] Renderer: Support for large meshes (64k+ vertices) with 16-bit indices.
// You can copy and use unmodified imgui_impl_* files in your project. See main.cpp for an example of using this. // You can copy and use unmodified imgui_impl_* files in your project. See examples/ folder for examples of using this.
// If you are new to dear imgui, read examples/README.txt and read the documentation at the top of imgui.cpp // If you are new to Dear ImGui, read documentation from the docs/ folder + read the top of imgui.cpp.
// https://github.com/ocornut/imgui // Read online: https://github.com/ocornut/imgui/tree/master/docs
// CHANGELOG // CHANGELOG
// (minor and older changes stripped away, please see git history for details) // (minor and older changes stripped away, please see git history for details)
// 2021-02-18: DirectX11: Change blending equation to preserve alpha in output buffer.
// 2019-08-01: DirectX11: Fixed code querying the Geometry Shader state (would generally error with Debug layer enabled). // 2019-08-01: DirectX11: Fixed code querying the Geometry Shader state (would generally error with Debug layer enabled).
// 2019-07-21: DirectX11: Backup, clear and restore Geometry Shader is any is bound when calling ImGui_ImplDX10_RenderDrawData. Clearing Hull/Domain/Compute shaders without backup/restore. // 2019-07-21: DirectX11: Backup, clear and restore Geometry Shader is any is bound when calling ImGui_ImplDX10_RenderDrawData. Clearing Hull/Domain/Compute shaders without backup/restore.
// 2019-05-29: DirectX11: Added support for large mesh (64K+ vertices), enable ImGuiBackendFlags_RendererHasVtxOffset flag. // 2019-05-29: DirectX11: Added support for large mesh (64K+ vertices), enable ImGuiBackendFlags_RendererHasVtxOffset flag.
@ -25,7 +26,7 @@
// 2018-02-06: Misc: Removed call to ImGui::Shutdown() which is not available from 1.60 WIP, user needs to call CreateContext/DestroyContext themselves. // 2018-02-06: Misc: Removed call to ImGui::Shutdown() which is not available from 1.60 WIP, user needs to call CreateContext/DestroyContext themselves.
// 2016-05-07: DirectX11: Disabling depth-write. // 2016-05-07: DirectX11: Disabling depth-write.
#include "../../imgui.h" #include "imgui.h"
#include "imgui_impl_dx11.h" #include "imgui_impl_dx11.h"
// DirectX // DirectX
@ -92,7 +93,6 @@ static void ImGui_ImplDX11_SetupRenderState(ImDrawData* draw_data, ID3D11DeviceC
} }
// Render function // Render function
// (this used to be set in io.RenderDrawListsFn and called by ImGui::Render(), but you can now call this directly from your main loop)
void ImGui_ImplDX11_RenderDrawData(ImDrawData* draw_data) void ImGui_ImplDX11_RenderDrawData(ImDrawData* draw_data)
{ {
// Avoid rendering when minimized // Avoid rendering when minimized
@ -303,6 +303,7 @@ static void ImGui_ImplDX11_CreateFontsTexture()
subResource.SysMemPitch = desc.Width * 4; subResource.SysMemPitch = desc.Width * 4;
subResource.SysMemSlicePitch = 0; subResource.SysMemSlicePitch = 0;
g_pd3dDevice->CreateTexture2D(&desc, &subResource, &pTexture); g_pd3dDevice->CreateTexture2D(&desc, &subResource, &pTexture);
IM_ASSERT(pTexture != NULL);
// Create texture view // Create texture view
D3D11_SHADER_RESOURCE_VIEW_DESC srvDesc; D3D11_SHADER_RESOURCE_VIEW_DESC srvDesc;
@ -316,7 +317,7 @@ static void ImGui_ImplDX11_CreateFontsTexture()
} }
// Store our identifier // Store our identifier
io.Fonts->TexID = (ImTextureID)g_pFontTextureView; io.Fonts->SetTexID((ImTextureID)g_pFontTextureView);
// Create texture sampler // Create texture sampler
{ {
@ -503,8 +504,8 @@ bool ImGui_ImplDX11_CreateDeviceObjects()
desc.RenderTarget[0].SrcBlend = D3D11_BLEND_SRC_ALPHA; desc.RenderTarget[0].SrcBlend = D3D11_BLEND_SRC_ALPHA;
desc.RenderTarget[0].DestBlend = D3D11_BLEND_INV_SRC_ALPHA; desc.RenderTarget[0].DestBlend = D3D11_BLEND_INV_SRC_ALPHA;
desc.RenderTarget[0].BlendOp = D3D11_BLEND_OP_ADD; desc.RenderTarget[0].BlendOp = D3D11_BLEND_OP_ADD;
desc.RenderTarget[0].SrcBlendAlpha = D3D11_BLEND_INV_SRC_ALPHA; desc.RenderTarget[0].SrcBlendAlpha = D3D11_BLEND_ONE;
desc.RenderTarget[0].DestBlendAlpha = D3D11_BLEND_ZERO; desc.RenderTarget[0].DestBlendAlpha = D3D11_BLEND_INV_SRC_ALPHA;
desc.RenderTarget[0].BlendOpAlpha = D3D11_BLEND_OP_ADD; desc.RenderTarget[0].BlendOpAlpha = D3D11_BLEND_OP_ADD;
desc.RenderTarget[0].RenderTargetWriteMask = D3D11_COLOR_WRITE_ENABLE_ALL; desc.RenderTarget[0].RenderTargetWriteMask = D3D11_COLOR_WRITE_ENABLE_ALL;
g_pd3dDevice->CreateBlendState(&desc, &g_pBlendState); g_pd3dDevice->CreateBlendState(&desc, &g_pBlendState);
@ -546,7 +547,7 @@ void ImGui_ImplDX11_InvalidateDeviceObjects()
return; return;
if (g_pFontSampler) { g_pFontSampler->Release(); g_pFontSampler = NULL; } if (g_pFontSampler) { g_pFontSampler->Release(); g_pFontSampler = NULL; }
if (g_pFontTextureView) { g_pFontTextureView->Release(); g_pFontTextureView = NULL; ImGui::GetIO().Fonts->TexID = NULL; } // We copied g_pFontTextureView to io.Fonts->TexID so let's clear that as well. if (g_pFontTextureView) { g_pFontTextureView->Release(); g_pFontTextureView = NULL; ImGui::GetIO().Fonts->SetTexID(NULL); } // We copied g_pFontTextureView to io.Fonts->TexID so let's clear that as well.
if (g_pIB) { g_pIB->Release(); g_pIB = NULL; } if (g_pIB) { g_pIB->Release(); g_pIB = NULL; }
if (g_pVB) { g_pVB->Release(); g_pVB = NULL; } if (g_pVB) { g_pVB->Release(); g_pVB = NULL; }
@ -561,7 +562,7 @@ void ImGui_ImplDX11_InvalidateDeviceObjects()
bool ImGui_ImplDX11_Init(ID3D11Device* device, ID3D11DeviceContext* device_context) bool ImGui_ImplDX11_Init(ID3D11Device* device, ID3D11DeviceContext* device_context)
{ {
// Setup back-end capabilities flags // Setup backend capabilities flags
ImGuiIO& io = ImGui::GetIO(); ImGuiIO& io = ImGui::GetIO();
io.BackendRendererName = "imgui_impl_dx11"; io.BackendRendererName = "imgui_impl_dx11";
io.BackendFlags |= ImGuiBackendFlags_RendererHasVtxOffset; // We can honor the ImDrawCmd::VtxOffset field, allowing for large meshes. io.BackendFlags |= ImGuiBackendFlags_RendererHasVtxOffset; // We can honor the ImDrawCmd::VtxOffset field, allowing for large meshes.

View File

@ -1,16 +1,16 @@
// dear imgui: Renderer for DirectX11 // dear imgui: Renderer Backend for DirectX11
// This needs to be used along with a Platform Binding (e.g. Win32) // This needs to be used along with a Platform Backend (e.g. Win32)
// Implemented features: // Implemented features:
// [X] Renderer: User texture binding. Use 'ID3D11ShaderResourceView*' as ImTextureID. Read the FAQ about ImTextureID! // [X] Renderer: User texture binding. Use 'ID3D11ShaderResourceView*' as ImTextureID. Read the FAQ about ImTextureID!
// [X] Renderer: Support for large meshes (64k+ vertices) with 16-bit indices. // [X] Renderer: Support for large meshes (64k+ vertices) with 16-bit indices.
// You can copy and use unmodified imgui_impl_* files in your project. See main.cpp for an example of using this. // You can copy and use unmodified imgui_impl_* files in your project. See examples/ folder for examples of using this.
// If you are new to dear imgui, read examples/README.txt and read the documentation at the top of imgui.cpp. // If you are new to Dear ImGui, read documentation from the docs/ folder + read the top of imgui.cpp.
// https://github.com/ocornut/imgui // Read online: https://github.com/ocornut/imgui/tree/master/docs
#pragma once #pragma once
#include "../../imgui.h" // IMGUI_IMPL_API #include "imgui.h" // IMGUI_IMPL_API
struct ID3D11Device; struct ID3D11Device;
struct ID3D11DeviceContext; struct ID3D11DeviceContext;

View File

@ -15,6 +15,7 @@
// CHANGELOG // CHANGELOG
// (minor and older changes stripped away, please see git history for details) // (minor and older changes stripped away, please see git history for details)
// 2021-02-18: DirectX12: Change blending equation to preserve alpha in output buffer.
// 2021-01-11: DirectX12: Improve Windows 7 compatibility (for D3D12On7) by loading d3d12.dll dynamically. // 2021-01-11: DirectX12: Improve Windows 7 compatibility (for D3D12On7) by loading d3d12.dll dynamically.
// 2020-09-16: DirectX12: Avoid rendering calls with zero-sized scissor rectangle since it generates a validation layer warning. // 2020-09-16: DirectX12: Avoid rendering calls with zero-sized scissor rectangle since it generates a validation layer warning.
// 2020-09-08: DirectX12: Clarified support for building on 32-bit systems by redefining ImTextureID. // 2020-09-08: DirectX12: Clarified support for building on 32-bit systems by redefining ImTextureID.
@ -29,7 +30,7 @@
// 2018-06-08: DirectX12: Use draw_data->DisplayPos and draw_data->DisplaySize to setup projection matrix and clipping rectangle (to ease support for future multi-viewport). // 2018-06-08: DirectX12: Use draw_data->DisplayPos and draw_data->DisplaySize to setup projection matrix and clipping rectangle (to ease support for future multi-viewport).
// 2018-02-22: Merged into master with all Win32 code synchronized to other examples. // 2018-02-22: Merged into master with all Win32 code synchronized to other examples.
#include "../../imgui.h" #include "imgui.h"
#include "imgui_impl_dx12.h" #include "imgui_impl_dx12.h"
// DirectX // DirectX
@ -393,7 +394,7 @@ static void ImGui_ImplDX12_CreateFontsTexture()
// Store our identifier // Store our identifier
static_assert(sizeof(ImTextureID) >= sizeof(g_hFontSrvGpuDescHandle.ptr), "Can't pack descriptor handle into TexID, 32-bit not supported yet."); static_assert(sizeof(ImTextureID) >= sizeof(g_hFontSrvGpuDescHandle.ptr), "Can't pack descriptor handle into TexID, 32-bit not supported yet.");
io.Fonts->TexID = (ImTextureID)g_hFontSrvGpuDescHandle.ptr; io.Fonts->SetTexID((ImTextureID)g_hFontSrvGpuDescHandle.ptr);
} }
bool ImGui_ImplDX12_CreateDeviceObjects() bool ImGui_ImplDX12_CreateDeviceObjects()
@ -529,8 +530,8 @@ bool ImGui_ImplDX12_CreateDeviceObjects()
desc.RenderTarget[0].SrcBlend = D3D12_BLEND_SRC_ALPHA; desc.RenderTarget[0].SrcBlend = D3D12_BLEND_SRC_ALPHA;
desc.RenderTarget[0].DestBlend = D3D12_BLEND_INV_SRC_ALPHA; desc.RenderTarget[0].DestBlend = D3D12_BLEND_INV_SRC_ALPHA;
desc.RenderTarget[0].BlendOp = D3D12_BLEND_OP_ADD; desc.RenderTarget[0].BlendOp = D3D12_BLEND_OP_ADD;
desc.RenderTarget[0].SrcBlendAlpha = D3D12_BLEND_INV_SRC_ALPHA; desc.RenderTarget[0].SrcBlendAlpha = D3D12_BLEND_ONE;
desc.RenderTarget[0].DestBlendAlpha = D3D12_BLEND_ZERO; desc.RenderTarget[0].DestBlendAlpha = D3D12_BLEND_INV_SRC_ALPHA;
desc.RenderTarget[0].BlendOpAlpha = D3D12_BLEND_OP_ADD; desc.RenderTarget[0].BlendOpAlpha = D3D12_BLEND_OP_ADD;
desc.RenderTarget[0].RenderTargetWriteMask = D3D12_COLOR_WRITE_ENABLE_ALL; desc.RenderTarget[0].RenderTargetWriteMask = D3D12_COLOR_WRITE_ENABLE_ALL;
} }
@ -582,7 +583,7 @@ void ImGui_ImplDX12_InvalidateDeviceObjects()
SafeRelease(g_pFontTextureResource); SafeRelease(g_pFontTextureResource);
ImGuiIO& io = ImGui::GetIO(); ImGuiIO& io = ImGui::GetIO();
io.Fonts->TexID = NULL; // We copied g_pFontTextureView to io.Fonts->TexID so let's clear that as well. io.Fonts->SetTexID(NULL); // We copied g_pFontTextureView to io.Fonts->TexID so let's clear that as well.
for (UINT i = 0; i < g_numFramesInFlight; i++) for (UINT i = 0; i < g_numFramesInFlight; i++)
{ {

View File

@ -14,7 +14,7 @@
// Read online: https://github.com/ocornut/imgui/tree/master/docs // Read online: https://github.com/ocornut/imgui/tree/master/docs
#pragma once #pragma once
#include "../../imgui.h" // IMGUI_IMPL_API #include "imgui.h" // IMGUI_IMPL_API
#ifdef _MSC_VER #ifdef _MSC_VER
#pragma warning (push) #pragma warning (push)

View File

@ -1,16 +1,20 @@
// dear imgui: Renderer for DirectX9 // dear imgui: Renderer Backend for DirectX9
// This needs to be used along with a Platform Binding (e.g. Win32) // This needs to be used along with a Platform Backend (e.g. Win32)
// Implemented features: // Implemented features:
// [X] Renderer: User texture binding. Use 'LPDIRECT3DTEXTURE9' as ImTextureID. Read the FAQ about ImTextureID! // [X] Renderer: User texture binding. Use 'LPDIRECT3DTEXTURE9' as ImTextureID. Read the FAQ about ImTextureID!
// [X] Renderer: Support for large meshes (64k+ vertices) with 16-bit indices. // [X] Renderer: Support for large meshes (64k+ vertices) with 16-bit indices.
// You can copy and use unmodified imgui_impl_* files in your project. See main.cpp for an example of using this. // You can copy and use unmodified imgui_impl_* files in your project. See examples/ folder for examples of using this.
// If you are new to dear imgui, read examples/README.txt and read the documentation at the top of imgui.cpp. // If you are new to Dear ImGui, read documentation from the docs/ folder + read the top of imgui.cpp.
// https://github.com/ocornut/imgui // Read online: https://github.com/ocornut/imgui/tree/master/docs
// CHANGELOG // CHANGELOG
// (minor and older changes stripped away, please see git history for details) // (minor and older changes stripped away, please see git history for details)
// 2021-04-23: DirectX9: Explicitly setting up more graphics states to increase compatibility with unusual non-default states.
// 2021-03-18: DirectX9: Calling IDirect3DStateBlock9::Capture() after CreateStateBlock() as a workaround for state restoring issues (see #3857).
// 2021-03-03: DirectX9: Added support for IMGUI_USE_BGRA_PACKED_COLOR in user's imconfig file.
// 2021-02-18: DirectX9: Change blending equation to preserve alpha in output buffer.
// 2019-05-29: DirectX9: Added support for large mesh (64K+ vertices), enable ImGuiBackendFlags_RendererHasVtxOffset flag. // 2019-05-29: DirectX9: Added support for large mesh (64K+ vertices), enable ImGuiBackendFlags_RendererHasVtxOffset flag.
// 2019-04-30: DirectX9: Added support for special ImDrawCallback_ResetRenderState callback to reset render state. // 2019-04-30: DirectX9: Added support for special ImDrawCallback_ResetRenderState callback to reset render state.
// 2019-03-29: Misc: Fixed erroneous assert in ImGui_ImplDX9_InvalidateDeviceObjects(). // 2019-03-29: Misc: Fixed erroneous assert in ImGui_ImplDX9_InvalidateDeviceObjects().
@ -22,13 +26,11 @@
// 2018-02-16: Misc: Obsoleted the io.RenderDrawListsFn callback and exposed ImGui_ImplDX9_RenderDrawData() in the .h file so you can call it yourself. // 2018-02-16: Misc: Obsoleted the io.RenderDrawListsFn callback and exposed ImGui_ImplDX9_RenderDrawData() in the .h file so you can call it yourself.
// 2018-02-06: Misc: Removed call to ImGui::Shutdown() which is not available from 1.60 WIP, user needs to call CreateContext/DestroyContext themselves. // 2018-02-06: Misc: Removed call to ImGui::Shutdown() which is not available from 1.60 WIP, user needs to call CreateContext/DestroyContext themselves.
#include "../../imgui.h" #include "imgui.h"
#include "imgui_impl_dx9.h" #include "imgui_impl_dx9.h"
// DirectX // DirectX
#include <d3d9.h> #include <d3d9.h>
#define DIRECTINPUT_VERSION 0x0800
#include <dinput.h>
// DirectX data // DirectX data
static LPDIRECT3DDEVICE9 g_pd3dDevice = NULL; static LPDIRECT3DDEVICE9 g_pd3dDevice = NULL;
@ -45,6 +47,12 @@ struct CUSTOMVERTEX
}; };
#define D3DFVF_CUSTOMVERTEX (D3DFVF_XYZ|D3DFVF_DIFFUSE|D3DFVF_TEX1) #define D3DFVF_CUSTOMVERTEX (D3DFVF_XYZ|D3DFVF_DIFFUSE|D3DFVF_TEX1)
#ifdef IMGUI_USE_BGRA_PACKED_COLOR
#define IMGUI_COL_TO_DX9_ARGB(_COL) (_COL)
#else
#define IMGUI_COL_TO_DX9_ARGB(_COL) (((_COL) & 0xFF00FF00) | (((_COL) & 0xFF0000) >> 16) | (((_COL) & 0xFF) << 16))
#endif
static void ImGui_ImplDX9_SetupRenderState(ImDrawData* draw_data) static void ImGui_ImplDX9_SetupRenderState(ImDrawData* draw_data)
{ {
// Setup viewport // Setup viewport
@ -59,17 +67,26 @@ static void ImGui_ImplDX9_SetupRenderState(ImDrawData* draw_data)
// Setup render state: fixed-pipeline, alpha-blending, no face culling, no depth testing, shade mode (for gradient) // Setup render state: fixed-pipeline, alpha-blending, no face culling, no depth testing, shade mode (for gradient)
g_pd3dDevice->SetPixelShader(NULL); g_pd3dDevice->SetPixelShader(NULL);
g_pd3dDevice->SetVertexShader(NULL); g_pd3dDevice->SetVertexShader(NULL);
g_pd3dDevice->SetRenderState(D3DRS_FILLMODE, D3DFILL_SOLID);
g_pd3dDevice->SetRenderState(D3DRS_SHADEMODE, D3DSHADE_GOURAUD);
g_pd3dDevice->SetRenderState(D3DRS_ZWRITEENABLE, FALSE);
g_pd3dDevice->SetRenderState(D3DRS_ALPHATESTENABLE, FALSE);
g_pd3dDevice->SetRenderState(D3DRS_CULLMODE, D3DCULL_NONE); g_pd3dDevice->SetRenderState(D3DRS_CULLMODE, D3DCULL_NONE);
g_pd3dDevice->SetRenderState(D3DRS_LIGHTING, FALSE);
g_pd3dDevice->SetRenderState(D3DRS_ZENABLE, FALSE); g_pd3dDevice->SetRenderState(D3DRS_ZENABLE, FALSE);
g_pd3dDevice->SetRenderState(D3DRS_ALPHABLENDENABLE, TRUE); g_pd3dDevice->SetRenderState(D3DRS_ALPHABLENDENABLE, TRUE);
g_pd3dDevice->SetRenderState(D3DRS_ALPHATESTENABLE, FALSE);
g_pd3dDevice->SetRenderState(D3DRS_BLENDOP, D3DBLENDOP_ADD); g_pd3dDevice->SetRenderState(D3DRS_BLENDOP, D3DBLENDOP_ADD);
g_pd3dDevice->SetRenderState(D3DRS_SRCBLEND, D3DBLEND_SRCALPHA); g_pd3dDevice->SetRenderState(D3DRS_SRCBLEND, D3DBLEND_SRCALPHA);
g_pd3dDevice->SetRenderState(D3DRS_DESTBLEND, D3DBLEND_INVSRCALPHA); g_pd3dDevice->SetRenderState(D3DRS_DESTBLEND, D3DBLEND_INVSRCALPHA);
g_pd3dDevice->SetRenderState(D3DRS_SEPARATEALPHABLENDENABLE, TRUE);
g_pd3dDevice->SetRenderState(D3DRS_SRCBLENDALPHA, D3DBLEND_ONE);
g_pd3dDevice->SetRenderState(D3DRS_DESTBLENDALPHA, D3DBLEND_INVSRCALPHA);
g_pd3dDevice->SetRenderState(D3DRS_SCISSORTESTENABLE, TRUE); g_pd3dDevice->SetRenderState(D3DRS_SCISSORTESTENABLE, TRUE);
g_pd3dDevice->SetRenderState(D3DRS_SHADEMODE, D3DSHADE_GOURAUD);
g_pd3dDevice->SetRenderState(D3DRS_FOGENABLE, FALSE); g_pd3dDevice->SetRenderState(D3DRS_FOGENABLE, FALSE);
g_pd3dDevice->SetRenderState(D3DRS_RANGEFOGENABLE, FALSE);
g_pd3dDevice->SetRenderState(D3DRS_SPECULARENABLE, FALSE);
g_pd3dDevice->SetRenderState(D3DRS_STENCILENABLE, FALSE);
g_pd3dDevice->SetRenderState(D3DRS_CLIPPING, TRUE);
g_pd3dDevice->SetRenderState(D3DRS_LIGHTING, FALSE);
g_pd3dDevice->SetTextureStageState(0, D3DTSS_COLOROP, D3DTOP_MODULATE); g_pd3dDevice->SetTextureStageState(0, D3DTSS_COLOROP, D3DTOP_MODULATE);
g_pd3dDevice->SetTextureStageState(0, D3DTSS_COLORARG1, D3DTA_TEXTURE); g_pd3dDevice->SetTextureStageState(0, D3DTSS_COLORARG1, D3DTA_TEXTURE);
g_pd3dDevice->SetTextureStageState(0, D3DTSS_COLORARG2, D3DTA_DIFFUSE); g_pd3dDevice->SetTextureStageState(0, D3DTSS_COLORARG2, D3DTA_DIFFUSE);
@ -102,7 +119,6 @@ static void ImGui_ImplDX9_SetupRenderState(ImDrawData* draw_data)
} }
// Render function. // Render function.
// (this used to be set in io.RenderDrawListsFn and called by ImGui::Render(), but you can now call this directly from your main loop)
void ImGui_ImplDX9_RenderDrawData(ImDrawData* draw_data) void ImGui_ImplDX9_RenderDrawData(ImDrawData* draw_data)
{ {
// Avoid rendering when minimized // Avoid rendering when minimized
@ -129,24 +145,37 @@ void ImGui_ImplDX9_RenderDrawData(ImDrawData* draw_data)
IDirect3DStateBlock9* d3d9_state_block = NULL; IDirect3DStateBlock9* d3d9_state_block = NULL;
if (g_pd3dDevice->CreateStateBlock(D3DSBT_ALL, &d3d9_state_block) < 0) if (g_pd3dDevice->CreateStateBlock(D3DSBT_ALL, &d3d9_state_block) < 0)
return; return;
if (d3d9_state_block->Capture() < 0)
{
d3d9_state_block->Release();
return;
}
d3d9_state_block->Capture();
// Backup the DX9 transform (DX9 documentation suggests that it is included in the StateBlock but it doesn't appear to) // Backup the DX9 transform (DX9 documentation suggests that it is included in the StateBlock but it doesn't appear to)
D3DMATRIX last_world, last_view, last_projection; D3DMATRIX last_world, last_view, last_projection;
g_pd3dDevice->GetTransform(D3DTS_WORLD, &last_world); g_pd3dDevice->GetTransform(D3DTS_WORLD, &last_world);
g_pd3dDevice->GetTransform(D3DTS_VIEW, &last_view); g_pd3dDevice->GetTransform(D3DTS_VIEW, &last_view);
g_pd3dDevice->GetTransform(D3DTS_PROJECTION, &last_projection); g_pd3dDevice->GetTransform(D3DTS_PROJECTION, &last_projection);
// Copy and convert all vertices into a single contiguous buffer, convert colors to DX9 default format. // Allocate buffers
// FIXME-OPT: This is a waste of resource, the ideal is to use imconfig.h and
// 1) to avoid repacking colors: #define IMGUI_USE_BGRA_PACKED_COLOR
// 2) to avoid repacking vertices: #define IMGUI_OVERRIDE_DRAWVERT_STRUCT_LAYOUT struct ImDrawVert { ImVec2 pos; float z; ImU32 col; ImVec2 uv; }
CUSTOMVERTEX* vtx_dst; CUSTOMVERTEX* vtx_dst;
ImDrawIdx* idx_dst; ImDrawIdx* idx_dst;
if (g_pVB->Lock(0, (UINT)(draw_data->TotalVtxCount * sizeof(CUSTOMVERTEX)), (void**)&vtx_dst, D3DLOCK_DISCARD) < 0) if (g_pVB->Lock(0, (UINT)(draw_data->TotalVtxCount * sizeof(CUSTOMVERTEX)), (void**)&vtx_dst, D3DLOCK_DISCARD) < 0)
{
d3d9_state_block->Release();
return; return;
}
if (g_pIB->Lock(0, (UINT)(draw_data->TotalIdxCount * sizeof(ImDrawIdx)), (void**)&idx_dst, D3DLOCK_DISCARD) < 0) if (g_pIB->Lock(0, (UINT)(draw_data->TotalIdxCount * sizeof(ImDrawIdx)), (void**)&idx_dst, D3DLOCK_DISCARD) < 0)
{
g_pVB->Unlock();
d3d9_state_block->Release();
return; return;
}
// Copy and convert all vertices into a single contiguous buffer, convert colors to DX9 default format.
// FIXME-OPT: This is a minor waste of resource, the ideal is to use imconfig.h and
// 1) to avoid repacking colors: #define IMGUI_USE_BGRA_PACKED_COLOR
// 2) to avoid repacking vertices: #define IMGUI_OVERRIDE_DRAWVERT_STRUCT_LAYOUT struct ImDrawVert { ImVec2 pos; float z; ImU32 col; ImVec2 uv; }
for (int n = 0; n < draw_data->CmdListsCount; n++) for (int n = 0; n < draw_data->CmdListsCount; n++)
{ {
const ImDrawList* cmd_list = draw_data->CmdLists[n]; const ImDrawList* cmd_list = draw_data->CmdLists[n];
@ -156,7 +185,7 @@ void ImGui_ImplDX9_RenderDrawData(ImDrawData* draw_data)
vtx_dst->pos[0] = vtx_src->pos.x; vtx_dst->pos[0] = vtx_src->pos.x;
vtx_dst->pos[1] = vtx_src->pos.y; vtx_dst->pos[1] = vtx_src->pos.y;
vtx_dst->pos[2] = 0.0f; vtx_dst->pos[2] = 0.0f;
vtx_dst->col = (vtx_src->col & 0xFF00FF00) | ((vtx_src->col & 0xFF0000) >> 16) | ((vtx_src->col & 0xFF) << 16); // RGBA --> ARGB for DirectX9 vtx_dst->col = IMGUI_COL_TO_DX9_ARGB(vtx_src->col);
vtx_dst->uv[0] = vtx_src->uv.x; vtx_dst->uv[0] = vtx_src->uv.x;
vtx_dst->uv[1] = vtx_src->uv.y; vtx_dst->uv[1] = vtx_src->uv.y;
vtx_dst++; vtx_dst++;
@ -219,7 +248,7 @@ void ImGui_ImplDX9_RenderDrawData(ImDrawData* draw_data)
bool ImGui_ImplDX9_Init(IDirect3DDevice9* device) bool ImGui_ImplDX9_Init(IDirect3DDevice9* device)
{ {
// Setup back-end capabilities flags // Setup backend capabilities flags
ImGuiIO& io = ImGui::GetIO(); ImGuiIO& io = ImGui::GetIO();
io.BackendRendererName = "imgui_impl_dx9"; io.BackendRendererName = "imgui_impl_dx9";
io.BackendFlags |= ImGuiBackendFlags_RendererHasVtxOffset; // We can honor the ImDrawCmd::VtxOffset field, allowing for large meshes. io.BackendFlags |= ImGuiBackendFlags_RendererHasVtxOffset; // We can honor the ImDrawCmd::VtxOffset field, allowing for large meshes.
@ -243,6 +272,17 @@ static bool ImGui_ImplDX9_CreateFontsTexture()
int width, height, bytes_per_pixel; int width, height, bytes_per_pixel;
io.Fonts->GetTexDataAsRGBA32(&pixels, &width, &height, &bytes_per_pixel); io.Fonts->GetTexDataAsRGBA32(&pixels, &width, &height, &bytes_per_pixel);
// Convert RGBA32 to BGRA32 (because RGBA32 is not well supported by DX9 devices)
#ifndef IMGUI_USE_BGRA_PACKED_COLOR
if (io.Fonts->TexPixelsUseColors)
{
ImU32* dst_start = (ImU32*)ImGui::MemAlloc(width * height * bytes_per_pixel);
for (ImU32* src = (ImU32*)pixels, *dst = dst_start, *dst_end = dst_start + width * height; dst < dst_end; src++, dst++)
*dst = IMGUI_COL_TO_DX9_ARGB(*src);
pixels = (unsigned char*)dst_start;
}
#endif
// Upload texture to graphics system // Upload texture to graphics system
g_FontTexture = NULL; g_FontTexture = NULL;
if (g_pd3dDevice->CreateTexture(width, height, 1, D3DUSAGE_DYNAMIC, D3DFMT_A8R8G8B8, D3DPOOL_DEFAULT, &g_FontTexture, NULL) < 0) if (g_pd3dDevice->CreateTexture(width, height, 1, D3DUSAGE_DYNAMIC, D3DFMT_A8R8G8B8, D3DPOOL_DEFAULT, &g_FontTexture, NULL) < 0)
@ -255,7 +295,12 @@ static bool ImGui_ImplDX9_CreateFontsTexture()
g_FontTexture->UnlockRect(0); g_FontTexture->UnlockRect(0);
// Store our identifier // Store our identifier
io.Fonts->TexID = (ImTextureID)g_FontTexture; io.Fonts->SetTexID((ImTextureID)g_FontTexture);
#ifndef IMGUI_USE_BGRA_PACKED_COLOR
if (io.Fonts->TexPixelsUseColors)
ImGui::MemFree(pixels);
#endif
return true; return true;
} }
@ -275,7 +320,7 @@ void ImGui_ImplDX9_InvalidateDeviceObjects()
return; return;
if (g_pVB) { g_pVB->Release(); g_pVB = NULL; } if (g_pVB) { g_pVB->Release(); g_pVB = NULL; }
if (g_pIB) { g_pIB->Release(); g_pIB = NULL; } if (g_pIB) { g_pIB->Release(); g_pIB = NULL; }
if (g_FontTexture) { g_FontTexture->Release(); g_FontTexture = NULL; ImGui::GetIO().Fonts->TexID = NULL; } // We copied g_pFontTextureView to io.Fonts->TexID so let's clear that as well. if (g_FontTexture) { g_FontTexture->Release(); g_FontTexture = NULL; ImGui::GetIO().Fonts->SetTexID(NULL); } // We copied g_pFontTextureView to io.Fonts->TexID so let's clear that as well.
} }
bool ImGui_ImplDX9_NewFrame() bool ImGui_ImplDX9_NewFrame()

View File

@ -1,16 +1,16 @@
// dear imgui: Renderer for DirectX9 // dear imgui: Renderer Backend for DirectX9
// This needs to be used along with a Platform Binding (e.g. Win32) // This needs to be used along with a Platform Backend (e.g. Win32)
// Implemented features: // Implemented features:
// [X] Renderer: User texture binding. Use 'LPDIRECT3DTEXTURE9' as ImTextureID. Read the FAQ about ImTextureID! // [X] Renderer: User texture binding. Use 'LPDIRECT3DTEXTURE9' as ImTextureID. Read the FAQ about ImTextureID!
// [X] Renderer: Support for large meshes (64k+ vertices) with 16-bit indices. // [X] Renderer: Support for large meshes (64k+ vertices) with 16-bit indices.
// You can copy and use unmodified imgui_impl_* files in your project. See main.cpp for an example of using this. // You can copy and use unmodified imgui_impl_* files in your project. See examples/ folder for examples of using this.
// If you are new to dear imgui, read examples/README.txt and read the documentation at the top of imgui.cpp. // If you are new to Dear ImGui, read documentation from the docs/ folder + read the top of imgui.cpp.
// https://github.com/ocornut/imgui // Read online: https://github.com/ocornut/imgui/tree/master/docs
#pragma once #pragma once
#include "../../imgui.h" // IMGUI_IMPL_API #include "imgui.h" // IMGUI_IMPL_API
struct IDirect3DDevice9; struct IDirect3DDevice9;

View File

@ -1,4 +1,4 @@
// dear imgui: Platform Binding for Windows (standard windows API for 32 and 64 bits applications) // dear imgui: Platform Backend for Windows (standard windows API for 32 and 64 bits applications)
// This needs to be used along with a Renderer (e.g. DirectX11, OpenGL3, Vulkan..) // This needs to be used along with a Renderer (e.g. DirectX11, OpenGL3, Vulkan..)
// Implemented features: // Implemented features:
@ -7,27 +7,36 @@
// [X] Platform: Keyboard arrays indexed using VK_* Virtual Key Codes, e.g. ImGui::IsKeyPressed(VK_SPACE). // [X] Platform: Keyboard arrays indexed using VK_* Virtual Key Codes, e.g. ImGui::IsKeyPressed(VK_SPACE).
// [X] Platform: Gamepad support. Enabled with 'io.ConfigFlags |= ImGuiConfigFlags_NavEnableGamepad'. // [X] Platform: Gamepad support. Enabled with 'io.ConfigFlags |= ImGuiConfigFlags_NavEnableGamepad'.
#include "../../imgui.h" // You can copy and use unmodified imgui_impl_* files in your project. See examples/ folder for examples of using this.
// If you are new to Dear ImGui, read documentation from the docs/ folder + read the top of imgui.cpp.
// Read online: https://github.com/ocornut/imgui/tree/master/docs
#include "imgui.h"
#include "imgui_impl_win32.h" #include "imgui_impl_win32.h"
#ifndef WIN32_LEAN_AND_MEAN #ifndef WIN32_LEAN_AND_MEAN
#define WIN32_LEAN_AND_MEAN #define WIN32_LEAN_AND_MEAN
#endif #endif
#include <windows.h> #include <windows.h>
#include <tchar.h> #include <tchar.h>
#include <dwmapi.h>
// Using XInput library for gamepad (with recent Windows SDK this may leads to executables which won't run on Windows 7) // Configuration flags to add in your imconfig.h file:
//#define IMGUI_IMPL_WIN32_DISABLE_GAMEPAD // Disable gamepad support (this used to be meaningful before <1.81) but we know load XInput dynamically so the option is less relevant now.
// Using XInput for gamepad (will load DLL dynamically)
#ifndef IMGUI_IMPL_WIN32_DISABLE_GAMEPAD #ifndef IMGUI_IMPL_WIN32_DISABLE_GAMEPAD
#include <XInput.h> #include <xinput.h>
#else typedef DWORD (WINAPI *PFN_XInputGetCapabilities)(DWORD, DWORD, XINPUT_CAPABILITIES*);
#define IMGUI_IMPL_WIN32_DISABLE_LINKING_XINPUT typedef DWORD (WINAPI *PFN_XInputGetState)(DWORD, XINPUT_STATE*);
#endif
#if defined(_MSC_VER) && !defined(IMGUI_IMPL_WIN32_DISABLE_LINKING_XINPUT)
#pragma comment(lib, "xinput")
//#pragma comment(lib, "Xinput9_1_0")
#endif #endif
// CHANGELOG // CHANGELOG
// (minor and older changes stripped away, please see git history for details) // (minor and older changes stripped away, please see git history for details)
// 2021-03-23: Inputs: Clearing keyboard down array when losing focus (WM_KILLFOCUS).
// 2021-02-18: Added ImGui_ImplWin32_EnableAlphaCompositing(). Non Visual Studio users will need to link with dwmapi.lib (MinGW/gcc: use -ldwmapi).
// 2021-02-17: Fixed ImGui_ImplWin32_EnableDpiAwareness() attempting to get SetProcessDpiAwareness from shcore.dll on Windows 8 whereas it is only supported on Windows 8.1.
// 2021-01-25: Inputs: Dynamically loading XInput DLL.
// 2020-12-04: Misc: Fixed setting of io.DisplaySize to invalid/uninitialized data when after hwnd has been closed.
// 2020-03-03: Inputs: Calling AddInputCharacterUTF16() to support surrogate pairs leading to codepoint >= 0x10000 (for more complete CJK inputs) // 2020-03-03: Inputs: Calling AddInputCharacterUTF16() to support surrogate pairs leading to codepoint >= 0x10000 (for more complete CJK inputs)
// 2020-02-17: Added ImGui_ImplWin32_EnableDpiAwareness(), ImGui_ImplWin32_GetDpiScaleForHwnd(), ImGui_ImplWin32_GetDpiScaleForMonitor() helper functions. // 2020-02-17: Added ImGui_ImplWin32_EnableDpiAwareness(), ImGui_ImplWin32_GetDpiScaleForHwnd(), ImGui_ImplWin32_GetDpiScaleForMonitor() helper functions.
// 2020-01-14: Inputs: Added support for #define IMGUI_IMPL_WIN32_DISABLE_GAMEPAD/IMGUI_IMPL_WIN32_DISABLE_LINKING_XINPUT. // 2020-01-14: Inputs: Added support for #define IMGUI_IMPL_WIN32_DISABLE_GAMEPAD/IMGUI_IMPL_WIN32_DISABLE_LINKING_XINPUT.
@ -60,6 +69,13 @@ static ImGuiMouseCursor g_LastMouseCursor = ImGuiMouseCursor_COUNT;
static bool g_HasGamepad = false; static bool g_HasGamepad = false;
static bool g_WantUpdateHasGamepad = true; static bool g_WantUpdateHasGamepad = true;
// XInput DLL and functions
#ifndef IMGUI_IMPL_WIN32_DISABLE_GAMEPAD
static HMODULE g_XInputDLL = NULL;
static PFN_XInputGetCapabilities g_XInputGetCapabilities = NULL;
static PFN_XInputGetState g_XInputGetState = NULL;
#endif
// Functions // Functions
bool ImGui_ImplWin32_Init(void* hwnd) bool ImGui_ImplWin32_Init(void* hwnd)
{ {
@ -68,7 +84,7 @@ bool ImGui_ImplWin32_Init(void* hwnd)
if (!::QueryPerformanceCounter((LARGE_INTEGER*)&g_Time)) if (!::QueryPerformanceCounter((LARGE_INTEGER*)&g_Time))
return false; return false;
// Setup back-end capabilities flags // Setup backend capabilities flags
g_hWnd = (HWND)hwnd; g_hWnd = (HWND)hwnd;
ImGuiIO& io = ImGui::GetIO(); ImGuiIO& io = ImGui::GetIO();
io.BackendFlags |= ImGuiBackendFlags_HasMouseCursors; // We can honor GetMouseCursor() values (optional) io.BackendFlags |= ImGuiBackendFlags_HasMouseCursors; // We can honor GetMouseCursor() values (optional)
@ -76,7 +92,7 @@ bool ImGui_ImplWin32_Init(void* hwnd)
io.BackendPlatformName = "imgui_impl_win32"; io.BackendPlatformName = "imgui_impl_win32";
io.ImeWindowHandle = hwnd; io.ImeWindowHandle = hwnd;
// Keyboard mapping. ImGui will use those indices to peek into the io.KeysDown[] array that we will update during the application lifetime. // Keyboard mapping. Dear ImGui will use those indices to peek into the io.KeysDown[] array that we will update during the application lifetime.
io.KeyMap[ImGuiKey_Tab] = VK_TAB; io.KeyMap[ImGuiKey_Tab] = VK_TAB;
io.KeyMap[ImGuiKey_LeftArrow] = VK_LEFT; io.KeyMap[ImGuiKey_LeftArrow] = VK_LEFT;
io.KeyMap[ImGuiKey_RightArrow] = VK_RIGHT; io.KeyMap[ImGuiKey_RightArrow] = VK_RIGHT;
@ -100,12 +116,46 @@ bool ImGui_ImplWin32_Init(void* hwnd)
io.KeyMap[ImGuiKey_Y] = 'Y'; io.KeyMap[ImGuiKey_Y] = 'Y';
io.KeyMap[ImGuiKey_Z] = 'Z'; io.KeyMap[ImGuiKey_Z] = 'Z';
// Dynamically load XInput library
#ifndef IMGUI_IMPL_WIN32_DISABLE_GAMEPAD
const char* xinput_dll_names[] =
{
"xinput1_4.dll", // Windows 8+
"xinput1_3.dll", // DirectX SDK
"xinput9_1_0.dll", // Windows Vista, Windows 7
"xinput1_2.dll", // DirectX SDK
"xinput1_1.dll" // DirectX SDK
};
for (int n = 0; n < IM_ARRAYSIZE(xinput_dll_names); n++)
if (HMODULE dll = ::LoadLibraryA(xinput_dll_names[n]))
{
g_XInputDLL = dll;
g_XInputGetCapabilities = (PFN_XInputGetCapabilities)::GetProcAddress(dll, "XInputGetCapabilities");
g_XInputGetState = (PFN_XInputGetState)::GetProcAddress(dll, "XInputGetState");
break;
}
#endif // IMGUI_IMPL_WIN32_DISABLE_GAMEPAD
return true; return true;
} }
void ImGui_ImplWin32_Shutdown() void ImGui_ImplWin32_Shutdown()
{ {
g_hWnd = (HWND)0; // Unload XInput library
#ifndef IMGUI_IMPL_WIN32_DISABLE_GAMEPAD
if (g_XInputDLL)
::FreeLibrary(g_XInputDLL);
g_XInputDLL = NULL;
g_XInputGetCapabilities = NULL;
g_XInputGetState = NULL;
#endif // IMGUI_IMPL_WIN32_DISABLE_GAMEPAD
g_hWnd = NULL;
g_Time = 0;
g_TicksPerSecond = 0;
g_LastMouseCursor = ImGuiMouseCursor_COUNT;
g_HasGamepad = false;
g_WantUpdateHasGamepad = true;
} }
static bool ImGui_ImplWin32_UpdateMouseCursor() static bool ImGui_ImplWin32_UpdateMouseCursor()
@ -144,12 +194,13 @@ static bool ImGui_ImplWin32_UpdateMouseCursor()
static void ImGui_ImplWin32_UpdateMousePos() static void ImGui_ImplWin32_UpdateMousePos()
{ {
ImGuiIO& io = ImGui::GetIO(); ImGuiIO& io = ImGui::GetIO();
IM_ASSERT(g_hWnd != 0);
// Set OS mouse position if requested (rarely used, only when ImGuiConfigFlags_NavEnableSetMousePos is enabled by user) // Set OS mouse position if requested (rarely used, only when ImGuiConfigFlags_NavEnableSetMousePos is enabled by user)
if (io.WantSetMousePos) if (io.WantSetMousePos)
{ {
POINT pos = { (int)io.MousePos.x, (int)io.MousePos.y }; POINT pos = { (int)io.MousePos.x, (int)io.MousePos.y };
::ClientToScreen(g_hWnd, &pos); if (::ClientToScreen(g_hWnd, &pos))
::SetCursorPos(pos.x, pos.y); ::SetCursorPos(pos.x, pos.y);
} }
@ -176,13 +227,13 @@ static void ImGui_ImplWin32_UpdateGamepads()
if (g_WantUpdateHasGamepad) if (g_WantUpdateHasGamepad)
{ {
XINPUT_CAPABILITIES caps; XINPUT_CAPABILITIES caps;
g_HasGamepad = (XInputGetCapabilities(0, XINPUT_FLAG_GAMEPAD, &caps) == ERROR_SUCCESS); g_HasGamepad = g_XInputGetCapabilities ? (g_XInputGetCapabilities(0, XINPUT_FLAG_GAMEPAD, &caps) == ERROR_SUCCESS) : false;
g_WantUpdateHasGamepad = false; g_WantUpdateHasGamepad = false;
} }
XINPUT_STATE xinput_state;
io.BackendFlags &= ~ImGuiBackendFlags_HasGamepad; io.BackendFlags &= ~ImGuiBackendFlags_HasGamepad;
if (g_HasGamepad && XInputGetState(0, &xinput_state) == ERROR_SUCCESS) XINPUT_STATE xinput_state;
if (g_HasGamepad && g_XInputGetState && g_XInputGetState(0, &xinput_state) == ERROR_SUCCESS)
{ {
const XINPUT_GAMEPAD& gamepad = xinput_state.Gamepad; const XINPUT_GAMEPAD& gamepad = xinput_state.Gamepad;
io.BackendFlags |= ImGuiBackendFlags_HasGamepad; io.BackendFlags |= ImGuiBackendFlags_HasGamepad;
@ -214,15 +265,15 @@ static void ImGui_ImplWin32_UpdateGamepads()
void ImGui_ImplWin32_NewFrame() void ImGui_ImplWin32_NewFrame()
{ {
ImGuiIO& io = ImGui::GetIO(); ImGuiIO& io = ImGui::GetIO();
IM_ASSERT(io.Fonts->IsBuilt() && "Font atlas not built! It is generally built by the renderer back-end. Missing call to renderer _NewFrame() function? e.g. ImGui_ImplOpenGL3_NewFrame()."); IM_ASSERT(io.Fonts->IsBuilt() && "Font atlas not built! It is generally built by the renderer backend. Missing call to renderer _NewFrame() function? e.g. ImGui_ImplOpenGL3_NewFrame().");
// Setup display size (every frame to accommodate for window resizing) // Setup display size (every frame to accommodate for window resizing)
RECT rect; RECT rect = { 0, 0, 0, 0 };
::GetClientRect(g_hWnd, &rect); ::GetClientRect(g_hWnd, &rect);
io.DisplaySize = ImVec2((float)(rect.right - rect.left), (float)(rect.bottom - rect.top)); io.DisplaySize = ImVec2((float)(rect.right - rect.left), (float)(rect.bottom - rect.top));
// Setup time step // Setup time step
INT64 current_time; INT64 current_time = 0;
::QueryPerformanceCounter((LARGE_INTEGER*)&current_time); ::QueryPerformanceCounter((LARGE_INTEGER*)&current_time);
io.DeltaTime = (float)(current_time - g_Time) / g_TicksPerSecond; io.DeltaTime = (float)(current_time - g_Time) / g_TicksPerSecond;
g_Time = current_time; g_Time = current_time;
@ -259,7 +310,7 @@ void ImGui_ImplWin32_NewFrame()
// Win32 message handler (process Win32 mouse/keyboard inputs, etc.) // Win32 message handler (process Win32 mouse/keyboard inputs, etc.)
// Call from your application's message handler. // Call from your application's message handler.
// When implementing your own back-end, you can read the io.WantCaptureMouse, io.WantCaptureKeyboard flags to tell if Dear ImGui wants to use your inputs. // When implementing your own backend, you can read the io.WantCaptureMouse, io.WantCaptureKeyboard flags to tell if Dear ImGui wants to use your inputs.
// - When io.WantCaptureMouse is true, do not dispatch mouse input data to your main application. // - When io.WantCaptureMouse is true, do not dispatch mouse input data to your main application.
// - When io.WantCaptureKeyboard is true, do not dispatch keyboard input data to your main application. // - When io.WantCaptureKeyboard is true, do not dispatch keyboard input data to your main application.
// Generally you may always pass all inputs to Dear ImGui, and hide them from your application based on those two flags. // Generally you may always pass all inputs to Dear ImGui, and hide them from your application based on those two flags.
@ -323,6 +374,9 @@ IMGUI_IMPL_API LRESULT ImGui_ImplWin32_WndProcHandler(HWND hwnd, UINT msg, WPARA
if (wParam < 256) if (wParam < 256)
io.KeysDown[wParam] = 0; io.KeysDown[wParam] = 0;
return 0; return 0;
case WM_KILLFOCUS:
memset(io.KeysDown, 0, sizeof(io.KeysDown));
return 0;
case WM_CHAR: case WM_CHAR:
// You can also use ToAscii()+GetKeyboardState() to retrieve characters. // You can also use ToAscii()+GetKeyboardState() to retrieve characters.
if (wParam > 0 && wParam < 0x10000) if (wParam > 0 && wParam < 0x10000)
@ -352,7 +406,7 @@ IMGUI_IMPL_API LRESULT ImGui_ImplWin32_WndProcHandler(HWND hwnd, UINT msg, WPARA
//--------------------------------------------------------------------------------------------------------- //---------------------------------------------------------------------------------------------------------
// This is the scheme successfully used by GLFW (from which we borrowed some of the code) and other apps aiming to be highly portable. // This is the scheme successfully used by GLFW (from which we borrowed some of the code) and other apps aiming to be highly portable.
// ImGui_ImplWin32_EnableDpiAwareness() is just a helper called by main.cpp, we don't call it automatically. // ImGui_ImplWin32_EnableDpiAwareness() is just a helper called by main.cpp, we don't call it automatically.
// If you are trying to implement your own back-end for your own engine, you may ignore that noise. // If you are trying to implement your own backend for your own engine, you may ignore that noise.
//--------------------------------------------------------------------------------------------------------- //---------------------------------------------------------------------------------------------------------
// Implement some of the functions and types normally declared in recent Windows SDK. // Implement some of the functions and types normally declared in recent Windows SDK.
@ -366,7 +420,9 @@ static BOOL IsWindowsVersionOrGreater(WORD major, WORD minor, WORD sp)
cond = ::VerSetConditionMask(cond, VER_SERVICEPACKMAJOR, VER_GREATER_EQUAL); cond = ::VerSetConditionMask(cond, VER_SERVICEPACKMAJOR, VER_GREATER_EQUAL);
return ::VerifyVersionInfoW(&osvi, mask, cond); return ::VerifyVersionInfoW(&osvi, mask, cond);
} }
#define IsWindows8Point1OrGreater() IsWindowsVersionOrGreater(HIBYTE(0x0602), LOBYTE(0x0602), 0) // _WIN32_WINNT_WINBLUE #define IsWindowsVistaOrGreater() IsWindowsVersionOrGreater(HIBYTE(0x0600), LOBYTE(0x0600), 0) // _WIN32_WINNT_VISTA
#define IsWindows8OrGreater() IsWindowsVersionOrGreater(HIBYTE(0x0602), LOBYTE(0x0602), 0) // _WIN32_WINNT_WIN8
#define IsWindows8Point1OrGreater() IsWindowsVersionOrGreater(HIBYTE(0x0603), LOBYTE(0x0603), 0) // _WIN32_WINNT_WINBLUE
#endif #endif
#ifndef DPI_ENUMS_DECLARED #ifndef DPI_ENUMS_DECLARED
@ -411,7 +467,7 @@ void ImGui_ImplWin32_EnableDpiAwareness()
} }
#if defined(_MSC_VER) && !defined(NOGDI) #if defined(_MSC_VER) && !defined(NOGDI)
#pragma comment(lib, "gdi32") // Link with gdi32.lib for GetDeviceCaps() #pragma comment(lib, "gdi32") // Link with gdi32.lib for GetDeviceCaps(). MinGW will require linking with '-lgdi32'
#endif #endif
float ImGui_ImplWin32_GetDpiScaleForMonitor(void* monitor) float ImGui_ImplWin32_GetDpiScaleForMonitor(void* monitor)
@ -444,3 +500,43 @@ float ImGui_ImplWin32_GetDpiScaleForHwnd(void* hwnd)
} }
//--------------------------------------------------------------------------------------------------------- //---------------------------------------------------------------------------------------------------------
// Transparency related helpers (optional)
//--------------------------------------------------------------------------------------------------------
#if defined(_MSC_VER)
#pragma comment(lib, "dwmapi") // Link with dwmapi.lib. MinGW will require linking with '-ldwmapi'
#endif
// [experimental]
// Borrowed from GLFW's function updateFramebufferTransparency() in src/win32_window.c
// (the Dwm* functions are Vista era functions but we are borrowing logic from GLFW)
void ImGui_ImplWin32_EnableAlphaCompositing(void* hwnd)
{
if (!IsWindowsVistaOrGreater())
return;
BOOL composition;
if (FAILED(::DwmIsCompositionEnabled(&composition)) || !composition)
return;
BOOL opaque;
DWORD color;
if (IsWindows8OrGreater() || (SUCCEEDED(::DwmGetColorizationColor(&color, &opaque)) && !opaque))
{
HRGN region = ::CreateRectRgn(0, 0, -1, -1);
DWM_BLURBEHIND bb = {};
bb.dwFlags = DWM_BB_ENABLE | DWM_BB_BLURREGION;
bb.hRgnBlur = region;
bb.fEnable = TRUE;
::DwmEnableBlurBehindWindow((HWND)hwnd, &bb);
::DeleteObject(region);
}
else
{
DWM_BLURBEHIND bb = {};
bb.dwFlags = DWM_BB_ENABLE;
::DwmEnableBlurBehindWindow((HWND)hwnd, &bb);
}
}
//---------------------------------------------------------------------------------------------------------

View File

@ -1,4 +1,4 @@
// dear imgui: Platform Binding for Windows (standard windows API for 32 and 64 bits applications) // dear imgui: Platform Backend for Windows (standard windows API for 32 and 64 bits applications)
// This needs to be used along with a Renderer (e.g. DirectX11, OpenGL3, Vulkan..) // This needs to be used along with a Renderer (e.g. DirectX11, OpenGL3, Vulkan..)
// Implemented features: // Implemented features:
@ -7,18 +7,17 @@
// [X] Platform: Keyboard arrays indexed using VK_* Virtual Key Codes, e.g. ImGui::IsKeyPressed(VK_SPACE). // [X] Platform: Keyboard arrays indexed using VK_* Virtual Key Codes, e.g. ImGui::IsKeyPressed(VK_SPACE).
// [X] Platform: Gamepad support. Enabled with 'io.ConfigFlags |= ImGuiConfigFlags_NavEnableGamepad'. // [X] Platform: Gamepad support. Enabled with 'io.ConfigFlags |= ImGuiConfigFlags_NavEnableGamepad'.
// You can copy and use unmodified imgui_impl_* files in your project. See examples/ folder for examples of using this.
// If you are new to Dear ImGui, read documentation from the docs/ folder + read the top of imgui.cpp.
// Read online: https://github.com/ocornut/imgui/tree/master/docs
#pragma once #pragma once
#include "../../imgui.h" // IMGUI_IMPL_API #include "imgui.h" // IMGUI_IMPL_API
IMGUI_IMPL_API bool ImGui_ImplWin32_Init(void* hwnd); IMGUI_IMPL_API bool ImGui_ImplWin32_Init(void* hwnd);
IMGUI_IMPL_API void ImGui_ImplWin32_Shutdown(); IMGUI_IMPL_API void ImGui_ImplWin32_Shutdown();
IMGUI_IMPL_API void ImGui_ImplWin32_NewFrame(); IMGUI_IMPL_API void ImGui_ImplWin32_NewFrame();
// Configuration
// - Disable gamepad support or linking with xinput.lib
//#define IMGUI_IMPL_WIN32_DISABLE_GAMEPAD
//#define IMGUI_IMPL_WIN32_DISABLE_LINKING_XINPUT
// Win32 message handler your application need to call. // Win32 message handler your application need to call.
// - Intentionally commented out in a '#if 0' block to avoid dragging dependencies on <windows.h> from this helper. // - Intentionally commented out in a '#if 0' block to avoid dragging dependencies on <windows.h> from this helper.
// - You should COPY the line below into your .cpp code to forward declare the function and then you can call it. // - You should COPY the line below into your .cpp code to forward declare the function and then you can call it.
@ -35,3 +34,8 @@ extern IMGUI_IMPL_API LRESULT ImGui_ImplWin32_WndProcHandler(HWND hWnd, UINT msg
IMGUI_IMPL_API void ImGui_ImplWin32_EnableDpiAwareness(); IMGUI_IMPL_API void ImGui_ImplWin32_EnableDpiAwareness();
IMGUI_IMPL_API float ImGui_ImplWin32_GetDpiScaleForHwnd(void* hwnd); // HWND hwnd IMGUI_IMPL_API float ImGui_ImplWin32_GetDpiScaleForHwnd(void* hwnd); // HWND hwnd
IMGUI_IMPL_API float ImGui_ImplWin32_GetDpiScaleForMonitor(void* monitor); // HMONITOR monitor IMGUI_IMPL_API float ImGui_ImplWin32_GetDpiScaleForMonitor(void* monitor); // HMONITOR monitor
// Transparency related helpers (optional) [experimental]
// - Use to enable alpha compositing transparency with the desktop.
// - Use together with e.g. clearing your framebuffer with zero-alpha.
IMGUI_IMPL_API void ImGui_ImplWin32_EnableAlphaCompositing(void* hwnd); // HWND hwnd

View File

@ -4302,7 +4302,7 @@ static int stbtt__compute_crossings_x(float x, float y, int nverts, stbtt_vertex
int winding = 0; int winding = 0;
orig[0] = x; orig[0] = x;
//orig[1] = y; // [DEAR IMGUI] commmented double assignment //orig[1] = y; // [DEAR IMGUI] commented double assignment
// make sure y never passes through a vertex of the shape // make sure y never passes through a vertex of the shape
y_frac = (float) STBTT_fmod(y, 1.0f); y_frac = (float) STBTT_fmod(y, 1.0f);

View File

@ -29,32 +29,32 @@ const GUID DETOUR_EXE_HELPER_GUID = { /* ea0251b9-5cde-41b5-98d0-2af4a26b0fee */
////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////
// //
// Enumate through modules in the target process. // Enumerate through modules in the target process.
// //
static BOOL WINAPI LoadNtHeaderFromProcess(HANDLE hProcess, static PVOID LoadNtHeaderFromProcess(_In_ HANDLE hProcess,
HMODULE hModule, _In_ HMODULE hModule,
PIMAGE_NT_HEADERS32 pNtHeader) _Out_ PIMAGE_NT_HEADERS32 pNtHeader)
{ {
ZeroMemory(pNtHeader, sizeof(*pNtHeader));
PBYTE pbModule = (PBYTE)hModule; PBYTE pbModule = (PBYTE)hModule;
if (pbModule == NULL) { if (pbModule == NULL) {
SetLastError(ERROR_INVALID_PARAMETER); SetLastError(ERROR_INVALID_PARAMETER);
return FALSE; return NULL;
} }
MEMORY_BASIC_INFORMATION mbi; MEMORY_BASIC_INFORMATION mbi;
ZeroMemory(&mbi, sizeof(mbi)); ZeroMemory(&mbi, sizeof(mbi));
if (VirtualQueryEx(hProcess, hModule, &mbi, sizeof(mbi)) == 0) { if (VirtualQueryEx(hProcess, hModule, &mbi, sizeof(mbi)) == 0) {
return FALSE; return NULL;
} }
IMAGE_DOS_HEADER idh; IMAGE_DOS_HEADER idh;
if (!ReadProcessMemory(hProcess, pbModule, &idh, sizeof(idh), NULL)) { if (!ReadProcessMemory(hProcess, pbModule, &idh, sizeof(idh), NULL)) {
DETOUR_TRACE(("ReadProcessMemory(idh@%p..%p) failed: %d\n", DETOUR_TRACE(("ReadProcessMemory(idh@%p..%p) failed: %lu\n",
pbModule, pbModule + sizeof(idh), GetLastError())); pbModule, pbModule + sizeof(idh), GetLastError()));
return FALSE; return NULL;
} }
if (idh.e_magic != IMAGE_DOS_SIGNATURE || if (idh.e_magic != IMAGE_DOS_SIGNATURE ||
@ -62,31 +62,37 @@ static BOOL WINAPI LoadNtHeaderFromProcess(HANDLE hProcess,
(DWORD)idh.e_lfanew < sizeof(idh)) { (DWORD)idh.e_lfanew < sizeof(idh)) {
SetLastError(ERROR_BAD_EXE_FORMAT); SetLastError(ERROR_BAD_EXE_FORMAT);
return FALSE; return NULL;
} }
if (!ReadProcessMemory(hProcess, pbModule + idh.e_lfanew, if (!ReadProcessMemory(hProcess, pbModule + idh.e_lfanew,
pNtHeader, sizeof(*pNtHeader), NULL)) { pNtHeader, sizeof(*pNtHeader), NULL)) {
DETOUR_TRACE(("ReadProcessMemory(inh@%p..%p:%p) failed: %d\n", DETOUR_TRACE(("ReadProcessMemory(inh@%p..%p:%p) failed: %lu\n",
pbModule + idh.e_lfanew, pbModule + idh.e_lfanew,
pbModule + idh.e_lfanew + sizeof(*pNtHeader), pbModule + idh.e_lfanew + sizeof(*pNtHeader),
pbModule, pbModule,
GetLastError())); GetLastError()));
return FALSE; return NULL;
} }
if (pNtHeader->Signature != IMAGE_NT_SIGNATURE) { if (pNtHeader->Signature != IMAGE_NT_SIGNATURE) {
SetLastError(ERROR_BAD_EXE_FORMAT); SetLastError(ERROR_BAD_EXE_FORMAT);
return FALSE; return NULL;
} }
return TRUE; return pbModule + idh.e_lfanew;
} }
static HMODULE WINAPI EnumerateModulesInProcess(HANDLE hProcess, static HMODULE EnumerateModulesInProcess(_In_ HANDLE hProcess,
HMODULE hModuleLast, _In_opt_ HMODULE hModuleLast,
PIMAGE_NT_HEADERS32 pNtHeader) _Out_ PIMAGE_NT_HEADERS32 pNtHeader,
_Out_opt_ PVOID *pRemoteNtHeader)
{ {
ZeroMemory(pNtHeader, sizeof(*pNtHeader));
if (pRemoteNtHeader) {
*pRemoteNtHeader = NULL;
}
PBYTE pbLast = (PBYTE)hModuleLast + MM_ALLOCATION_GRANULARITY; PBYTE pbLast = (PBYTE)hModuleLast + MM_ALLOCATION_GRANULARITY;
MEMORY_BASIC_INFORMATION mbi; MEMORY_BASIC_INFORMATION mbi;
@ -118,13 +124,147 @@ static HMODULE WINAPI EnumerateModulesInProcess(HANDLE hProcess,
continue; continue;
} }
if (LoadNtHeaderFromProcess(hProcess, (HMODULE)pbLast, pNtHeader)) { PVOID remoteHeader
= LoadNtHeaderFromProcess(hProcess, (HMODULE)pbLast, pNtHeader);
if (remoteHeader) {
if (pRemoteNtHeader) {
*pRemoteNtHeader = remoteHeader;
}
return (HMODULE)pbLast; return (HMODULE)pbLast;
} }
} }
return NULL; return NULL;
} }
//////////////////////////////////////////////////////////////////////////////
//
// Find payloads in target process.
//
static PVOID FindDetourSectionInRemoteModule(_In_ HANDLE hProcess,
_In_ HMODULE hModule,
_In_ const IMAGE_NT_HEADERS32 *pNtHeader,
_In_ PVOID pRemoteNtHeader)
{
if (pNtHeader->FileHeader.SizeOfOptionalHeader == 0) {
SetLastError(ERROR_EXE_MARKED_INVALID);
return NULL;
}
PIMAGE_SECTION_HEADER pRemoteSectionHeaders
= (PIMAGE_SECTION_HEADER)((PBYTE)pRemoteNtHeader
+ sizeof(pNtHeader->Signature)
+ sizeof(pNtHeader->FileHeader)
+ pNtHeader->FileHeader.SizeOfOptionalHeader);
IMAGE_SECTION_HEADER header;
for (DWORD n = 0; n < pNtHeader->FileHeader.NumberOfSections; ++n) {
if (!ReadProcessMemory(hProcess, pRemoteSectionHeaders + n, &header, sizeof(header), NULL)) {
DETOUR_TRACE(("ReadProcessMemory(ish@%p..%p) failed: %lu\n",
pRemoteSectionHeaders + n,
(PBYTE)(pRemoteSectionHeaders + n) + sizeof(header),
GetLastError()));
return NULL;
}
if (strcmp((PCHAR)header.Name, ".detour") == 0) {
if (header.VirtualAddress == 0 ||
header.SizeOfRawData == 0) {
break;
}
SetLastError(NO_ERROR);
return (PBYTE)hModule + header.VirtualAddress;
}
}
SetLastError(ERROR_EXE_MARKED_INVALID);
return NULL;
}
static PVOID FindPayloadInRemoteDetourSection(_In_ HANDLE hProcess,
_In_ REFGUID rguid,
_Out_opt_ DWORD *pcbData,
_In_ PVOID pvRemoteDetoursSection)
{
if (pcbData) {
*pcbData = 0;
}
PBYTE pbData = (PBYTE)pvRemoteDetoursSection;
DETOUR_SECTION_HEADER header;
if (!ReadProcessMemory(hProcess, pbData, &header, sizeof(header), NULL)) {
DETOUR_TRACE(("ReadProcessMemory(dsh@%p..%p) failed: %lu\n",
pbData,
pbData + sizeof(header),
GetLastError()));
return NULL;
}
if (header.cbHeaderSize < sizeof(DETOUR_SECTION_HEADER) ||
header.nSignature != DETOUR_SECTION_HEADER_SIGNATURE) {
SetLastError(ERROR_EXE_MARKED_INVALID);
return NULL;
}
if (header.nDataOffset == 0) {
header.nDataOffset = header.cbHeaderSize;
}
for (PVOID pvSection = pbData + header.nDataOffset; pvSection < pbData + header.cbDataSize;) {
DETOUR_SECTION_RECORD section;
if (!ReadProcessMemory(hProcess, pvSection, &section, sizeof(section), NULL)) {
DETOUR_TRACE(("ReadProcessMemory(dsr@%p..%p) failed: %lu\n",
pvSection,
(PBYTE)pvSection + sizeof(section),
GetLastError()));
return NULL;
}
if (DetourAreSameGuid(section.guid, rguid)) {
if (pcbData) {
*pcbData = section.cbBytes - sizeof(section);
}
SetLastError(NO_ERROR);
return (DETOUR_SECTION_RECORD *)pvSection + 1;
}
pvSection = (PBYTE)pvSection + section.cbBytes;
}
return NULL;
}
_Success_(return != NULL)
PVOID WINAPI DetourFindRemotePayload(_In_ HANDLE hProcess,
_In_ REFGUID rguid,
_Out_opt_ DWORD *pcbData)
{
if (hProcess == NULL) {
SetLastError(ERROR_INVALID_HANDLE);
return NULL;
}
IMAGE_NT_HEADERS32 header;
PVOID pvRemoteHeader;
for (HMODULE hMod = NULL; (hMod = EnumerateModulesInProcess(hProcess, hMod, &header, &pvRemoteHeader)) != NULL;) {
PVOID pvData = FindDetourSectionInRemoteModule(hProcess, hMod, &header, pvRemoteHeader);
if (pvData != NULL) {
pvData = FindPayloadInRemoteDetourSection(hProcess, rguid, pcbData, pvData);
if (pvData != NULL) {
return pvData;
}
}
}
SetLastError(ERROR_MOD_NOT_FOUND);
return NULL;
}
////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////
// //
// Find a region of memory in which we can create a replacement import table. // Find a region of memory in which we can create a replacement import table.
@ -142,7 +282,7 @@ static PBYTE FindAndAllocateNearBase(HANDLE hProcess, PBYTE pbModule, PBYTE pbBa
if (GetLastError() == ERROR_INVALID_PARAMETER) { if (GetLastError() == ERROR_INVALID_PARAMETER) {
break; break;
} }
DETOUR_TRACE(("VirtualQueryEx(%p) failed: %d\n", DETOUR_TRACE(("VirtualQueryEx(%p) failed: %lu\n",
pbLast, GetLastError())); pbLast, GetLastError()));
break; break;
} }
@ -187,7 +327,7 @@ static PBYTE FindAndAllocateNearBase(HANDLE hProcess, PBYTE pbModule, PBYTE pbBa
PBYTE pbAlloc = (PBYTE)VirtualAllocEx(hProcess, pbAddress, cbAlloc, PBYTE pbAlloc = (PBYTE)VirtualAllocEx(hProcess, pbAddress, cbAlloc,
MEM_RESERVE | MEM_COMMIT, PAGE_READWRITE); MEM_RESERVE | MEM_COMMIT, PAGE_READWRITE);
if (pbAlloc == NULL) { if (pbAlloc == NULL) {
DETOUR_TRACE(("VirtualAllocEx(%p) failed: %d\n", pbAddress, GetLastError())); DETOUR_TRACE(("VirtualAllocEx(%p) failed: %lu\n", pbAddress, GetLastError()));
continue; continue;
} }
#ifdef _WIN64 #ifdef _WIN64
@ -246,7 +386,7 @@ static BOOL RecordExeRestore(HANDLE hProcess, HMODULE hModule, DETOUR_EXE_RESTOR
der.pidh = (PBYTE)hModule; der.pidh = (PBYTE)hModule;
der.cbidh = sizeof(der.idh); der.cbidh = sizeof(der.idh);
if (!ReadProcessMemory(hProcess, der.pidh, &der.idh, sizeof(der.idh), NULL)) { if (!ReadProcessMemory(hProcess, der.pidh, &der.idh, sizeof(der.idh), NULL)) {
DETOUR_TRACE(("ReadProcessMemory(idh@%p..%p) failed: %d\n", DETOUR_TRACE(("ReadProcessMemory(idh@%p..%p) failed: %lu\n",
der.pidh, der.pidh + der.cbidh, GetLastError())); der.pidh, der.pidh + der.cbidh, GetLastError()));
return FALSE; return FALSE;
} }
@ -257,7 +397,7 @@ static BOOL RecordExeRestore(HANDLE hProcess, HMODULE hModule, DETOUR_EXE_RESTOR
der.pinh = der.pidh + der.idh.e_lfanew; der.pinh = der.pidh + der.idh.e_lfanew;
der.cbinh = FIELD_OFFSET(IMAGE_NT_HEADERS, OptionalHeader); der.cbinh = FIELD_OFFSET(IMAGE_NT_HEADERS, OptionalHeader);
if (!ReadProcessMemory(hProcess, der.pinh, &der.inh, der.cbinh, NULL)) { if (!ReadProcessMemory(hProcess, der.pinh, &der.inh, der.cbinh, NULL)) {
DETOUR_TRACE(("ReadProcessMemory(inh@%p..%p) failed: %d\n", DETOUR_TRACE(("ReadProcessMemory(inh@%p..%p) failed: %lu\n",
der.pinh, der.pinh + der.cbinh, GetLastError())); der.pinh, der.pinh + der.cbinh, GetLastError()));
return FALSE; return FALSE;
} }
@ -272,7 +412,7 @@ static BOOL RecordExeRestore(HANDLE hProcess, HMODULE hModule, DETOUR_EXE_RESTOR
} }
if (!ReadProcessMemory(hProcess, der.pinh, &der.inh, der.cbinh, NULL)) { if (!ReadProcessMemory(hProcess, der.pinh, &der.inh, der.cbinh, NULL)) {
DETOUR_TRACE(("ReadProcessMemory(inh@%p..%p) failed: %d\n", DETOUR_TRACE(("ReadProcessMemory(inh@%p..%p) failed: %lu\n",
der.pinh, der.pinh + der.cbinh, GetLastError())); der.pinh, der.pinh + der.cbinh, GetLastError()));
return FALSE; return FALSE;
} }
@ -284,7 +424,7 @@ static BOOL RecordExeRestore(HANDLE hProcess, HMODULE hModule, DETOUR_EXE_RESTOR
if (der.inh32.CLR_DIRECTORY.VirtualAddress != 0 && if (der.inh32.CLR_DIRECTORY.VirtualAddress != 0 &&
der.inh32.CLR_DIRECTORY.Size != 0) { der.inh32.CLR_DIRECTORY.Size != 0) {
DETOUR_TRACE(("CLR32.VirtAddr=%x, CLR.Size=%x\n", DETOUR_TRACE(("CLR32.VirtAddr=%08lx, CLR.Size=%lu\n",
der.inh32.CLR_DIRECTORY.VirtualAddress, der.inh32.CLR_DIRECTORY.VirtualAddress,
der.inh32.CLR_DIRECTORY.Size)); der.inh32.CLR_DIRECTORY.Size));
@ -295,7 +435,7 @@ static BOOL RecordExeRestore(HANDLE hProcess, HMODULE hModule, DETOUR_EXE_RESTOR
if (der.inh64.CLR_DIRECTORY.VirtualAddress != 0 && if (der.inh64.CLR_DIRECTORY.VirtualAddress != 0 &&
der.inh64.CLR_DIRECTORY.Size != 0) { der.inh64.CLR_DIRECTORY.Size != 0) {
DETOUR_TRACE(("CLR64.VirtAddr=%x, CLR.Size=%x\n", DETOUR_TRACE(("CLR64.VirtAddr=%08lx, CLR.Size=%lu\n",
der.inh64.CLR_DIRECTORY.VirtualAddress, der.inh64.CLR_DIRECTORY.VirtualAddress,
der.inh64.CLR_DIRECTORY.Size)); der.inh64.CLR_DIRECTORY.Size));
@ -306,7 +446,7 @@ static BOOL RecordExeRestore(HANDLE hProcess, HMODULE hModule, DETOUR_EXE_RESTOR
if (der.pclr != 0) { if (der.pclr != 0) {
der.cbclr = sizeof(der.clr); der.cbclr = sizeof(der.clr);
if (!ReadProcessMemory(hProcess, der.pclr, &der.clr, der.cbclr, NULL)) { if (!ReadProcessMemory(hProcess, der.pclr, &der.clr, der.cbclr, NULL)) {
DETOUR_TRACE(("ReadProcessMemory(clr@%p..%p) failed: %d\n", DETOUR_TRACE(("ReadProcessMemory(clr@%p..%p) failed: %lu\n",
der.pclr, der.pclr + der.cbclr, GetLastError())); der.pclr, der.pclr + der.cbclr, GetLastError()));
return FALSE; return FALSE;
} }
@ -323,6 +463,7 @@ static BOOL RecordExeRestore(HANDLE hProcess, HMODULE hModule, DETOUR_EXE_RESTOR
#define IMAGE_NT_HEADERS_XX IMAGE_NT_HEADERS32 #define IMAGE_NT_HEADERS_XX IMAGE_NT_HEADERS32
#define IMAGE_NT_OPTIONAL_HDR_MAGIC_XX IMAGE_NT_OPTIONAL_HDR32_MAGIC #define IMAGE_NT_OPTIONAL_HDR_MAGIC_XX IMAGE_NT_OPTIONAL_HDR32_MAGIC
#define IMAGE_ORDINAL_FLAG_XX IMAGE_ORDINAL_FLAG32 #define IMAGE_ORDINAL_FLAG_XX IMAGE_ORDINAL_FLAG32
#define IMAGE_THUNK_DATAXX IMAGE_THUNK_DATA32
#define UPDATE_IMPORTS_XX UpdateImports32 #define UPDATE_IMPORTS_XX UpdateImports32
#define DETOURS_BITS_XX 32 #define DETOURS_BITS_XX 32
#include "uimports.cc" #include "uimports.cc"
@ -339,6 +480,7 @@ static BOOL RecordExeRestore(HANDLE hProcess, HMODULE hModule, DETOUR_EXE_RESTOR
#define IMAGE_NT_HEADERS_XX IMAGE_NT_HEADERS64 #define IMAGE_NT_HEADERS_XX IMAGE_NT_HEADERS64
#define IMAGE_NT_OPTIONAL_HDR_MAGIC_XX IMAGE_NT_OPTIONAL_HDR64_MAGIC #define IMAGE_NT_OPTIONAL_HDR_MAGIC_XX IMAGE_NT_OPTIONAL_HDR64_MAGIC
#define IMAGE_ORDINAL_FLAG_XX IMAGE_ORDINAL_FLAG64 #define IMAGE_ORDINAL_FLAG_XX IMAGE_ORDINAL_FLAG64
#define IMAGE_THUNK_DATAXX IMAGE_THUNK_DATA64
#define UPDATE_IMPORTS_XX UpdateImports64 #define UPDATE_IMPORTS_XX UpdateImports64
#define DETOURS_BITS_XX 64 #define DETOURS_BITS_XX 64
#include "uimports.cc" #include "uimports.cc"
@ -374,7 +516,7 @@ static BOOL UpdateFrom32To64(HANDLE hProcess, HMODULE hModule, WORD machine,
//////////////////////////////////////////////////////// Read old headers. //////////////////////////////////////////////////////// Read old headers.
// //
if (!ReadProcessMemory(hProcess, pbModule, &idh, sizeof(idh), NULL)) { if (!ReadProcessMemory(hProcess, pbModule, &idh, sizeof(idh), NULL)) {
DETOUR_TRACE(("ReadProcessMemory(idh@%p..%p) failed: %d\n", DETOUR_TRACE(("ReadProcessMemory(idh@%p..%p) failed: %lu\n",
pbModule, pbModule + sizeof(idh), GetLastError())); pbModule, pbModule + sizeof(idh), GetLastError()));
return FALSE; return FALSE;
} }
@ -383,7 +525,7 @@ static BOOL UpdateFrom32To64(HANDLE hProcess, HMODULE hModule, WORD machine,
PBYTE pnh = pbModule + idh.e_lfanew; PBYTE pnh = pbModule + idh.e_lfanew;
if (!ReadProcessMemory(hProcess, pnh, &inh32, sizeof(inh32), NULL)) { if (!ReadProcessMemory(hProcess, pnh, &inh32, sizeof(inh32), NULL)) {
DETOUR_TRACE(("ReadProcessMemory(inh@%p..%p) failed: %d\n", DETOUR_TRACE(("ReadProcessMemory(inh@%p..%p) failed: %lu\n",
pnh, pnh + sizeof(inh32), GetLastError())); pnh, pnh + sizeof(inh32), GetLastError()));
return FALSE; return FALSE;
} }
@ -398,7 +540,7 @@ static BOOL UpdateFrom32To64(HANDLE hProcess, HMODULE hModule, WORD machine,
inh32.FileHeader.SizeOfOptionalHeader; inh32.FileHeader.SizeOfOptionalHeader;
ULONG cb = inh32.FileHeader.NumberOfSections * sizeof(IMAGE_SECTION_HEADER); ULONG cb = inh32.FileHeader.NumberOfSections * sizeof(IMAGE_SECTION_HEADER);
if (!ReadProcessMemory(hProcess, psects, &sects, cb, NULL)) { if (!ReadProcessMemory(hProcess, psects, &sects, cb, NULL)) {
DETOUR_TRACE(("ReadProcessMemory(ish@%p..%p) failed: %d\n", DETOUR_TRACE(("ReadProcessMemory(ish@%p..%p) failed: %lu\n",
psects, psects + cb, GetLastError())); psects, psects + cb, GetLastError()));
return FALSE; return FALSE;
} }
@ -455,7 +597,7 @@ static BOOL UpdateFrom32To64(HANDLE hProcess, HMODULE hModule, WORD machine,
} }
if (!WriteProcessMemory(hProcess, pnh, &inh64, sizeof(inh64), NULL)) { if (!WriteProcessMemory(hProcess, pnh, &inh64, sizeof(inh64), NULL)) {
DETOUR_TRACE(("WriteProcessMemory(inh@%p..%p) failed: %d\n", DETOUR_TRACE(("WriteProcessMemory(inh@%p..%p) failed: %lu\n",
pnh, pnh + sizeof(inh64), GetLastError())); pnh, pnh + sizeof(inh64), GetLastError()));
return FALSE; return FALSE;
} }
@ -466,7 +608,7 @@ static BOOL UpdateFrom32To64(HANDLE hProcess, HMODULE hModule, WORD machine,
inh64.FileHeader.SizeOfOptionalHeader; inh64.FileHeader.SizeOfOptionalHeader;
cb = inh64.FileHeader.NumberOfSections * sizeof(IMAGE_SECTION_HEADER); cb = inh64.FileHeader.NumberOfSections * sizeof(IMAGE_SECTION_HEADER);
if (!WriteProcessMemory(hProcess, psects, &sects, cb, NULL)) { if (!WriteProcessMemory(hProcess, psects, &sects, cb, NULL)) {
DETOUR_TRACE(("WriteProcessMemory(ish@%p..%p) failed: %d\n", DETOUR_TRACE(("WriteProcessMemory(ish@%p..%p) failed: %lu\n",
psects, psects + cb, GetLastError())); psects, psects + cb, GetLastError()));
return FALSE; return FALSE;
} }
@ -478,12 +620,12 @@ static BOOL UpdateFrom32To64(HANDLE hProcess, HMODULE hModule, WORD machine,
} }
// Remove the import table. // Remove the import table.
if (der.pclr != NULL && (der.clr.Flags & 1)) { if (der.pclr != NULL && (der.clr.Flags & COMIMAGE_FLAGS_ILONLY)) {
inh64.IMPORT_DIRECTORY.VirtualAddress = 0; inh64.IMPORT_DIRECTORY.VirtualAddress = 0;
inh64.IMPORT_DIRECTORY.Size = 0; inh64.IMPORT_DIRECTORY.Size = 0;
if (!WriteProcessMemory(hProcess, pnh, &inh64, sizeof(inh64), NULL)) { if (!WriteProcessMemory(hProcess, pnh, &inh64, sizeof(inh64), NULL)) {
DETOUR_TRACE(("WriteProcessMemory(inh@%p..%p) failed: %d\n", DETOUR_TRACE(("WriteProcessMemory(inh@%p..%p) failed: %lu\n",
pnh, pnh + sizeof(inh64), GetLastError())); pnh, pnh + sizeof(inh64), GetLastError()));
return FALSE; return FALSE;
} }
@ -499,6 +641,37 @@ static BOOL UpdateFrom32To64(HANDLE hProcess, HMODULE hModule, WORD machine,
} }
#endif // DETOURS_64BIT #endif // DETOURS_64BIT
typedef BOOL(WINAPI *LPFN_ISWOW64PROCESS)(HANDLE, PBOOL);
static BOOL IsWow64ProcessHelper(HANDLE hProcess,
PBOOL Wow64Process)
{
#ifdef _X86_
if (Wow64Process == NULL) {
return FALSE;
}
// IsWow64Process is not available on all supported versions of Windows.
//
HMODULE hKernel32 = LoadLibraryW(L"KERNEL32.DLL");
if (hKernel32 == NULL) {
DETOUR_TRACE(("LoadLibraryW failed: %lu\n", GetLastError()));
return FALSE;
}
LPFN_ISWOW64PROCESS pfnIsWow64Process = (LPFN_ISWOW64PROCESS)GetProcAddress(
hKernel32, "IsWow64Process");
if (pfnIsWow64Process == NULL) {
DETOUR_TRACE(("GetProcAddress failed: %lu\n", GetLastError()));
return FALSE;
}
return pfnIsWow64Process(hProcess, Wow64Process);
#else
return IsWow64Process(hProcess, Wow64Process);
#endif
}
////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////
// //
BOOL WINAPI DetourUpdateProcessWithDll(_In_ HANDLE hProcess, BOOL WINAPI DetourUpdateProcessWithDll(_In_ HANDLE hProcess,
@ -507,18 +680,17 @@ BOOL WINAPI DetourUpdateProcessWithDll(_In_ HANDLE hProcess,
{ {
// Find the next memory region that contains a mapped PE image. // Find the next memory region that contains a mapped PE image.
// //
BOOL bHas64BitDll = FALSE;
BOOL bHas32BitExe = FALSE;
BOOL bIs32BitProcess; BOOL bIs32BitProcess;
BOOL bIs64BitOS = FALSE;
HMODULE hModule = NULL; HMODULE hModule = NULL;
HMODULE hLast = NULL; HMODULE hLast = NULL;
DETOUR_TRACE(("DetourUpdateProcessWithDll(%p,dlls=%d)\n", hProcess, nDlls)); DETOUR_TRACE(("DetourUpdateProcessWithDll(%p,dlls=%lu)\n", hProcess, nDlls));
for (;;) { for (;;) {
IMAGE_NT_HEADERS32 inh; IMAGE_NT_HEADERS32 inh;
if ((hLast = EnumerateModulesInProcess(hProcess, hLast, &inh)) == NULL) { if ((hLast = EnumerateModulesInProcess(hProcess, hLast, &inh, NULL)) == NULL) {
break; break;
} }
@ -527,20 +699,8 @@ BOOL WINAPI DetourUpdateProcessWithDll(_In_ HANDLE hProcess,
if ((inh.FileHeader.Characteristics & IMAGE_FILE_DLL) == 0) { if ((inh.FileHeader.Characteristics & IMAGE_FILE_DLL) == 0) {
hModule = hLast; hModule = hLast;
if (inh.OptionalHeader.Magic == IMAGE_NT_OPTIONAL_HDR32_MAGIC
&& inh.FileHeader.Machine != 0) {
bHas32BitExe = TRUE;
}
DETOUR_TRACE(("%p Found EXE\n", hLast)); DETOUR_TRACE(("%p Found EXE\n", hLast));
} }
else {
if (inh.OptionalHeader.Magic == IMAGE_NT_OPTIONAL_HDR64_MAGIC
&& inh.FileHeader.Machine != 0) {
bHas64BitDll = TRUE;
}
}
} }
if (hModule == NULL) { if (hModule == NULL) {
@ -548,19 +708,37 @@ BOOL WINAPI DetourUpdateProcessWithDll(_In_ HANDLE hProcess,
return FALSE; return FALSE;
} }
if (!bHas32BitExe) { // Determine if the target process is 32bit or 64bit. This is a two-stop process:
bIs32BitProcess = FALSE; //
} // 1. First, determine if we're running on a 64bit operating system.
else if (!bHas64BitDll) { // - If we're running 64bit code (i.e. _WIN64 is defined), this is trivially true.
bIs32BitProcess = TRUE; // - If we're running 32bit code (i.e. _WIN64 is not defined), test if
} // we're running under Wow64. If so, it implies that the operating system
else { // is 64bit.
if (!IsWow64Process(hProcess, &bIs32BitProcess)) { //
#ifdef _WIN64
bIs64BitOS = TRUE;
#else
if (!IsWow64ProcessHelper(GetCurrentProcess(), &bIs64BitOS)) {
return FALSE; return FALSE;
} }
#endif
// 2. With the operating system bitness known, we can now consider the target process:
// - If we're running on a 64bit OS, the target process is 32bit in case
// it is running under Wow64. Otherwise, it's 64bit, running natively
// (without Wow64).
// - If we're running on a 32bit OS, the target process must be 32bit, too.
//
if (bIs64BitOS) {
if (!IsWow64ProcessHelper(hProcess, &bIs32BitProcess)) {
return FALSE;
}
} else {
bIs32BitProcess = TRUE;
} }
DETOUR_TRACE((" 32BitExe=%d 32BitProcess\n", bHas32BitExe, bIs32BitProcess)); DETOUR_TRACE((" 32BitProcess=%d\n", bIs32BitProcess));
return DetourUpdateProcessWithDllEx(hProcess, return DetourUpdateProcessWithDllEx(hProcess,
hModule, hModule,
@ -579,11 +757,11 @@ BOOL WINAPI DetourUpdateProcessWithDllEx(_In_ HANDLE hProcess,
// //
BOOL bIs32BitExe = FALSE; BOOL bIs32BitExe = FALSE;
DETOUR_TRACE(("DetourUpdateProcessWithDllEx(%p,%p,dlls=%d)\n", hProcess, hModule, nDlls)); DETOUR_TRACE(("DetourUpdateProcessWithDllEx(%p,%p,dlls=%lu)\n", hProcess, hModule, nDlls));
IMAGE_NT_HEADERS32 inh; IMAGE_NT_HEADERS32 inh;
if (hModule == NULL || LoadNtHeaderFromProcess(hProcess, hModule, &inh) == NULL) { if (hModule == NULL || !LoadNtHeaderFromProcess(hProcess, hModule, &inh)) {
SetLastError(ERROR_INVALID_OPERATION); SetLastError(ERROR_INVALID_OPERATION);
return FALSE; return FALSE;
} }
@ -594,7 +772,7 @@ BOOL WINAPI DetourUpdateProcessWithDllEx(_In_ HANDLE hProcess,
bIs32BitExe = TRUE; bIs32BitExe = TRUE;
} }
DETOUR_TRACE((" 32BitExe=%d 32BitProcess\n", bIs32BitExe, bIs32BitProcess)); DETOUR_TRACE((" 32BitExe=%d\n", bIs32BitExe));
if (hModule == NULL) { if (hModule == NULL) {
SetLastError(ERROR_INVALID_OPERATION); SetLastError(ERROR_INVALID_OPERATION);
@ -613,8 +791,8 @@ BOOL WINAPI DetourUpdateProcessWithDllEx(_In_ HANDLE hProcess,
// Try to convert a neutral 32-bit managed binary to a 64-bit managed binary. // Try to convert a neutral 32-bit managed binary to a 64-bit managed binary.
if (bIs32BitExe && !bIs32BitProcess) { if (bIs32BitExe && !bIs32BitProcess) {
if (!der.pclr // Native binary if (!der.pclr // Native binary
|| (der.clr.Flags & 1) == 0 // Or mixed-mode MSIL || (der.clr.Flags & COMIMAGE_FLAGS_ILONLY) == 0 // Or mixed-mode MSIL
|| (der.clr.Flags & 2) != 0) { // Or 32BIT Required MSIL || (der.clr.Flags & COMIMAGE_FLAGS_32BITREQUIRED) != 0) { // Or 32BIT Required MSIL
SetLastError(ERROR_INVALID_HANDLE); SetLastError(ERROR_INVALID_HANDLE);
return FALSE; return FALSE;
@ -677,30 +855,30 @@ BOOL WINAPI DetourUpdateProcessWithDllEx(_In_ HANDLE hProcess,
if (der.pclr != NULL) { if (der.pclr != NULL) {
DETOUR_CLR_HEADER clr; DETOUR_CLR_HEADER clr;
CopyMemory(&clr, &der.clr, sizeof(clr)); CopyMemory(&clr, &der.clr, sizeof(clr));
clr.Flags &= 0xfffffffe; // Clear the IL_ONLY flag. clr.Flags &= ~COMIMAGE_FLAGS_ILONLY; // Clear the IL_ONLY flag.
DWORD dwProtect; DWORD dwProtect;
if (!DetourVirtualProtectSameExecuteEx(hProcess, der.pclr, sizeof(clr), PAGE_READWRITE, &dwProtect)) { if (!DetourVirtualProtectSameExecuteEx(hProcess, der.pclr, sizeof(clr), PAGE_READWRITE, &dwProtect)) {
DETOUR_TRACE(("VirtualProtectEx(clr) write failed: %d\n", GetLastError())); DETOUR_TRACE(("VirtualProtectEx(clr) write failed: %lu\n", GetLastError()));
return FALSE; return FALSE;
} }
if (!WriteProcessMemory(hProcess, der.pclr, &clr, sizeof(clr), NULL)) { if (!WriteProcessMemory(hProcess, der.pclr, &clr, sizeof(clr), NULL)) {
DETOUR_TRACE(("WriteProcessMemory(clr) failed: %d\n", GetLastError())); DETOUR_TRACE(("WriteProcessMemory(clr) failed: %lu\n", GetLastError()));
return FALSE; return FALSE;
} }
if (!VirtualProtectEx(hProcess, der.pclr, sizeof(clr), dwProtect, &dwProtect)) { if (!VirtualProtectEx(hProcess, der.pclr, sizeof(clr), dwProtect, &dwProtect)) {
DETOUR_TRACE(("VirtualProtectEx(clr) restore failed: %d\n", GetLastError())); DETOUR_TRACE(("VirtualProtectEx(clr) restore failed: %lu\n", GetLastError()));
return FALSE; return FALSE;
} }
DETOUR_TRACE(("CLR: %p..%p\n", der.pclr, der.pclr + der.cbclr)); DETOUR_TRACE(("CLR: %p..%p\n", der.pclr, der.pclr + der.cbclr));
#if DETOURS_64BIT #if DETOURS_64BIT
if (der.clr.Flags & 0x2) { // Is the 32BIT Required Flag set? if (der.clr.Flags & COMIMAGE_FLAGS_32BITREQUIRED) { // Is the 32BIT Required Flag set?
// X64 never gets here because the process appears as a WOW64 process. // X64 never gets here because the process appears as a WOW64 process.
// However, on IA64, it doesn't appear to be a WOW process. // However, on IA64, it doesn't appear to be a WOW process.
DETOUR_TRACE(("CLR Requires 32-bit\n", der.pclr, der.pclr + der.cbclr)); DETOUR_TRACE(("CLR Requires 32-bit\n"));
SetLastError(ERROR_INVALID_HANDLE); SetLastError(ERROR_INVALID_HANDLE);
return FALSE; return FALSE;
} }
@ -710,7 +888,7 @@ BOOL WINAPI DetourUpdateProcessWithDllEx(_In_ HANDLE hProcess,
//////////////////////////////// Save the undo data to the target process. //////////////////////////////// Save the undo data to the target process.
// //
if (!DetourCopyPayloadToProcess(hProcess, DETOUR_EXE_RESTORE_GUID, &der, sizeof(der))) { if (!DetourCopyPayloadToProcess(hProcess, DETOUR_EXE_RESTORE_GUID, &der, sizeof(der))) {
DETOUR_TRACE(("DetourCopyPayloadToProcess failed: %d\n", GetLastError())); DETOUR_TRACE(("DetourCopyPayloadToProcess failed: %lu\n", GetLastError()));
return FALSE; return FALSE;
} }
return TRUE; return TRUE;
@ -834,9 +1012,23 @@ BOOL WINAPI DetourCreateProcessWithDllW(_In_opt_ LPCWSTR lpApplicationName,
BOOL WINAPI DetourCopyPayloadToProcess(_In_ HANDLE hProcess, BOOL WINAPI DetourCopyPayloadToProcess(_In_ HANDLE hProcess,
_In_ REFGUID rguid, _In_ REFGUID rguid,
_In_reads_bytes_(cbData) PVOID pvData, _In_reads_bytes_(cbData) LPCVOID pvData,
_In_ DWORD cbData) _In_ DWORD cbData)
{ {
return DetourCopyPayloadToProcessEx(hProcess, rguid, pvData, cbData) != NULL;
}
_Success_(return != NULL)
PVOID WINAPI DetourCopyPayloadToProcessEx(_In_ HANDLE hProcess,
_In_ REFGUID rguid,
_In_reads_bytes_(cbData) LPCVOID pvData,
_In_ DWORD cbData)
{
if (hProcess == NULL) {
SetLastError(ERROR_INVALID_HANDLE);
return NULL;
}
DWORD cbTotal = (sizeof(IMAGE_DOS_HEADER) + DWORD cbTotal = (sizeof(IMAGE_DOS_HEADER) +
sizeof(IMAGE_NT_HEADERS) + sizeof(IMAGE_NT_HEADERS) +
sizeof(IMAGE_SECTION_HEADER) + sizeof(IMAGE_SECTION_HEADER) +
@ -847,10 +1039,15 @@ BOOL WINAPI DetourCopyPayloadToProcess(_In_ HANDLE hProcess,
PBYTE pbBase = (PBYTE)VirtualAllocEx(hProcess, NULL, cbTotal, PBYTE pbBase = (PBYTE)VirtualAllocEx(hProcess, NULL, cbTotal,
MEM_COMMIT, PAGE_READWRITE); MEM_COMMIT, PAGE_READWRITE);
if (pbBase == NULL) { if (pbBase == NULL) {
DETOUR_TRACE(("VirtualAllocEx(%d) failed: %d\n", cbTotal, GetLastError())); DETOUR_TRACE(("VirtualAllocEx(%lu) failed: %lu\n", cbTotal, GetLastError()));
return FALSE; return NULL;
} }
// As you can see in the following code,
// the memory layout of the payload range "[pbBase, pbBase+cbTotal]" is a PE executable file,
// so DetourFreePayload can use "DetourGetContainingModule(Payload pointer)" to get the above "pbBase" pointer,
// pbBase: the memory block allocated by VirtualAllocEx will be released in DetourFreePayload by VirtualFree.
PBYTE pbTarget = pbBase; PBYTE pbTarget = pbBase;
IMAGE_DOS_HEADER idh; IMAGE_DOS_HEADER idh;
IMAGE_NT_HEADERS inh; IMAGE_NT_HEADERS inh;
@ -864,8 +1061,8 @@ BOOL WINAPI DetourCopyPayloadToProcess(_In_ HANDLE hProcess,
idh.e_lfanew = sizeof(idh); idh.e_lfanew = sizeof(idh);
if (!WriteProcessMemory(hProcess, pbTarget, &idh, sizeof(idh), &cbWrote) || if (!WriteProcessMemory(hProcess, pbTarget, &idh, sizeof(idh), &cbWrote) ||
cbWrote != sizeof(idh)) { cbWrote != sizeof(idh)) {
DETOUR_TRACE(("WriteProcessMemory(idh) failed: %d\n", GetLastError())); DETOUR_TRACE(("WriteProcessMemory(idh) failed: %lu\n", GetLastError()));
return FALSE; return NULL;
} }
pbTarget += sizeof(idh); pbTarget += sizeof(idh);
@ -877,7 +1074,7 @@ BOOL WINAPI DetourCopyPayloadToProcess(_In_ HANDLE hProcess,
inh.OptionalHeader.Magic = IMAGE_NT_OPTIONAL_HDR_MAGIC; inh.OptionalHeader.Magic = IMAGE_NT_OPTIONAL_HDR_MAGIC;
if (!WriteProcessMemory(hProcess, pbTarget, &inh, sizeof(inh), &cbWrote) || if (!WriteProcessMemory(hProcess, pbTarget, &inh, sizeof(inh), &cbWrote) ||
cbWrote != sizeof(inh)) { cbWrote != sizeof(inh)) {
return FALSE; return NULL;
} }
pbTarget += sizeof(inh); pbTarget += sizeof(inh);
@ -889,7 +1086,7 @@ BOOL WINAPI DetourCopyPayloadToProcess(_In_ HANDLE hProcess,
cbData); cbData);
if (!WriteProcessMemory(hProcess, pbTarget, &ish, sizeof(ish), &cbWrote) || if (!WriteProcessMemory(hProcess, pbTarget, &ish, sizeof(ish), &cbWrote) ||
cbWrote != sizeof(ish)) { cbWrote != sizeof(ish)) {
return FALSE; return NULL;
} }
pbTarget += sizeof(ish); pbTarget += sizeof(ish);
@ -902,7 +1099,7 @@ BOOL WINAPI DetourCopyPayloadToProcess(_In_ HANDLE hProcess,
cbData); cbData);
if (!WriteProcessMemory(hProcess, pbTarget, &dsh, sizeof(dsh), &cbWrote) || if (!WriteProcessMemory(hProcess, pbTarget, &dsh, sizeof(dsh), &cbWrote) ||
cbWrote != sizeof(dsh)) { cbWrote != sizeof(dsh)) {
return FALSE; return NULL;
} }
pbTarget += sizeof(dsh); pbTarget += sizeof(dsh);
@ -912,19 +1109,20 @@ BOOL WINAPI DetourCopyPayloadToProcess(_In_ HANDLE hProcess,
dsr.guid = rguid; dsr.guid = rguid;
if (!WriteProcessMemory(hProcess, pbTarget, &dsr, sizeof(dsr), &cbWrote) || if (!WriteProcessMemory(hProcess, pbTarget, &dsr, sizeof(dsr), &cbWrote) ||
cbWrote != sizeof(dsr)) { cbWrote != sizeof(dsr)) {
return FALSE; return NULL;
} }
pbTarget += sizeof(dsr); pbTarget += sizeof(dsr);
if (!WriteProcessMemory(hProcess, pbTarget, pvData, cbData, &cbWrote) || if (!WriteProcessMemory(hProcess, pbTarget, pvData, cbData, &cbWrote) ||
cbWrote != cbData) { cbWrote != cbData) {
return FALSE; return NULL;
} }
pbTarget += cbData;
DETOUR_TRACE(("Copied %d byte payload into target process at %p\n", DETOUR_TRACE(("Copied %lu byte payload into target process at %p\n",
cbTotal, pbTarget - cbTotal)); cbData, pbTarget));
return TRUE;
SetLastError(NO_ERROR);
return pbTarget;
} }
static BOOL s_fSearchedForHelper = FALSE; static BOOL s_fSearchedForHelper = FALSE;
@ -949,7 +1147,7 @@ VOID CALLBACK DetourFinishHelperProcess(_In_ HWND,
hProcess = OpenProcess(PROCESS_ALL_ACCESS, FALSE, s_pHelper->pid); hProcess = OpenProcess(PROCESS_ALL_ACCESS, FALSE, s_pHelper->pid);
if (hProcess == NULL) { if (hProcess == NULL) {
DETOUR_TRACE(("OpenProcess(pid=%d) failed: %d\n", DETOUR_TRACE(("OpenProcess(pid=%lu) failed: %lu\n",
s_pHelper->pid, GetLastError())); s_pHelper->pid, GetLastError()));
Result = 9901; Result = 9901;
goto Cleanup; goto Cleanup;
@ -970,7 +1168,7 @@ VOID CALLBACK DetourFinishHelperProcess(_In_ HWND,
} }
if (!DetourUpdateProcessWithDll(hProcess, rlpDlls, s_pHelper->nDlls)) { if (!DetourUpdateProcessWithDll(hProcess, rlpDlls, s_pHelper->nDlls)) {
DETOUR_TRACE(("DetourUpdateProcessWithDll(pid=%d) failed: %d\n", DETOUR_TRACE(("DetourUpdateProcessWithDll(pid=%lu) failed: %lu\n",
s_pHelper->pid, GetLastError())); s_pHelper->pid, GetLastError()));
Result = 9903; Result = 9903;
goto Cleanup; goto Cleanup;
@ -983,6 +1181,15 @@ VOID CALLBACK DetourFinishHelperProcess(_In_ HWND,
rlpDlls = NULL; rlpDlls = NULL;
} }
// Note: s_pHelper is allocated as part of injecting the payload in DetourCopyPayloadToProcess(..),
// it's a fake section and not data allocated by the system PE loader.
// Delete the payload after execution to release the memory occupied by it
if (s_pHelper != NULL) {
DetourFreePayload(s_pHelper);
s_pHelper = NULL;
}
ExitProcess(Result); ExitProcess(Result);
} }
@ -1146,7 +1353,7 @@ BOOL WINAPI DetourProcessViaHelperDllsA(_In_ DWORD dwTargetPid,
HRESULT hr; HRESULT hr;
DWORD nLen = GetEnvironmentVariableA("WINDIR", szExe, ARRAYSIZE(szExe)); DWORD nLen = GetEnvironmentVariableA("WINDIR", szExe, ARRAYSIZE(szExe));
DETOUR_TRACE(("DetourProcessViaHelperDlls(pid=%d,dlls=%d)\n", dwTargetPid, nDlls)); DETOUR_TRACE(("DetourProcessViaHelperDlls(pid=%lu,dlls=%lu)\n", dwTargetPid, nDlls));
if (nDlls < 1 || nDlls > 4096) { if (nDlls < 1 || nDlls > 4096) {
SetLastError(ERROR_INVALID_PARAMETER); SetLastError(ERROR_INVALID_PARAMETER);
goto Cleanup; goto Cleanup;
@ -1172,8 +1379,10 @@ BOOL WINAPI DetourProcessViaHelperDllsA(_In_ DWORD dwTargetPid,
goto Cleanup; goto Cleanup;
} }
//for East Asia languages and so on, like Chinese, print format with "%hs" can not work fine before user call _tsetlocale(LC_ALL,_T(".ACP"));
//so we can't use "%hs" in format string, because the dll that contain this code would inject to any process, even not call _tsetlocale(LC_ALL,_T(".ACP")) before
hr = StringCchPrintfA(szCommand, ARRAYSIZE(szCommand), hr = StringCchPrintfA(szCommand, ARRAYSIZE(szCommand),
"rundll32.exe \"%hs\",#1", &helper->rDlls[0]); "rundll32.exe \"%s\",#1", &helper->rDlls[0]);
if (!SUCCEEDED(hr)) { if (!SUCCEEDED(hr)) {
goto Cleanup; goto Cleanup;
} }
@ -1189,7 +1398,7 @@ BOOL WINAPI DetourProcessViaHelperDllsA(_In_ DWORD dwTargetPid,
if (!DetourCopyPayloadToProcess(pi.hProcess, if (!DetourCopyPayloadToProcess(pi.hProcess,
DETOUR_EXE_HELPER_GUID, DETOUR_EXE_HELPER_GUID,
helper, helper->cb)) { helper, helper->cb)) {
DETOUR_TRACE(("DetourCopyPayloadToProcess failed: %d\n", GetLastError())); DETOUR_TRACE(("DetourCopyPayloadToProcess failed: %lu\n", GetLastError()));
TerminateProcess(pi.hProcess, ~0u); TerminateProcess(pi.hProcess, ~0u);
CloseHandle(pi.hProcess); CloseHandle(pi.hProcess);
CloseHandle(pi.hThread); CloseHandle(pi.hThread);
@ -1206,13 +1415,13 @@ BOOL WINAPI DetourProcessViaHelperDllsA(_In_ DWORD dwTargetPid,
CloseHandle(pi.hThread); CloseHandle(pi.hThread);
if (dwResult != 0) { if (dwResult != 0) {
DETOUR_TRACE(("Rundll32.exe failed: result=%d\n", dwResult)); DETOUR_TRACE(("Rundll32.exe failed: result=%lu\n", dwResult));
goto Cleanup; goto Cleanup;
} }
Result = TRUE; Result = TRUE;
} }
else { else {
DETOUR_TRACE(("CreateProcess failed: %d\n", GetLastError())); DETOUR_TRACE(("CreateProcess failed: %lu\n", GetLastError()));
goto Cleanup; goto Cleanup;
} }
@ -1240,9 +1449,11 @@ BOOL WINAPI DetourProcessViaHelperDllsW(_In_ DWORD dwTargetPid,
WCHAR szCommand[MAX_PATH]; WCHAR szCommand[MAX_PATH];
PDETOUR_EXE_HELPER helper = NULL; PDETOUR_EXE_HELPER helper = NULL;
HRESULT hr; HRESULT hr;
WCHAR szDllName[MAX_PATH];
int cchWrittenWideChar;
DWORD nLen = GetEnvironmentVariableW(L"WINDIR", szExe, ARRAYSIZE(szExe)); DWORD nLen = GetEnvironmentVariableW(L"WINDIR", szExe, ARRAYSIZE(szExe));
DETOUR_TRACE(("DetourProcessViaHelperDlls(pid=%d,dlls=%d)\n", dwTargetPid, nDlls)); DETOUR_TRACE(("DetourProcessViaHelperDlls(pid=%lu,dlls=%lu)\n", dwTargetPid, nDlls));
if (nDlls < 1 || nDlls > 4096) { if (nDlls < 1 || nDlls > 4096) {
SetLastError(ERROR_INVALID_PARAMETER); SetLastError(ERROR_INVALID_PARAMETER);
goto Cleanup; goto Cleanup;
@ -1268,8 +1479,15 @@ BOOL WINAPI DetourProcessViaHelperDllsW(_In_ DWORD dwTargetPid,
goto Cleanup; goto Cleanup;
} }
//for East Asia languages and so on, like Chinese, print format with "%hs" can not work fine before user call _tsetlocale(LC_ALL,_T(".ACP"));
//so we can't use "%hs" in format string, because the dll that contain this code would inject to any process, even not call _tsetlocale(LC_ALL,_T(".ACP")) before
cchWrittenWideChar = MultiByteToWideChar(CP_ACP, 0, &helper->rDlls[0], -1, szDllName, ARRAYSIZE(szDllName));
if (cchWrittenWideChar >= ARRAYSIZE(szDllName) || cchWrittenWideChar <= 0) {
goto Cleanup;
}
hr = StringCchPrintfW(szCommand, ARRAYSIZE(szCommand), hr = StringCchPrintfW(szCommand, ARRAYSIZE(szCommand),
L"rundll32.exe \"%hs\",#1", &helper->rDlls[0]); L"rundll32.exe \"%s\",#1", szDllName);
if (!SUCCEEDED(hr)) { if (!SUCCEEDED(hr)) {
goto Cleanup; goto Cleanup;
} }
@ -1285,15 +1503,13 @@ BOOL WINAPI DetourProcessViaHelperDllsW(_In_ DWORD dwTargetPid,
if (!DetourCopyPayloadToProcess(pi.hProcess, if (!DetourCopyPayloadToProcess(pi.hProcess,
DETOUR_EXE_HELPER_GUID, DETOUR_EXE_HELPER_GUID,
helper, helper->cb)) { helper, helper->cb)) {
DETOUR_TRACE(("DetourCopyPayloadToProcess failed: %d\n", GetLastError())); DETOUR_TRACE(("DetourCopyPayloadToProcess failed: %lu\n", GetLastError()));
TerminateProcess(pi.hProcess, ~0u); TerminateProcess(pi.hProcess, ~0u);
CloseHandle(pi.hProcess); CloseHandle(pi.hProcess);
CloseHandle(pi.hThread); CloseHandle(pi.hThread);
goto Cleanup; goto Cleanup;
} }
ResumeThread(pi.hThread);
ResumeThread(pi.hThread); ResumeThread(pi.hThread);
WaitForSingleObject(pi.hProcess, INFINITE); WaitForSingleObject(pi.hProcess, INFINITE);
@ -1304,13 +1520,13 @@ BOOL WINAPI DetourProcessViaHelperDllsW(_In_ DWORD dwTargetPid,
CloseHandle(pi.hThread); CloseHandle(pi.hThread);
if (dwResult != 0) { if (dwResult != 0) {
DETOUR_TRACE(("Rundll32.exe failed: result=%d\n", dwResult)); DETOUR_TRACE(("Rundll32.exe failed: result=%lu\n", dwResult));
goto Cleanup; goto Cleanup;
} }
Result = TRUE; Result = TRUE;
} }
else { else {
DETOUR_TRACE(("CreateProcess failed: %d\n", GetLastError())); DETOUR_TRACE(("CreateProcess failed: %lu\n", GetLastError()));
goto Cleanup; goto Cleanup;
} }

View File

@ -18,6 +18,27 @@
#define NOTHROW #define NOTHROW
//////////////////////////////////////////////////////////////////////////////
//
#ifdef _DEBUG
extern "C" IMAGE_DOS_HEADER __ImageBase;
int Detour_AssertExprWithFunctionName(int reportType, const char* filename, int linenumber, const char* FunctionName, const char* msg)
{
int nRet = 0;
DWORD dwLastError = GetLastError();
CHAR szModuleNameWithFunctionName[MAX_PATH * 2];
szModuleNameWithFunctionName[0] = 0;
GetModuleFileNameA((HMODULE)&__ImageBase, szModuleNameWithFunctionName, ARRAYSIZE(szModuleNameWithFunctionName));
StringCchCatNA(szModuleNameWithFunctionName, ARRAYSIZE(szModuleNameWithFunctionName), ",", ARRAYSIZE(szModuleNameWithFunctionName) - strlen(szModuleNameWithFunctionName) - 1);
StringCchCatNA(szModuleNameWithFunctionName, ARRAYSIZE(szModuleNameWithFunctionName), FunctionName, ARRAYSIZE(szModuleNameWithFunctionName) - strlen(szModuleNameWithFunctionName) - 1);
SetLastError(dwLastError);
nRet = _CrtDbgReport(reportType, filename, linenumber, szModuleNameWithFunctionName, msg);
SetLastError(dwLastError);
return nRet;
}
#endif// _DEBUG
////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////
// //
struct _DETOUR_ALIGN struct _DETOUR_ALIGN
@ -186,7 +207,7 @@ inline void detour_find_jmp_bounds(PBYTE pbCode,
// We have to place trampolines within +/- 2GB of code. // We have to place trampolines within +/- 2GB of code.
ULONG_PTR lo = detour_2gb_below((ULONG_PTR)pbCode); ULONG_PTR lo = detour_2gb_below((ULONG_PTR)pbCode);
ULONG_PTR hi = detour_2gb_above((ULONG_PTR)pbCode); ULONG_PTR hi = detour_2gb_above((ULONG_PTR)pbCode);
DETOUR_TRACE(("[%p..%p..%p]\n", lo, pbCode, hi)); DETOUR_TRACE(("[%p..%p..%p]\n", (PVOID)lo, pbCode, (PVOID)hi));
// And, within +/- 2GB of relative jmp targets. // And, within +/- 2GB of relative jmp targets.
if (pbCode[0] == 0xe9) { // jmp +imm32 if (pbCode[0] == 0xe9) { // jmp +imm32
@ -198,7 +219,7 @@ inline void detour_find_jmp_bounds(PBYTE pbCode,
else { else {
lo = detour_2gb_below((ULONG_PTR)pbNew); lo = detour_2gb_below((ULONG_PTR)pbNew);
} }
DETOUR_TRACE(("[%p..%p..%p] +imm32\n", lo, pbCode, hi)); DETOUR_TRACE(("[%p..%p..%p] +imm32\n", (PVOID)lo, pbCode, (PVOID)hi));
} }
*ppLower = (PDETOUR_TRAMPOLINE)lo; *ppLower = (PDETOUR_TRAMPOLINE)lo;
@ -399,7 +420,7 @@ inline void detour_find_jmp_bounds(PBYTE pbCode,
// We have to place trampolines within +/- 2GB of code. // We have to place trampolines within +/- 2GB of code.
ULONG_PTR lo = detour_2gb_below((ULONG_PTR)pbCode); ULONG_PTR lo = detour_2gb_below((ULONG_PTR)pbCode);
ULONG_PTR hi = detour_2gb_above((ULONG_PTR)pbCode); ULONG_PTR hi = detour_2gb_above((ULONG_PTR)pbCode);
DETOUR_TRACE(("[%p..%p..%p]\n", lo, pbCode, hi)); DETOUR_TRACE(("[%p..%p..%p]\n", (PVOID)lo, pbCode, (PVOID)hi));
// And, within +/- 2GB of relative jmp vectors. // And, within +/- 2GB of relative jmp vectors.
if (pbCode[0] == 0xff && pbCode[1] == 0x25) { // jmp [+imm32] if (pbCode[0] == 0xff && pbCode[1] == 0x25) { // jmp [+imm32]
@ -411,7 +432,7 @@ inline void detour_find_jmp_bounds(PBYTE pbCode,
else { else {
lo = detour_2gb_below((ULONG_PTR)pbNew); lo = detour_2gb_below((ULONG_PTR)pbNew);
} }
DETOUR_TRACE(("[%p..%p..%p] [+imm32]\n", lo, pbCode, hi)); DETOUR_TRACE(("[%p..%p..%p] [+imm32]\n", (PVOID)lo, pbCode, (PVOID)hi));
} }
// And, within +/- 2GB of relative jmp targets. // And, within +/- 2GB of relative jmp targets.
else if (pbCode[0] == 0xe9) { // jmp +imm32 else if (pbCode[0] == 0xe9) { // jmp +imm32
@ -423,7 +444,7 @@ inline void detour_find_jmp_bounds(PBYTE pbCode,
else { else {
lo = detour_2gb_below((ULONG_PTR)pbNew); lo = detour_2gb_below((ULONG_PTR)pbNew);
} }
DETOUR_TRACE(("[%p..%p..%p] +imm32\n", lo, pbCode, hi)); DETOUR_TRACE(("[%p..%p..%p] +imm32\n", (PVOID)lo, pbCode, (PVOID)hi));
} }
*ppLower = (PDETOUR_TRAMPOLINE)lo; *ppLower = (PDETOUR_TRAMPOLINE)lo;
@ -818,7 +839,7 @@ inline void detour_find_jmp_bounds(PBYTE pbCode,
// We have to place trampolines within +/- 2GB of code. // We have to place trampolines within +/- 2GB of code.
ULONG_PTR lo = detour_2gb_below((ULONG_PTR)pbCode); ULONG_PTR lo = detour_2gb_below((ULONG_PTR)pbCode);
ULONG_PTR hi = detour_2gb_above((ULONG_PTR)pbCode); ULONG_PTR hi = detour_2gb_above((ULONG_PTR)pbCode);
DETOUR_TRACE(("[%p..%p..%p]\n", lo, pbCode, hi)); DETOUR_TRACE(("[%p..%p..%p]\n", (PVOID)lo, pbCode, (PVOID)hi));
*ppLower = (PDETOUR_TRAMPOLINE)lo; *ppLower = (PDETOUR_TRAMPOLINE)lo;
*ppUpper = (PDETOUR_TRAMPOLINE)hi; *ppUpper = (PDETOUR_TRAMPOLINE)hi;
@ -1124,7 +1145,7 @@ inline void detour_find_jmp_bounds(PBYTE pbCode,
ULONG_PTR lo = detour_2gb_below((ULONG_PTR)pbCode); ULONG_PTR lo = detour_2gb_below((ULONG_PTR)pbCode);
ULONG_PTR hi = detour_2gb_above((ULONG_PTR)pbCode); ULONG_PTR hi = detour_2gb_above((ULONG_PTR)pbCode);
DETOUR_TRACE(("[%p..%p..%p]\n", lo, pbCode, hi)); DETOUR_TRACE(("[%p..%p..%p]\n", (PVOID)lo, pbCode, (PVOID)hi));
*ppLower = (PDETOUR_TRAMPOLINE)lo; *ppLower = (PDETOUR_TRAMPOLINE)lo;
*ppUpper = (PDETOUR_TRAMPOLINE)hi; *ppUpper = (PDETOUR_TRAMPOLINE)hi;
@ -1237,7 +1258,7 @@ static PVOID detour_alloc_region_from_lo(PBYTE pbLo, PBYTE pbHi)
break; break;
} }
DETOUR_TRACE((" Try %p => %p..%p %6x\n", DETOUR_TRACE((" Try %p => %p..%p %6lx\n",
pbTry, pbTry,
mbi.BaseAddress, mbi.BaseAddress,
(PBYTE)mbi.BaseAddress + mbi.RegionSize - 1, (PBYTE)mbi.BaseAddress + mbi.RegionSize - 1,
@ -1252,6 +1273,9 @@ static PVOID detour_alloc_region_from_lo(PBYTE pbLo, PBYTE pbHi)
if (pv != NULL) { if (pv != NULL) {
return pv; return pv;
} }
else if (GetLastError() == ERROR_DYNAMIC_CODE_BLOCKED) {
return NULL;
}
pbTry += DETOUR_REGION_SIZE; pbTry += DETOUR_REGION_SIZE;
} }
else { else {
@ -1284,7 +1308,7 @@ static PVOID detour_alloc_region_from_hi(PBYTE pbLo, PBYTE pbHi)
break; break;
} }
DETOUR_TRACE((" Try %p => %p..%p %6x\n", DETOUR_TRACE((" Try %p => %p..%p %6lx\n",
pbTry, pbTry,
mbi.BaseAddress, mbi.BaseAddress,
(PBYTE)mbi.BaseAddress + mbi.RegionSize - 1, (PBYTE)mbi.BaseAddress + mbi.RegionSize - 1,
@ -1299,6 +1323,9 @@ static PVOID detour_alloc_region_from_hi(PBYTE pbLo, PBYTE pbHi)
if (pv != NULL) { if (pv != NULL) {
return pv; return pv;
} }
else if (GetLastError() == ERROR_DYNAMIC_CODE_BLOCKED) {
return NULL;
}
pbTry -= DETOUR_REGION_SIZE; pbTry -= DETOUR_REGION_SIZE;
} }
else { else {
@ -1698,7 +1725,7 @@ LONG WINAPI DetourTransactionCommitEx(_Out_opt_ PVOID **pppFailedPointer)
#endif // DETOURS_ARM #endif // DETOURS_ARM
} }
else { else {
DETOUR_TRACE(("detours: pbTramp =%p, pbRemain=%p, pbDetour=%p, cbRestore=%d\n", DETOUR_TRACE(("detours: pbTramp =%p, pbRemain=%p, pbDetour=%p, cbRestore=%u\n",
o->pTrampoline, o->pTrampoline,
o->pTrampoline->pbRemain, o->pTrampoline->pbRemain,
o->pTrampoline->pbDetour, o->pTrampoline->pbDetour,
@ -1990,13 +2017,13 @@ LONG WINAPI DetourAttachEx(_Inout_ PVOID *ppPointer,
} }
if (s_nPendingThreadId != (LONG)GetCurrentThreadId()) { if (s_nPendingThreadId != (LONG)GetCurrentThreadId()) {
DETOUR_TRACE(("transaction conflict with thread id=%d\n", s_nPendingThreadId)); DETOUR_TRACE(("transaction conflict with thread id=%ld\n", s_nPendingThreadId));
return ERROR_INVALID_OPERATION; return ERROR_INVALID_OPERATION;
} }
// If any of the pending operations failed, then we don't need to do this. // If any of the pending operations failed, then we don't need to do this.
if (s_nPendingError != NO_ERROR) { if (s_nPendingError != NO_ERROR) {
DETOUR_TRACE(("pending transaction error=%d\n", s_nPendingError)); DETOUR_TRACE(("pending transaction error=%ld\n", s_nPendingError));
return s_nPendingError; return s_nPendingError;
} }
@ -2177,7 +2204,7 @@ LONG WINAPI DetourAttachEx(_Inout_ PVOID *ppPointer,
pTrampoline->rAlign[n].obTrampoline == 0) { pTrampoline->rAlign[n].obTrampoline == 0) {
break; break;
} }
DETOUR_TRACE((" %d/%d", DETOUR_TRACE((" %u/%u",
pTrampoline->rAlign[n].obTarget, pTrampoline->rAlign[n].obTarget,
pTrampoline->rAlign[n].obTrampoline pTrampoline->rAlign[n].obTrampoline
)); ));
@ -2545,4 +2572,20 @@ BOOL WINAPI DetourVirtualProtectSameExecute(_In_ PVOID pAddress,
pAddress, nSize, dwNewProtect, pdwOldProtect); pAddress, nSize, dwNewProtect, pdwOldProtect);
} }
BOOL WINAPI DetourAreSameGuid(_In_ REFGUID left, _In_ REFGUID right)
{
return
left.Data1 == right.Data1 &&
left.Data2 == right.Data2 &&
left.Data3 == right.Data3 &&
left.Data4[0] == right.Data4[0] &&
left.Data4[1] == right.Data4[1] &&
left.Data4[2] == right.Data4[2] &&
left.Data4[3] == right.Data4[3] &&
left.Data4[4] == right.Data4[4] &&
left.Data4[5] == right.Data4[5] &&
left.Data4[6] == right.Data4[6] &&
left.Data4[7] == right.Data4[7];
}
// End of File // End of File

View File

@ -28,6 +28,15 @@
#pragma warning(disable:4091) // empty typedef #pragma warning(disable:4091) // empty typedef
#endif #endif
// Suppress declspec(dllimport) for the sake of Detours
// users that provide kernel32 functionality themselves.
// This is ok in the mainstream case, it will just cost
// an extra instruction calling some functions, which
// LTCG optimizes away.
//
#define _KERNEL32_ 1
#define _USER32_ 1
#include <windows.h> #include <windows.h>
#if (_MSC_VER < 1310) #if (_MSC_VER < 1310)
#else #else
@ -36,8 +45,28 @@
#pragma warning(disable:6102 6103) // /analyze warnings #pragma warning(disable:6102 6103) // /analyze warnings
#endif #endif
#include <strsafe.h> #include <strsafe.h>
#include <intsafe.h>
#pragma warning(pop) #pragma warning(pop)
#endif #endif
#include <crtdbg.h>
// Allow Detours to cleanly compile with the MingW toolchain.
//
#ifdef __GNUC__
#define __try
#define __except(x) if (0)
#include <strsafe.h>
#endif
// From winerror.h, as this error isn't found in some SDKs:
//
// MessageId: ERROR_DYNAMIC_CODE_BLOCKED
//
// MessageText:
//
// The operation was blocked as the process prohibits dynamic code generation.
//
#define ERROR_DYNAMIC_CODE_BLOCKED 1655L
#endif // DETOURS_INTERNAL #endif // DETOURS_INTERNAL
@ -99,7 +128,7 @@
////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////
// //
#if (_MSC_VER < 1299) #if (_MSC_VER < 1299) && !defined(__MINGW32__)
typedef LONG LONG_PTR; typedef LONG LONG_PTR;
typedef ULONG ULONG_PTR; typedef ULONG ULONG_PTR;
#endif #endif
@ -120,6 +149,7 @@ typedef ULONG ULONG_PTR;
#undef _In_ #undef _In_
#undef _In_bytecount_ #undef _In_bytecount_
#undef _In_count_ #undef _In_count_
#undef __in_ecount
#undef _In_opt_ #undef _In_opt_
#undef _In_opt_bytecount_ #undef _In_opt_bytecount_
#undef _In_opt_count_ #undef _In_opt_count_
@ -176,6 +206,10 @@ typedef ULONG ULONG_PTR;
#define _In_count_(x) #define _In_count_(x)
#endif #endif
#ifndef __in_ecount
#define __in_ecount(x)
#endif
#ifndef _In_opt_ #ifndef _In_opt_
#define _In_opt_ #define _In_opt_
#endif #endif
@ -581,16 +615,17 @@ _Readable_bytes_(*pcbData)
_Success_(return != NULL) _Success_(return != NULL)
PVOID WINAPI DetourFindPayload(_In_opt_ HMODULE hModule, PVOID WINAPI DetourFindPayload(_In_opt_ HMODULE hModule,
_In_ REFGUID rguid, _In_ REFGUID rguid,
_Out_ DWORD *pcbData); _Out_opt_ DWORD *pcbData);
_Writable_bytes_(*pcbData) _Writable_bytes_(*pcbData)
_Readable_bytes_(*pcbData) _Readable_bytes_(*pcbData)
_Success_(return != NULL) _Success_(return != NULL)
PVOID WINAPI DetourFindPayloadEx(_In_ REFGUID rguid, PVOID WINAPI DetourFindPayloadEx(_In_ REFGUID rguid,
_Out_ DWORD * pcbData); _Out_opt_ DWORD *pcbData);
DWORD WINAPI DetourGetSizeOfPayloads(_In_opt_ HMODULE hModule); DWORD WINAPI DetourGetSizeOfPayloads(_In_opt_ HMODULE hModule);
BOOL WINAPI DetourFreePayload(_In_ PVOID pvData);
///////////////////////////////////////////////// Persistent Binary Functions. ///////////////////////////////////////////////// Persistent Binary Functions.
// //
@ -629,6 +664,11 @@ BOOL WINAPI DetourBinaryClose(_In_ PDETOUR_BINARY pBinary);
/////////////////////////////////////////////////// Create Process & Load Dll. /////////////////////////////////////////////////// Create Process & Load Dll.
// //
_Success_(return != NULL)
PVOID WINAPI DetourFindRemotePayload(_In_ HANDLE hProcess,
_In_ REFGUID rguid,
_Out_opt_ DWORD *pcbData);
typedef BOOL (WINAPI *PDETOUR_CREATE_PROCESS_ROUTINEA)( typedef BOOL (WINAPI *PDETOUR_CREATE_PROCESS_ROUTINEA)(
_In_opt_ LPCSTR lpApplicationName, _In_opt_ LPCSTR lpApplicationName,
_Inout_opt_ LPSTR lpCommandLine, _Inout_opt_ LPSTR lpCommandLine,
@ -795,8 +835,14 @@ BOOL WINAPI DetourUpdateProcessWithDllEx(_In_ HANDLE hProcess,
BOOL WINAPI DetourCopyPayloadToProcess(_In_ HANDLE hProcess, BOOL WINAPI DetourCopyPayloadToProcess(_In_ HANDLE hProcess,
_In_ REFGUID rguid, _In_ REFGUID rguid,
_In_reads_bytes_(cbData) PVOID pvData, _In_reads_bytes_(cbData) LPCVOID pvData,
_In_ DWORD cbData); _In_ DWORD cbData);
_Success_(return != NULL)
PVOID WINAPI DetourCopyPayloadToProcessEx(_In_ HANDLE hProcess,
_In_ REFGUID rguid,
_In_reads_bytes_(cbData) LPCVOID pvData,
_In_ DWORD cbData);
BOOL WINAPI DetourRestoreAfterWith(VOID); BOOL WINAPI DetourRestoreAfterWith(VOID);
BOOL WINAPI DetourRestoreAfterWithEx(_In_reads_bytes_(cbData) PVOID pvData, BOOL WINAPI DetourRestoreAfterWithEx(_In_reads_bytes_(cbData) PVOID pvData,
_In_ DWORD cbData); _In_ DWORD cbData);
@ -812,6 +858,60 @@ VOID CALLBACK DetourFinishHelperProcess(_In_ HWND,
} }
#endif // __cplusplus #endif // __cplusplus
/////////////////////////////////////////////////// Type-safe overloads for C++
//
#if __cplusplus >= 201103L || _MSVC_LANG >= 201103L
#include <type_traits>
template<typename T>
struct DetoursIsFunctionPointer : std::false_type {};
template<typename T>
struct DetoursIsFunctionPointer<T*> : std::is_function<typename std::remove_pointer<T>::type> {};
template<
typename T,
typename std::enable_if<DetoursIsFunctionPointer<T>::value, int>::type = 0>
LONG DetourAttach(_Inout_ T *ppPointer,
_In_ T pDetour) noexcept
{
return DetourAttach(
reinterpret_cast<void**>(ppPointer),
reinterpret_cast<void*>(pDetour));
}
template<
typename T,
typename std::enable_if<DetoursIsFunctionPointer<T>::value, int>::type = 0>
LONG DetourAttachEx(_Inout_ T *ppPointer,
_In_ T pDetour,
_Out_opt_ PDETOUR_TRAMPOLINE *ppRealTrampoline,
_Out_opt_ T *ppRealTarget,
_Out_opt_ T *ppRealDetour) noexcept
{
return DetourAttachEx(
reinterpret_cast<void**>(ppPointer),
reinterpret_cast<void*>(pDetour),
ppRealTrampoline,
reinterpret_cast<void**>(ppRealTarget),
reinterpret_cast<void**>(ppRealDetour));
}
template<
typename T,
typename std::enable_if<DetoursIsFunctionPointer<T>::value, int>::type = 0>
LONG DetourDetach(_Inout_ T *ppPointer,
_In_ T pDetour) noexcept
{
return DetourDetach(
reinterpret_cast<void**>(ppPointer),
reinterpret_cast<void*>(pDetour));
}
#endif // __cplusplus >= 201103L || _MSVC_LANG >= 201103L
//
//////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////// Detours Internal Definitions. //////////////////////////////////////////////// Detours Internal Definitions.
// //
#ifdef __cplusplus #ifdef __cplusplus
@ -822,7 +922,7 @@ VOID CALLBACK DetourFinishHelperProcess(_In_ HWND,
////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////
// //
#if (_MSC_VER < 1299) #if (_MSC_VER < 1299) && !defined(__GNUC__)
#include <imagehlp.h> #include <imagehlp.h>
typedef IMAGEHLP_MODULE IMAGEHLP_MODULE64; typedef IMAGEHLP_MODULE IMAGEHLP_MODULE64;
typedef PIMAGEHLP_MODULE PIMAGEHLP_MODULE64; typedef PIMAGEHLP_MODULE PIMAGEHLP_MODULE64;
@ -884,6 +984,21 @@ PDETOUR_SYM_INFO DetourLoadImageHlp(VOID);
#endif #endif
#define _CRT_STDIO_ARBITRARY_WIDE_SPECIFIERS 1 #define _CRT_STDIO_ARBITRARY_WIDE_SPECIFIERS 1
#ifdef _DEBUG
int Detour_AssertExprWithFunctionName(int reportType, const char* filename, int linenumber, const char* FunctionName, const char* msg);
#define DETOUR_ASSERT_EXPR_WITH_FUNCTION(expr, msg) \
(void) ((expr) || \
(1 != Detour_AssertExprWithFunctionName(_CRT_ASSERT, __FILE__, __LINE__,__FUNCTION__, msg)) || \
(_CrtDbgBreak(), 0))
#define DETOUR_ASSERT(expr) DETOUR_ASSERT_EXPR_WITH_FUNCTION((expr), #expr)
#else// _DEBUG
#define DETOUR_ASSERT(expr)
#endif// _DEBUG
#ifndef DETOUR_TRACE #ifndef DETOUR_TRACE
#if DETOUR_DEBUG #if DETOUR_DEBUG
#define DETOUR_TRACE(x) printf x #define DETOUR_TRACE(x) printf x
@ -1090,6 +1205,9 @@ BOOL WINAPI DetourVirtualProtectSameExecute(_In_ PVOID pAddress,
_In_ SIZE_T nSize, _In_ SIZE_T nSize,
_In_ DWORD dwNewProtect, _In_ DWORD dwNewProtect,
_Out_ PDWORD pdwOldProtect); _Out_ PDWORD pdwOldProtect);
// Detours must depend only on kernel32.lib, so we cannot use IsEqualGUID
BOOL WINAPI DetourAreSameGuid(_In_ REFGUID left, _In_ REFGUID right);
#ifdef __cplusplus #ifdef __cplusplus
} }
#endif // __cplusplus #endif // __cplusplus

File diff suppressed because it is too large Load Diff

View File

@ -146,6 +146,8 @@ protected:
DWORD m_cbAlloc; DWORD m_cbAlloc;
}; };
class CImageImportName;
class CImageImportFile class CImageImportFile
{ {
friend class CImage; friend class CImage;
@ -534,18 +536,7 @@ PBYTE CImageData::Find(REFGUID rguid, DWORD *pcbData)
continue; continue;
} }
if (pRecord->guid.Data1 == rguid.Data1 && if (DetourAreSameGuid(pRecord->guid, rguid)) {
pRecord->guid.Data2 == rguid.Data2 &&
pRecord->guid.Data3 == rguid.Data3 &&
pRecord->guid.Data4[0] == rguid.Data4[0] &&
pRecord->guid.Data4[1] == rguid.Data4[1] &&
pRecord->guid.Data4[2] == rguid.Data4[2] &&
pRecord->guid.Data4[3] == rguid.Data4[3] &&
pRecord->guid.Data4[4] == rguid.Data4[4] &&
pRecord->guid.Data4[5] == rguid.Data4[5] &&
pRecord->guid.Data4[6] == rguid.Data4[6] &&
pRecord->guid.Data4[7] == rguid.Data4[7]) {
*pcbData = cbBytes - sizeof(DETOUR_SECTION_RECORD); *pcbData = cbBytes - sizeof(DETOUR_SECTION_RECORD);
return (PBYTE)(pRecord + 1); return (PBYTE)(pRecord + 1);
} }

View File

@ -23,8 +23,8 @@
////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////
// //
const GUID DETOUR_EXE_RESTORE_GUID = { const GUID DETOUR_EXE_RESTORE_GUID = {
0x2ed7a3ff, 0x3339, 0x4a8d, 0xbda26f34, 0xbc82, 0x4829,
{ 0x80, 0x5c, 0xd4, 0x98, 0x15, 0x3f, 0xc2, 0x8f }}; { 0x9e, 0x64, 0x74, 0x2c, 0x4, 0xc8, 0x4f, 0xa0 } };
////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////
// //
@ -142,6 +142,11 @@ PDETOUR_SYM_INFO DetourLoadImageHlp(VOID)
PVOID WINAPI DetourFindFunction(_In_ LPCSTR pszModule, PVOID WINAPI DetourFindFunction(_In_ LPCSTR pszModule,
_In_ LPCSTR pszFunction) _In_ LPCSTR pszFunction)
{ {
if (pszFunction == NULL) {
SetLastError(ERROR_INVALID_PARAMETER);
return NULL;
}
/////////////////////////////////////////////// First, try GetProcAddress. /////////////////////////////////////////////// First, try GetProcAddress.
// //
#pragma prefast(suppress:28752, "We don't do the unicode conversion for LoadLibraryExA.") #pragma prefast(suppress:28752, "We don't do the unicode conversion for LoadLibraryExA.")
@ -160,7 +165,7 @@ PVOID WINAPI DetourFindFunction(_In_ LPCSTR pszModule,
DETOUR_TRACE(("DetourFindFunction(%hs, %hs)\n", pszModule, pszFunction)); DETOUR_TRACE(("DetourFindFunction(%hs, %hs)\n", pszModule, pszFunction));
PDETOUR_SYM_INFO pSymInfo = DetourLoadImageHlp(); PDETOUR_SYM_INFO pSymInfo = DetourLoadImageHlp();
if (pSymInfo == NULL) { if (pSymInfo == NULL) {
DETOUR_TRACE(("DetourLoadImageHlp failed: %d\n", DETOUR_TRACE(("DetourLoadImageHlp failed: %lu\n",
GetLastError())); GetLastError()));
return NULL; return NULL;
} }
@ -169,7 +174,7 @@ PVOID WINAPI DetourFindFunction(_In_ LPCSTR pszModule,
(PCHAR)pszModule, NULL, (PCHAR)pszModule, NULL,
(DWORD64)hModule, 0) == 0) { (DWORD64)hModule, 0) == 0) {
if (ERROR_SUCCESS != GetLastError()) { if (ERROR_SUCCESS != GetLastError()) {
DETOUR_TRACE(("SymLoadModule64(%p) failed: %d\n", DETOUR_TRACE(("SymLoadModule64(%p) failed: %lu\n",
pSymInfo->hProcess, GetLastError())); pSymInfo->hProcess, GetLastError()));
return NULL; return NULL;
} }
@ -181,24 +186,24 @@ PVOID WINAPI DetourFindFunction(_In_ LPCSTR pszModule,
ZeroMemory(&modinfo, sizeof(modinfo)); ZeroMemory(&modinfo, sizeof(modinfo));
modinfo.SizeOfStruct = sizeof(modinfo); modinfo.SizeOfStruct = sizeof(modinfo);
if (!pSymInfo->pfSymGetModuleInfo64(pSymInfo->hProcess, (DWORD64)hModule, &modinfo)) { if (!pSymInfo->pfSymGetModuleInfo64(pSymInfo->hProcess, (DWORD64)hModule, &modinfo)) {
DETOUR_TRACE(("SymGetModuleInfo64(%p, %p) failed: %d\n", DETOUR_TRACE(("SymGetModuleInfo64(%p, %p) failed: %lu\n",
pSymInfo->hProcess, hModule, GetLastError())); pSymInfo->hProcess, hModule, GetLastError()));
return NULL; return NULL;
} }
hrRet = StringCchCopyA(szFullName, sizeof(szFullName)/sizeof(CHAR), modinfo.ModuleName); hrRet = StringCchCopyA(szFullName, sizeof(szFullName)/sizeof(CHAR), modinfo.ModuleName);
if (FAILED(hrRet)) { if (FAILED(hrRet)) {
DETOUR_TRACE(("StringCchCopyA failed: %08x\n", hrRet)); DETOUR_TRACE(("StringCchCopyA failed: %08lx\n", hrRet));
return NULL; return NULL;
} }
hrRet = StringCchCatA(szFullName, sizeof(szFullName)/sizeof(CHAR), "!"); hrRet = StringCchCatA(szFullName, sizeof(szFullName)/sizeof(CHAR), "!");
if (FAILED(hrRet)) { if (FAILED(hrRet)) {
DETOUR_TRACE(("StringCchCatA failed: %08x\n", hrRet)); DETOUR_TRACE(("StringCchCatA failed: %08lx\n", hrRet));
return NULL; return NULL;
} }
hrRet = StringCchCatA(szFullName, sizeof(szFullName)/sizeof(CHAR), pszFunction); hrRet = StringCchCatA(szFullName, sizeof(szFullName)/sizeof(CHAR), pszFunction);
if (FAILED(hrRet)) { if (FAILED(hrRet)) {
DETOUR_TRACE(("StringCchCatA failed: %08x\n", hrRet)); DETOUR_TRACE(("StringCchCatA failed: %08lx\n", hrRet));
return NULL; return NULL;
} }
@ -215,7 +220,7 @@ PVOID WINAPI DetourFindFunction(_In_ LPCSTR pszModule,
#endif #endif
if (!pSymInfo->pfSymFromName(pSymInfo->hProcess, szFullName, &symbol)) { if (!pSymInfo->pfSymFromName(pSymInfo->hProcess, szFullName, &symbol)) {
DETOUR_TRACE(("SymFromName(%hs) failed: %d\n", szFullName, GetLastError())); DETOUR_TRACE(("SymFromName(%hs) failed: %lu\n", szFullName, GetLastError()));
return NULL; return NULL;
} }
@ -277,6 +282,7 @@ HMODULE WINAPI DetourEnumerateModules(_In_opt_ HMODULE hModuleLast)
continue; continue;
} }
SetLastError(NO_ERROR);
return (HMODULE)pDosHeader; return (HMODULE)pDosHeader;
} }
#pragma prefast(suppress:28940, "A bad pointer means this probably isn't a PE header.") #pragma prefast(suppress:28940, "A bad pointer means this probably isn't a PE header.")
@ -340,7 +346,7 @@ PVOID WINAPI DetourGetEntryPoint(_In_opt_ HMODULE hModule)
} }
SetLastError(NO_ERROR); SetLastError(NO_ERROR);
return GetProcAddress(hClr, "_CorExeMain"); return (PVOID)GetProcAddress(hClr, "_CorExeMain");
} }
SetLastError(NO_ERROR); SetLastError(NO_ERROR);
@ -456,6 +462,11 @@ BOOL WINAPI DetourEnumerateExports(_In_ HMODULE hModule,
_In_opt_ PVOID pContext, _In_opt_ PVOID pContext,
_In_ PF_DETOUR_ENUMERATE_EXPORT_CALLBACK pfExport) _In_ PF_DETOUR_ENUMERATE_EXPORT_CALLBACK pfExport)
{ {
if (pfExport == NULL) {
SetLastError(ERROR_INVALID_PARAMETER);
return FALSE;
}
PIMAGE_DOS_HEADER pDosHeader = (PIMAGE_DOS_HEADER)hModule; PIMAGE_DOS_HEADER pDosHeader = (PIMAGE_DOS_HEADER)hModule;
if (hModule == NULL) { if (hModule == NULL) {
pDosHeader = (PIMAGE_DOS_HEADER)GetModuleHandleW(NULL); pDosHeader = (PIMAGE_DOS_HEADER)GetModuleHandleW(NULL);
@ -658,6 +669,11 @@ BOOL WINAPI DetourEnumerateImports(_In_opt_ HMODULE hModule,
_In_opt_ PF_DETOUR_IMPORT_FILE_CALLBACK pfImportFile, _In_opt_ PF_DETOUR_IMPORT_FILE_CALLBACK pfImportFile,
_In_opt_ PF_DETOUR_IMPORT_FUNC_CALLBACK pfImportFunc) _In_opt_ PF_DETOUR_IMPORT_FUNC_CALLBACK pfImportFunc)
{ {
if (pfImportFile == NULL || pfImportFunc == NULL) {
SetLastError(ERROR_INVALID_PARAMETER);
return FALSE;
}
_DETOUR_ENUMERATE_IMPORTS_THUNK_CONTEXT const context = { pContext, pfImportFunc }; _DETOUR_ENUMERATE_IMPORTS_THUNK_CONTEXT const context = { pContext, pfImportFunc };
return DetourEnumerateImportsEx(hModule, return DetourEnumerateImportsEx(hModule,
@ -761,7 +777,7 @@ _Readable_bytes_(*pcbData)
_Success_(return != NULL) _Success_(return != NULL)
PVOID WINAPI DetourFindPayload(_In_opt_ HMODULE hModule, PVOID WINAPI DetourFindPayload(_In_opt_ HMODULE hModule,
_In_ REFGUID rguid, _In_ REFGUID rguid,
_Out_ DWORD *pcbData) _Out_opt_ DWORD *pcbData)
{ {
PBYTE pbData = NULL; PBYTE pbData = NULL;
if (pcbData) { if (pcbData) {
@ -789,24 +805,13 @@ PVOID WINAPI DetourFindPayload(_In_opt_ HMODULE hModule,
for (pbData = pbBeg; pbData < pbEnd;) { for (pbData = pbBeg; pbData < pbEnd;) {
DETOUR_SECTION_RECORD *pSection = (DETOUR_SECTION_RECORD *)pbData; DETOUR_SECTION_RECORD *pSection = (DETOUR_SECTION_RECORD *)pbData;
if (pSection->guid.Data1 == rguid.Data1 && if (DetourAreSameGuid(pSection->guid, rguid)) {
pSection->guid.Data2 == rguid.Data2 &&
pSection->guid.Data3 == rguid.Data3 &&
pSection->guid.Data4[0] == rguid.Data4[0] &&
pSection->guid.Data4[1] == rguid.Data4[1] &&
pSection->guid.Data4[2] == rguid.Data4[2] &&
pSection->guid.Data4[3] == rguid.Data4[3] &&
pSection->guid.Data4[4] == rguid.Data4[4] &&
pSection->guid.Data4[5] == rguid.Data4[5] &&
pSection->guid.Data4[6] == rguid.Data4[6] &&
pSection->guid.Data4[7] == rguid.Data4[7]) {
if (pcbData) { if (pcbData) {
*pcbData = pSection->cbBytes - sizeof(*pSection); *pcbData = pSection->cbBytes - sizeof(*pSection);
}
SetLastError(NO_ERROR); SetLastError(NO_ERROR);
return (PBYTE)(pSection + 1); return (PBYTE)(pSection + 1);
} }
}
pbData = (PBYTE)pSection + pSection->cbBytes; pbData = (PBYTE)pSection + pSection->cbBytes;
} }
@ -824,7 +829,7 @@ _Writable_bytes_(*pcbData)
_Readable_bytes_(*pcbData) _Readable_bytes_(*pcbData)
_Success_(return != NULL) _Success_(return != NULL)
PVOID WINAPI DetourFindPayloadEx(_In_ REFGUID rguid, PVOID WINAPI DetourFindPayloadEx(_In_ REFGUID rguid,
_Out_ DWORD * pcbData) _Out_opt_ DWORD *pcbData)
{ {
for (HMODULE hMod = NULL; (hMod = DetourEnumerateModules(hMod)) != NULL;) { for (HMODULE hMod = NULL; (hMod = DetourEnumerateModules(hMod)) != NULL;) {
PVOID pvData; PVOID pvData;
@ -838,6 +843,24 @@ PVOID WINAPI DetourFindPayloadEx(_In_ REFGUID rguid,
return NULL; return NULL;
} }
BOOL WINAPI DetourFreePayload(_In_ PVOID pvData)
{
BOOL fSucceeded = FALSE;
// If you have any doubts about the following code, please refer to the comments in DetourCopyPayloadToProcess.
HMODULE hModule = DetourGetContainingModule(pvData);
DETOUR_ASSERT(hModule != NULL);
if (hModule != NULL) {
fSucceeded = VirtualFree(hModule, 0, MEM_RELEASE);
DETOUR_ASSERT(fSucceeded);
if (fSucceeded) {
hModule = NULL;
}
}
return fSucceeded;
}
BOOL WINAPI DetourRestoreAfterWithEx(_In_reads_bytes_(cbData) PVOID pvData, BOOL WINAPI DetourRestoreAfterWithEx(_In_reads_bytes_(cbData) PVOID pvData,
_In_ DWORD cbData) _In_ DWORD cbData)
{ {
@ -884,6 +907,11 @@ BOOL WINAPI DetourRestoreAfterWithEx(_In_reads_bytes_(cbData) PVOID pvData,
} }
VirtualProtect(pder->pidh, pder->cbidh, dwPermIdh, &dwIgnore); VirtualProtect(pder->pidh, pder->cbidh, dwPermIdh, &dwIgnore);
} }
// Delete the payload after successful recovery to prevent repeated restore
if (fSucceeded) {
DetourFreePayload(pder);
pder = NULL;
}
return fSucceeded; return fSucceeded;
} }

View File

@ -35,7 +35,7 @@ static BOOL UPDATE_IMPORTS_XX(HANDLE hProcess,
if (!ReadProcessMemory(hProcess, pbModule, &idh, sizeof(idh), &cbRead) if (!ReadProcessMemory(hProcess, pbModule, &idh, sizeof(idh), &cbRead)
|| cbRead < sizeof(idh)) { || cbRead < sizeof(idh)) {
DETOUR_TRACE(("ReadProcessMemory(idh@%p..%p) failed: %d\n", DETOUR_TRACE(("ReadProcessMemory(idh@%p..%p) failed: %lu\n",
pbModule, pbModule + sizeof(idh), GetLastError())); pbModule, pbModule + sizeof(idh), GetLastError()));
finish: finish:
@ -51,7 +51,7 @@ static BOOL UPDATE_IMPORTS_XX(HANDLE hProcess,
if (!ReadProcessMemory(hProcess, pbModule + idh.e_lfanew, &inh, sizeof(inh), &cbRead) if (!ReadProcessMemory(hProcess, pbModule + idh.e_lfanew, &inh, sizeof(inh), &cbRead)
|| cbRead < sizeof(inh)) { || cbRead < sizeof(inh)) {
DETOUR_TRACE(("ReadProcessMemory(inh@%p..%p) failed: %d\n", DETOUR_TRACE(("ReadProcessMemory(inh@%p..%p) failed: %lu\n",
pbModule + idh.e_lfanew, pbModule + idh.e_lfanew,
pbModule + idh.e_lfanew + sizeof(inh), pbModule + idh.e_lfanew + sizeof(inh),
GetLastError())); GetLastError()));
@ -82,16 +82,21 @@ static BOOL UPDATE_IMPORTS_XX(HANDLE hProcess,
sizeof(ish), &cbRead) sizeof(ish), &cbRead)
|| cbRead < sizeof(ish)) { || cbRead < sizeof(ish)) {
DETOUR_TRACE(("ReadProcessMemory(ish@%p..%p) failed: %d\n", DETOUR_TRACE(("ReadProcessMemory(ish@%p..%p) failed: %lu\n",
pbModule + dwSec + sizeof(ish) * i, pbModule + dwSec + sizeof(ish) * i,
pbModule + dwSec + sizeof(ish) * (i + 1), pbModule + dwSec + sizeof(ish) * (i + 1),
GetLastError())); GetLastError()));
goto finish; goto finish;
} }
DETOUR_TRACE(("ish[%d] : va=%08x sr=%d\n", i, ish.VirtualAddress, ish.SizeOfRawData)); DETOUR_TRACE(("ish[%lu] : va=%08lx sr=%lu\n", i, ish.VirtualAddress, ish.SizeOfRawData));
// If the file didn't have an IAT_DIRECTORY, we assign it... // If the linker didn't suggest an IAT in the data directories, the
// loader will look for the section of the import directory to be used
// for this instead. Since we put out new IMPORT_DIRECTORY outside any
// section boundary, the loader will not find it. So we provide one
// explicitly to avoid the search.
//
if (inh.IAT_DIRECTORY.VirtualAddress == 0 && if (inh.IAT_DIRECTORY.VirtualAddress == 0 &&
inh.IMPORT_DIRECTORY.VirtualAddress >= ish.VirtualAddress && inh.IMPORT_DIRECTORY.VirtualAddress >= ish.VirtualAddress &&
inh.IMPORT_DIRECTORY.VirtualAddress < ish.VirtualAddress + ish.SizeOfRawData) { inh.IMPORT_DIRECTORY.VirtualAddress < ish.VirtualAddress + ish.SizeOfRawData) {
@ -101,25 +106,78 @@ static BOOL UPDATE_IMPORTS_XX(HANDLE hProcess,
} }
} }
if (inh.IMPORT_DIRECTORY.VirtualAddress != 0 && inh.IMPORT_DIRECTORY.Size == 0) {
// Don't worry about changing the PE file,
// because the load information of the original PE header has been saved and will be restored.
// The change here is just for the following code to work normally
PIMAGE_IMPORT_DESCRIPTOR pImageImport = (PIMAGE_IMPORT_DESCRIPTOR)(pbModule + inh.IMPORT_DIRECTORY.VirtualAddress);
do {
IMAGE_IMPORT_DESCRIPTOR ImageImport;
if (!ReadProcessMemory(hProcess, pImageImport, &ImageImport, sizeof(ImageImport), NULL)) {
DETOUR_TRACE(("ReadProcessMemory failed: %lu\n", GetLastError()));
goto finish;
}
inh.IMPORT_DIRECTORY.Size += sizeof(IMAGE_IMPORT_DESCRIPTOR);
if (!ImageImport.Name) {
break;
}
++pImageImport;
} while (TRUE);
DWORD dwLastError = GetLastError();
OutputDebugString(TEXT("[This PE file has an import table, but the import table size is marked as 0. This is an error.")
TEXT("If it is not repaired, the launched program will not work properly, Detours has automatically repaired its import table size for you! ! !]\r\n"));
if (GetLastError() != dwLastError) {
SetLastError(dwLastError);
}
}
DETOUR_TRACE((" Imports: %p..%p\n", DETOUR_TRACE((" Imports: %p..%p\n",
(DWORD_PTR)pbModule + inh.IMPORT_DIRECTORY.VirtualAddress, pbModule + inh.IMPORT_DIRECTORY.VirtualAddress,
(DWORD_PTR)pbModule + inh.IMPORT_DIRECTORY.VirtualAddress + pbModule + inh.IMPORT_DIRECTORY.VirtualAddress +
inh.IMPORT_DIRECTORY.Size)); inh.IMPORT_DIRECTORY.Size));
// Calculate new import directory size. Note that since inh is from another
// process, inh could have been corrupted. We need to protect against
// integer overflow in allocation calculations.
DWORD nOldDlls = inh.IMPORT_DIRECTORY.Size / sizeof(IMAGE_IMPORT_DESCRIPTOR); DWORD nOldDlls = inh.IMPORT_DIRECTORY.Size / sizeof(IMAGE_IMPORT_DESCRIPTOR);
DWORD obRem = sizeof(IMAGE_IMPORT_DESCRIPTOR) * nDlls; DWORD obRem;
DWORD obOld = obRem + sizeof(IMAGE_IMPORT_DESCRIPTOR) * nOldDlls; if (DWordMult(sizeof(IMAGE_IMPORT_DESCRIPTOR), nDlls, &obRem) != S_OK) {
DETOUR_TRACE(("too many new DLLs.\n"));
goto finish;
}
DWORD obOld;
if (DWordAdd(obRem, sizeof(IMAGE_IMPORT_DESCRIPTOR) * nOldDlls, &obOld) != S_OK) {
DETOUR_TRACE(("DLL entries overflow.\n"));
goto finish;
}
DWORD obTab = PadToDwordPtr(obOld); DWORD obTab = PadToDwordPtr(obOld);
DWORD obDll = obTab + sizeof(DWORD_XX) * 4 * nDlls; // Check for integer overflow.
if (obTab < obOld) {
DETOUR_TRACE(("DLL entries padding overflow.\n"));
goto finish;
}
DWORD stSize;
if (DWordMult(sizeof(DWORD_XX) * 4, nDlls, &stSize) != S_OK) {
DETOUR_TRACE(("String table overflow.\n"));
goto finish;
}
DWORD obDll;
if (DWordAdd(obTab, stSize, &obDll) != S_OK) {
DETOUR_TRACE(("Import table size overflow\n"));
goto finish;
}
DWORD obStr = obDll; DWORD obStr = obDll;
cbNew = obStr; cbNew = obStr;
for (n = 0; n < nDlls; n++) { for (n = 0; n < nDlls; n++) {
cbNew += PadToDword((DWORD)strlen(plpDlls[n]) + 1); if (DWordAdd(cbNew, PadToDword((DWORD)strlen(plpDlls[n]) + 1), &cbNew) != S_OK) {
DETOUR_TRACE(("Overflow adding string table entry\n"));
goto finish;
}
} }
_Analysis_assume_(cbNew >
sizeof(IMAGE_IMPORT_DESCRIPTOR) * (nDlls + nOldDlls)
+ sizeof(DWORD_XX) * 4 * nDlls);
pbNew = new BYTE [cbNew]; pbNew = new BYTE [cbNew];
if (pbNew == NULL) { if (pbNew == NULL) {
DETOUR_TRACE(("new BYTE [cbNew] failed.\n")); DETOUR_TRACE(("new BYTE [cbNew] failed.\n"));
@ -145,14 +203,14 @@ static BOOL UPDATE_IMPORTS_XX(HANDLE hProcess,
} }
PIMAGE_IMPORT_DESCRIPTOR piid = (PIMAGE_IMPORT_DESCRIPTOR)pbNew; PIMAGE_IMPORT_DESCRIPTOR piid = (PIMAGE_IMPORT_DESCRIPTOR)pbNew;
DWORD_XX *pt; IMAGE_THUNK_DATAXX *pt = NULL;
DWORD obBase = (DWORD)(pbNewIid - pbModule); DWORD obBase = (DWORD)(pbNewIid - pbModule);
DWORD dwProtect = 0; DWORD dwProtect = 0;
if (inh.IMPORT_DIRECTORY.VirtualAddress != 0) { if (inh.IMPORT_DIRECTORY.VirtualAddress != 0) {
// Read the old import directory if it exists. // Read the old import directory if it exists.
DETOUR_TRACE(("IMPORT_DIRECTORY perms=%x\n", dwProtect)); DETOUR_TRACE(("IMPORT_DIRECTORY perms=%lx\n", dwProtect));
if (!ReadProcessMemory(hProcess, if (!ReadProcessMemory(hProcess,
pbModule + inh.IMPORT_DIRECTORY.VirtualAddress, pbModule + inh.IMPORT_DIRECTORY.VirtualAddress,
@ -160,7 +218,7 @@ static BOOL UPDATE_IMPORTS_XX(HANDLE hProcess,
nOldDlls * sizeof(IMAGE_IMPORT_DESCRIPTOR), &cbRead) nOldDlls * sizeof(IMAGE_IMPORT_DESCRIPTOR), &cbRead)
|| cbRead < nOldDlls * sizeof(IMAGE_IMPORT_DESCRIPTOR)) { || cbRead < nOldDlls * sizeof(IMAGE_IMPORT_DESCRIPTOR)) {
DETOUR_TRACE(("ReadProcessMemory(imports) failed: %d\n", GetLastError())); DETOUR_TRACE(("ReadProcessMemory(imports) failed: %lu\n", GetLastError()));
goto finish; goto finish;
} }
} }
@ -168,7 +226,7 @@ static BOOL UPDATE_IMPORTS_XX(HANDLE hProcess,
for (n = 0; n < nDlls; n++) { for (n = 0; n < nDlls; n++) {
HRESULT hrRet = StringCchCopyA((char*)pbNew + obStr, cbNew - obStr, plpDlls[n]); HRESULT hrRet = StringCchCopyA((char*)pbNew + obStr, cbNew - obStr, plpDlls[n]);
if (FAILED(hrRet)) { if (FAILED(hrRet)) {
DETOUR_TRACE(("StringCchCopyA failed: %d\n", GetLastError())); DETOUR_TRACE(("StringCchCopyA failed: %08lx\n", hrRet));
goto finish; goto finish;
} }
@ -177,21 +235,24 @@ static BOOL UPDATE_IMPORTS_XX(HANDLE hProcess,
cbNew - obStr, cbNew - obStr,
DETOURS_STRINGIFY(DETOURS_BITS_XX)); DETOURS_STRINGIFY(DETOURS_BITS_XX));
if (FAILED(hrRet)) { if (FAILED(hrRet)) {
DETOUR_TRACE(("ReplaceOptionalSizeA failed: %d\n", GetLastError())); DETOUR_TRACE(("ReplaceOptionalSizeA failed: %08lx\n", hrRet));
goto finish; goto finish;
} }
DWORD nOffset = obTab + (sizeof(DWORD_XX) * (4 * n)); DWORD nOffset = obTab + (sizeof(IMAGE_THUNK_DATAXX) * (4 * n));
piid[n].OriginalFirstThunk = obBase + nOffset; piid[n].OriginalFirstThunk = obBase + nOffset;
pt = ((DWORD_XX*)(pbNew + nOffset));
pt[0] = IMAGE_ORDINAL_FLAG_XX + 1;
pt[1] = 0;
nOffset = obTab + (sizeof(DWORD_XX) * ((4 * n) + 2)); // We need 2 thunks for the import table and 2 thunks for the IAT.
// One for an ordinal import and one to mark the end of the list.
pt = ((IMAGE_THUNK_DATAXX*)(pbNew + nOffset));
pt[0].u1.Ordinal = IMAGE_ORDINAL_FLAG_XX + 1;
pt[1].u1.Ordinal = 0;
nOffset = obTab + (sizeof(IMAGE_THUNK_DATAXX) * ((4 * n) + 2));
piid[n].FirstThunk = obBase + nOffset; piid[n].FirstThunk = obBase + nOffset;
pt = ((DWORD_XX*)(pbNew + nOffset)); pt = ((IMAGE_THUNK_DATAXX*)(pbNew + nOffset));
pt[0] = IMAGE_ORDINAL_FLAG_XX + 1; pt[0].u1.Ordinal = IMAGE_ORDINAL_FLAG_XX + 1;
pt[1] = 0; pt[1].u1.Ordinal = 0;
piid[n].TimeDateStamp = 0; piid[n].TimeDateStamp = 0;
piid[n].ForwarderChain = 0; piid[n].ForwarderChain = 0;
piid[n].Name = obBase + obStr; piid[n].Name = obBase + obStr;
@ -216,16 +277,19 @@ static BOOL UPDATE_IMPORTS_XX(HANDLE hProcess,
#endif #endif
if (!WriteProcessMemory(hProcess, pbNewIid, pbNew, obStr, NULL)) { if (!WriteProcessMemory(hProcess, pbNewIid, pbNew, obStr, NULL)) {
DETOUR_TRACE(("WriteProcessMemory(iid) failed: %d\n", GetLastError())); DETOUR_TRACE(("WriteProcessMemory(iid) failed: %lu\n", GetLastError()));
goto finish; goto finish;
} }
DETOUR_TRACE(("obBaseBef = %08x..%08x\n", DETOUR_TRACE(("obBaseBef = %08lx..%08lx\n",
inh.IMPORT_DIRECTORY.VirtualAddress, inh.IMPORT_DIRECTORY.VirtualAddress,
inh.IMPORT_DIRECTORY.VirtualAddress + inh.IMPORT_DIRECTORY.Size)); inh.IMPORT_DIRECTORY.VirtualAddress + inh.IMPORT_DIRECTORY.Size));
DETOUR_TRACE(("obBaseAft = %08x..%08x\n", obBase, obBase + obStr)); DETOUR_TRACE(("obBaseAft = %08lx..%08lx\n", obBase, obBase + obStr));
// If the file doesn't have an IAT_DIRECTORY, we create it... // In this case the file didn't have an import directory in first place,
// so we couldn't fix the missing IAT above. We still need to explicitly
// provide an IAT to prevent to loader from looking for one.
//
if (inh.IAT_DIRECTORY.VirtualAddress == 0) { if (inh.IAT_DIRECTORY.VirtualAddress == 0) {
inh.IAT_DIRECTORY.VirtualAddress = obBase; inh.IAT_DIRECTORY.VirtualAddress = obBase;
inh.IAT_DIRECTORY.Size = cbNew; inh.IAT_DIRECTORY.Size = cbNew;
@ -238,20 +302,20 @@ static BOOL UPDATE_IMPORTS_XX(HANDLE hProcess,
// //
if (!DetourVirtualProtectSameExecuteEx(hProcess, pbModule, inh.OptionalHeader.SizeOfHeaders, if (!DetourVirtualProtectSameExecuteEx(hProcess, pbModule, inh.OptionalHeader.SizeOfHeaders,
PAGE_EXECUTE_READWRITE, &dwProtect)) { PAGE_EXECUTE_READWRITE, &dwProtect)) {
DETOUR_TRACE(("VirtualProtectEx(inh) write failed: %d\n", GetLastError())); DETOUR_TRACE(("VirtualProtectEx(inh) write failed: %lu\n", GetLastError()));
goto finish; goto finish;
} }
inh.OptionalHeader.CheckSum = 0; inh.OptionalHeader.CheckSum = 0;
if (!WriteProcessMemory(hProcess, pbModule, &idh, sizeof(idh), NULL)) { if (!WriteProcessMemory(hProcess, pbModule, &idh, sizeof(idh), NULL)) {
DETOUR_TRACE(("WriteProcessMemory(idh) failed: %d\n", GetLastError())); DETOUR_TRACE(("WriteProcessMemory(idh) failed: %lu\n", GetLastError()));
goto finish; goto finish;
} }
DETOUR_TRACE(("WriteProcessMemory(idh:%p..%p)\n", pbModule, pbModule + sizeof(idh))); DETOUR_TRACE(("WriteProcessMemory(idh:%p..%p)\n", pbModule, pbModule + sizeof(idh)));
if (!WriteProcessMemory(hProcess, pbModule + idh.e_lfanew, &inh, sizeof(inh), NULL)) { if (!WriteProcessMemory(hProcess, pbModule + idh.e_lfanew, &inh, sizeof(inh), NULL)) {
DETOUR_TRACE(("WriteProcessMemory(inh) failed: %d\n", GetLastError())); DETOUR_TRACE(("WriteProcessMemory(inh) failed: %lu\n", GetLastError()));
goto finish; goto finish;
} }
DETOUR_TRACE(("WriteProcessMemory(inh:%p..%p)\n", DETOUR_TRACE(("WriteProcessMemory(inh:%p..%p)\n",
@ -260,7 +324,7 @@ static BOOL UPDATE_IMPORTS_XX(HANDLE hProcess,
if (!VirtualProtectEx(hProcess, pbModule, inh.OptionalHeader.SizeOfHeaders, if (!VirtualProtectEx(hProcess, pbModule, inh.OptionalHeader.SizeOfHeaders,
dwProtect, &dwProtect)) { dwProtect, &dwProtect)) {
DETOUR_TRACE(("VirtualProtectEx(idh) restore failed: %d\n", GetLastError())); DETOUR_TRACE(("VirtualProtectEx(idh) restore failed: %lu\n", GetLastError()));
goto finish; goto finish;
} }