From 9460fbd970a6d35633fbf83919ea94be511766dc Mon Sep 17 00:00:00 2001 From: baldurk Date: Sun, 5 Oct 2014 13:57:11 +0100 Subject: [PATCH] Add feature to globally hook processes to inject indirectly. * This allows you to hook into processes that are difficult to launch directly with the existing functionality in RenderDoc. * This is rather risky, as it modifies the AppInit_DLLs registry key to inject a small shim dll that checks for the desired process and injects the full renderdoc.dll. If that registry key got left, or if there was some incompatibility with the shim dll, you could have problems. It should only ever be used as a last resort if there's no other way to capture. --- dist.sh | 4 +- docs/FAQ.aml | 16 + docs/Layout.content | 2 + docs/Windows/CaptureDialog.aml | 36 ++ docs/Windows/Options.aml | 9 + installer/Installer32.wxs | 1 + installer/Installer64.wxs | 2 + renderdoc.sln | 11 + renderdoc/api/app/renderdoc_app.h | 12 - renderdoc/api/replay/renderdoc_replay.h | 17 + renderdoc/os/linux/linux_process.cpp | 8 +- renderdoc/os/os_specific.h | 1 + renderdoc/os/win32/win32_process.cpp | 56 +++ renderdoc/replay/entry_points.cpp | 6 + renderdoccmd/renderdoccmd.vcxproj | 12 +- renderdoccmd/renderdoccmd_win32.cpp | 103 +++++ renderdocshim/renderdocshim.cpp | 169 +++++++++ renderdocshim/renderdocshim.h | 40 ++ renderdocshim/renderdocshim.vcxproj | 205 ++++++++++ renderdocshim/renderdocshim.vcxproj.filters | 9 + renderdocui/Code/PersistantConfig.cs | 6 + renderdocui/Code/Win32PInvoke.cs | 12 + renderdocui/Interop/StaticExports.cs | 8 + .../Windows/Dialogs/CaptureDialog.Designer.cs | 197 +++++++--- renderdocui/Windows/Dialogs/CaptureDialog.cs | 355 +++++++++++++++++- .../Windows/Dialogs/CaptureDialog.resx | 6 +- .../Dialogs/SettingsDialog.Designer.cs | 84 +++-- renderdocui/Windows/Dialogs/SettingsDialog.cs | 12 + .../Windows/Dialogs/SettingsDialog.resx | 3 + 29 files changed, 1292 insertions(+), 110 deletions(-) create mode 100644 renderdocshim/renderdocshim.cpp create mode 100644 renderdocshim/renderdocshim.h create mode 100644 renderdocshim/renderdocshim.vcxproj create mode 100644 renderdocshim/renderdocshim.vcxproj.filters diff --git a/dist.sh b/dist.sh index 310c7ee6e..2c0147e11 100644 --- a/dist.sh +++ b/dist.sh @@ -45,9 +45,9 @@ rm -f dist/Release{32,64}/*.{exp,lib,metagen,xml} dist/Release{32,64}/*.vshost.* # In the 64bit release folder, make an x86 subfolder and copy in renderdoc 32bit mkdir -p dist/Release64/x86 rm -rf dist/Release32/pdblocate/x64 dist/ReleasePDBs32/pdblocate/x64 -cp -R dist/Release32/{renderdoc.dll,renderdoccmd.exe,pdblocate} dist/Release64/x86/ +cp -R dist/Release32/{renderdoc.dll,renderdocshim32.dll,renderdoccmd.exe,pdblocate} dist/Release64/x86/ mkdir -p dist/ReleasePDBs64/x86 -cp -R dist/ReleasePDBs32/{renderdoc.dll,renderdoc.pdb,renderdoccmd.exe,renderdoccmd.pdb,pdblocate} dist/ReleasePDBs64/x86/ +cp -R dist/ReleasePDBs32/{renderdoc.dll,renderdoc.pdb,renderdocshim32.dll,renderdocshim32.pdb,renderdoccmd.exe,renderdoccmd.pdb,pdblocate} dist/ReleasePDBs64/x86/ if [[ $AUTOBUILD -eq 0 ]]; then echo "Ready to make installer MSIs - make sure to bump version numbers on package." diff --git a/docs/FAQ.aml b/docs/FAQ.aml index 7cda58fc6..c9b5d078a 100644 --- a/docs/FAQ.aml +++ b/docs/FAQ.aml @@ -289,5 +289,21 @@ +
+ I can't launch my program for capture directly. Can I capture it anyway? + + + There is an option for capturing programs using RenderDoc where you can't easily set + up a direct launch of the process. + + + More details can be found in the + capture options page which + details how to use it, however you should take care to read the warnings! This option + isn't without its risks, so you need to be sure you know what you're doing before + using it. It should always be used as a last resort when there is no other option. + + +
diff --git a/docs/Layout.content b/docs/Layout.content index 05ede5f0d..fc5b27247 100644 --- a/docs/Layout.content +++ b/docs/Layout.content @@ -126,6 +126,8 @@ + + diff --git a/docs/Windows/CaptureDialog.aml b/docs/Windows/CaptureDialog.aml index f7d23f763..4d1bf8c5a 100644 --- a/docs/Windows/CaptureDialog.aml +++ b/docs/Windows/CaptureDialog.aml @@ -201,6 +201,42 @@ +
+ Global Process Hook + + + This option is risky and should not be used lightly. Know what you're doing and + use it as a last resort. + + To expose this option you have to enable it in + the settings, + to prevent it being used accidentally. + When you've entered a path, or filename, in the executable text at the top + of the window, this option will then insert a global hook that causes every new + process created to load a very small shim dll. + The shim dll will load, create a thread that checks to see if the process + matches the path or filename specified, and then unload. If the process matches + it will also inject RenderDoc and capturing will continue as normal. At this + point you should first disable the global hook, then + you can use the 'Attach to running instance' menu option to continue as normal. + RenderDoc implements this behaviour by modifying the + +AppInit_DLLs +AppInit_DLLs on MSDN +http://support2.microsoft.com/kb/197571 + registry key to reference RenderDoc's dlls. This is not a particularly safe + method but it's the only reliable method to do what we want. The shim dll is + deliberately made as small and thin as possible, referencing only kernel32.dll, to + minimise any risks. + + If RenderDoc crashes or something otherwise goes wrong while these registry + keys are modified, the shim dll will continue to be injected into every process which + is certainly not desireable. Should anything go wrong, RenderDoc writes a .reg + file that restores the registry to its previous state in %TEMP%. + Again, this method should be a last resort. Given + the risks you should always try to capture directly in some way before trying this. + +
diff --git a/docs/Windows/Options.aml b/docs/Windows/Options.aml index b093520a0..94afec63d 100644 --- a/docs/Windows/Options.aml +++ b/docs/Windows/Options.aml @@ -96,6 +96,15 @@ recommended that you manually check for updates as new versions will be made available regularly with bugfixes. Enabled + + Allow global process hooking + This option enables the functionality allowing capturing of programs that aren't + launched directly from RenderDoc, but are launched from somewhere else. + This option can be dangerous which is why you have to deliberately enable it + here. Be careful when using this and only do so when necessary - more details can be found in the + capture options page. + Disabled + diff --git a/installer/Installer32.wxs b/installer/Installer32.wxs index 77f052727..010ae0593 100644 --- a/installer/Installer32.wxs +++ b/installer/Installer32.wxs @@ -79,6 +79,7 @@ + + + ToString(); + + _snwprintf_s(paramsAlloc, 2047, 2047, L"\"%ls\" --globalhook \"%ls\" \"%ls\" \"%hs\"", + renderdocPath, pathmatch, logfile == NULL ? L"" : logfile, optstr.c_str()); + + paramsAlloc[2047] = 0; + + BOOL retValue = CreateProcessW(NULL, paramsAlloc, &pSec, &tSec, false, 0, NULL, NULL, &si, &pi); + + if(retValue == FALSE) return; + + CloseHandle(pi.hThread); + CloseHandle(pi.hProcess); + +#if defined(WIN64) + *slash = 0; + + wcscat_s(renderdocPath, L"\\x86\\renderdoccmd.exe"); + + _snwprintf_s(paramsAlloc, 2047, 2047, L"\"%ls\" --globalhook \"%ls\" \"%ls\" \"%hs\"", + renderdocPath, pathmatch, logfile == NULL ? L"" : logfile, optstr.c_str()); + + paramsAlloc[2047] = 0; + + retValue = CreateProcessW(NULL, paramsAlloc, &pSec, &tSec, false, 0, NULL, NULL, &si, &pi); + + if(retValue == FALSE) return; + + CloseHandle(pi.hThread); + CloseHandle(pi.hProcess); +#endif +} + void *Process::GetFunctionAddress(const char *module, const char *function) { HMODULE mod = GetModuleHandleA(module); diff --git a/renderdoc/replay/entry_points.cpp b/renderdoc/replay/entry_points.cpp index 82cc622b4..b75db27da 100644 --- a/renderdoc/replay/entry_points.cpp +++ b/renderdoc/replay/entry_points.cpp @@ -219,6 +219,12 @@ uint32_t RENDERDOC_CC RENDERDOC_ExecuteAndInject(const wchar_t *app, const wchar return Process::CreateAndInjectIntoProcess(app, workingDir, cmdLine, logfile, opts, waitForExit != 0); } +extern "C" RENDERDOC_API +void RENDERDOC_CC RENDERDOC_StartGlobalHook(const wchar_t *pathmatch, const wchar_t *logfile, const CaptureOptions *opts) +{ + Process::StartGlobalHook(pathmatch, logfile, opts); +} + extern "C" RENDERDOC_API uint32_t RENDERDOC_CC RENDERDOC_InjectIntoProcess(uint32_t pid, const wchar_t *logfile, const CaptureOptions *opts, bool32 waitForExit) { diff --git a/renderdoccmd/renderdoccmd.vcxproj b/renderdoccmd/renderdoccmd.vcxproj index fbe0c0d3d..7d2c6a530 100644 --- a/renderdoccmd/renderdoccmd.vcxproj +++ b/renderdoccmd/renderdoccmd.vcxproj @@ -93,7 +93,7 @@ Level3 Disabled WIN32;RENDERDOC_PLATFORM=win32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) - ..\renderdoc\api\;$(SolutionDir)renderdoc\3rdparty\ + $(SolutionDir)renderdocshim\;$(SolutionDir)renderdoc\api\;$(SolutionDir)renderdoc\3rdparty\ MultiThreadedDLL true @@ -109,8 +109,8 @@ Level3 Disabled - WIN32;RENDERDOC_PLATFORM=win32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) - ..\renderdoc\api\;$(SolutionDir)renderdoc\3rdparty\ + WIN32;WIN64;RENDERDOC_PLATFORM=win32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) + $(SolutionDir)renderdocshim\;$(SolutionDir)renderdoc\api\;$(SolutionDir)renderdoc\3rdparty\ MultiThreadedDLL true @@ -129,7 +129,7 @@ true true WIN32;RENDERDOC_PLATFORM=win32;NDEBUG;RELEASE;_CONSOLE;%(PreprocessorDefinitions) - ..\renderdoc\api\;$(SolutionDir)renderdoc\3rdparty\ + $(SolutionDir)renderdocshim\;$(SolutionDir)renderdoc\api\;$(SolutionDir)renderdoc\3rdparty\ true @@ -148,8 +148,8 @@ MaxSpeed true true - WIN32;RENDERDOC_PLATFORM=win32;NDEBUG;RELEASE;_CONSOLE;%(PreprocessorDefinitions) - ..\renderdoc\api\;$(SolutionDir)renderdoc\3rdparty\ + WIN32;WIN64;RENDERDOC_PLATFORM=win32;NDEBUG;RELEASE;_CONSOLE;%(PreprocessorDefinitions) + $(SolutionDir)renderdocshim\;$(SolutionDir)renderdoc\api\;$(SolutionDir)renderdoc\3rdparty\ true diff --git a/renderdoccmd/renderdoccmd_win32.cpp b/renderdoccmd/renderdoccmd_win32.cpp index 577cf201f..09b605674 100644 --- a/renderdoccmd/renderdoccmd_win32.cpp +++ b/renderdoccmd/renderdoccmd_win32.cpp @@ -29,6 +29,8 @@ #include #include +#include + #include "resource.h" #include "miniz/miniz.h" @@ -293,6 +295,7 @@ void DisplayRendererPreview(ReplayRenderer *renderer) } int renderdoccmd(int argc, wchar_t **argv); +bool argequal(const wchar_t *a, const wchar_t *b); int WINAPI wWinMain(HINSTANCE hInst, HINSTANCE hPrevInstance, LPWSTR lpCmdLine, int nShowCmd ) { @@ -499,5 +502,105 @@ int WINAPI wWinMain(HINSTANCE hInst, HINSTANCE hPrevInstance, LPWSTR lpCmdLine, } #endif + // this installs a global windows hook pointing at renderdocshim*.dll that filters all running processes and + // loads renderdoc.dll in the target one. In any other process it unloads as soon as possible + if(argc == 5 && argequal(argv[1], L"--globalhook")) + { + wchar_t *pathmatch = argv[2]; + + wchar_t *log = argv[3]; + + CaptureOptions cmdopts; + string optstring(&argv[4][0], &argv[4][0] + wcslen(argv[4])); + cmdopts.FromString(optstring); + + // make sure the user doesn't accidentally run this with 'a' as a parameter or something. + // "a.exe" is over 4 characters so this limit should not be a problem. + if(wcslen(pathmatch) < 4) + { + fprintf(stderr, "--globalhook path match is too short/general. Danger of matching too many processes!\n"); + return 1; + } + + wchar_t rdocpath[1024]; + + // fetch path to our matching renderdoc.dll + HMODULE rdoc = GetModuleHandleA("renderdoc.dll"); + + if(rdoc == NULL) + { + fprintf(stderr, "--globalhook couldn't find renderdoc.dll!\n"); + return 1; + } + + GetModuleFileNameW(rdoc, rdocpath, _countof(rdocpath)-1); + FreeLibrary(rdoc); + + // Create pipe from control program, to stay open until requested to close + HANDLE pipe = CreateFileW(L"\\\\.\\pipe\\" +#ifdef WIN64 + L"RenderDoc.GlobalHookControl64" +#else + L"RenderDoc.GlobalHookControl32" +#endif + , GENERIC_READ|GENERIC_WRITE, 0, NULL, OPEN_EXISTING, 0, NULL); + + if(pipe == INVALID_HANDLE_VALUE) + { + fprintf(stderr, "--globalhook couldn't open control pipe.\n"); + return 1; + } + + HANDLE datahandle = OpenFileMappingA(FILE_MAP_READ, FALSE, GLOBAL_HOOK_DATA_NAME); + + if(datahandle != NULL) + { + CloseHandle(pipe); + CloseHandle(datahandle); + fprintf(stderr, "--globalhook found pre-existing global data, not creating second global hook.\n"); + return 1; + } + + datahandle = CreateFileMappingA(INVALID_HANDLE_VALUE, NULL, PAGE_READWRITE, 0, sizeof(ShimData), GLOBAL_HOOK_DATA_NAME); + + if(datahandle) + { + ShimData *shimdata = (ShimData *)MapViewOfFile(datahandle, FILE_MAP_WRITE|FILE_MAP_READ, 0, 0, sizeof(ShimData)); + + if(shimdata) + { + memset(shimdata, 0, sizeof(ShimData)); + + wcsncpy_s(shimdata->pathmatchstring, pathmatch, _TRUNCATE); + wcsncpy_s(shimdata->rdocpath, rdocpath, _TRUNCATE); + wcsncpy_s(shimdata->log, log, _TRUNCATE); + memcpy (shimdata->opts, &cmdopts, sizeof(CaptureOptions)); + + static_assert(sizeof(CaptureOptions) <= sizeof(shimdata->opts), "ShimData options is too small"); + + // wait until a write comes in over the pipe + char buf[16]; + DWORD read = 0; + ReadFile(pipe, buf, 16, &read, NULL); + + UnmapViewOfFile(shimdata); + } + else + { + fprintf(stderr, "--globalhook couldn't map global data store.\n"); + } + + CloseHandle(datahandle); + } + else + { + fprintf(stderr, "--globalhook couldn't create global data store.\n"); + } + + CloseHandle(pipe); + + return 0; + } + return renderdoccmd(argc, argv); } diff --git a/renderdocshim/renderdocshim.cpp b/renderdocshim/renderdocshim.cpp new file mode 100644 index 000000000..6a1522586 --- /dev/null +++ b/renderdocshim/renderdocshim.cpp @@ -0,0 +1,169 @@ +/****************************************************************************** + * The MIT License (MIT) + * + * Copyright (c) 2014 Baldur Karlsson + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + ******************************************************************************/ + +// This project deliberately references only kernel32.dll (ie. not even the CRT) +// so that when inserted into an application it has as small an overhead/impact +// as possible. Ideally it would be present only to be a pass-through hook and +// the first time only to allocate a little, check if this process should be hooked +// and load the renderdoc dll. +// +// The no-CRT restriction causes some awkward bits and pieces but the dll is simple +// enough that it's not a big issue. + +#include + +#include "renderdocshim.h" + +struct CaptureOptions; +typedef void (__cdecl *pRENDERDOC_SetCaptureOptions)(const CaptureOptions *opts); +typedef void (__cdecl *pRENDERDOC_SetLogFile)(const wchar_t *logfile); + +#if defined(RELEASE) +#define LOGPRINT(txt) do { } while (0) +#else +// define this to something to get logging +//#define LOGPRINT(txt) OutputDebugStringW(txt) +#define LOGPRINT(txt) do { } while (0) +#endif + +void CheckHook() +{ + ShimData *data = NULL; + + HANDLE datahandle = OpenFileMappingA(FILE_MAP_READ, FALSE, GLOBAL_HOOK_DATA_NAME); + + if(datahandle == NULL) + { + LOGPRINT(L"renderdocshim: can't open global data\n"); + return; + } + + data = (ShimData *)MapViewOfFile(datahandle, FILE_MAP_READ, 0, 0, sizeof(ShimData)); + + if(data == NULL) + { + CloseHandle(datahandle); + LOGPRINT(L"renderdocshim: can't map global data\n"); + return; + } + + if(data->pathmatchstring[0] == 0 || + data->pathmatchstring[1] == 0 || + data->pathmatchstring[2] == 0 || + data->pathmatchstring[3] == 0) + { + LOGPRINT(L"renderdocshim: invalid pathmatchstring: '"); + LOGPRINT(data->pathmatchstring); + LOGPRINT(L"'\n"); + + UnmapViewOfFile(data); + CloseHandle(datahandle); + return; + } + + // no new[], need to use VirtualAlloc + const int exepathLen = 1024; + wchar_t *exepath = (wchar_t *)VirtualAlloc(NULL, exepathLen*sizeof(wchar_t), MEM_RESERVE|MEM_COMMIT, PAGE_READWRITE); + + if(exepath) + { + // no memset :). + for(int i=0; i < exepathLen; i++) exepath[i] = 0; + + GetModuleFileNameW(NULL, exepath, exepathLen - 1); + + // no str*cmp functions + int find = FindStringOrdinal(FIND_FROMSTART, exepath, -1, data->pathmatchstring, -1, TRUE); + + if(find >= 0) + { + LOGPRINT(L"renderdocshim: Hooking into '"); + LOGPRINT(exepath); + LOGPRINT(L"', based on '"); + LOGPRINT(data->pathmatchstring); + LOGPRINT(L"'\n"); + + HMODULE mod = LoadLibraryW(data->rdocpath); + + if(mod) + { + pRENDERDOC_SetCaptureOptions setopts = (pRENDERDOC_SetCaptureOptions)GetProcAddress(mod, "RENDERDOC_SetCaptureOptions"); + pRENDERDOC_SetLogFile setlog = (pRENDERDOC_SetLogFile)GetProcAddress(mod, "RENDERDOC_SetLogFile"); + + if(setopts) + setopts( (const CaptureOptions *)data->opts ); + + if(setlog && data->log[0]) + setlog( data->log ); + } + } + else + { + LOGPRINT(L"renderdocshim: NOT Hooking into '"); + LOGPRINT(data->exepath); + LOGPRINT(L"', based on '"); + LOGPRINT(data->pathmatchstring); + LOGPRINT(L"'\n"); + } + + VirtualFree(exepath, 0, MEM_RELEASE); + } + else + { + LOGPRINT(L"renderdocshim: Failed to allocate exepath\n"); + } + + UnmapViewOfFile(data); + CloseHandle(datahandle); +} + +DWORD CheckHookThread(LPVOID param) +{ + CheckHook(); + + // this makes sure that we remove the reference to the shim dll and unload from + // the target process. That minimises the impact of having the dll inserted into + // every process + FreeLibraryAndExitThread((HMODULE)param, 0); + return 0; +} + +BOOL APIENTRY dll_entry(HMODULE hModule, DWORD ul_reason_for_call, LPVOID lpReserved) +{ + if(ul_reason_for_call == DLL_PROCESS_ATTACH) + { + DisableThreadLibraryCalls(hModule); + + // create a thread so that we can perform more complex actions (DllMain must be minimal + // in size, even this is a bit dodgy). + CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)&CheckHookThread, (LPVOID)hModule, 0, NULL); + + // Sleep on this thread a bit, as we want to call CheckHook() before any real work is done. + // Note it is important we don't try to *synchronise* on CheckHookThread, as that can easily + // cause deadlocks, crashes, etc. + Sleep(500); + } + + return TRUE; +} diff --git a/renderdocshim/renderdocshim.h b/renderdocshim/renderdocshim.h new file mode 100644 index 000000000..5112a8427 --- /dev/null +++ b/renderdocshim/renderdocshim.h @@ -0,0 +1,40 @@ +/****************************************************************************** + * The MIT License (MIT) + * + * Copyright (c) 2014 Baldur Karlsson + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + ******************************************************************************/ + +struct ShimData +{ + wchar_t pathmatchstring[2048]; + wchar_t rdocpath[2048]; + wchar_t log[2048]; + + unsigned char opts[512]; +}; + +#ifdef WIN64 +#define GLOBAL_HOOK_DATA_NAME "RenderDocGlobalHookData64" +#define SHIM_DLL_NAME "renderdocshim64.dll" +#else +#define GLOBAL_HOOK_DATA_NAME "RenderDocGlobalHookData32" +#define SHIM_DLL_NAME "renderdocshim32.dll" +#endif \ No newline at end of file diff --git a/renderdocshim/renderdocshim.vcxproj b/renderdocshim/renderdocshim.vcxproj new file mode 100644 index 000000000..4d25ba71a --- /dev/null +++ b/renderdocshim/renderdocshim.vcxproj @@ -0,0 +1,205 @@ + + + + + Profile + Win32 + + + Profile + x64 + + + Release + Win32 + + + Release + x64 + + + + {6DEE3F12-F2F8-42CA-865A-578D0FD11387} + Win32Proj + renderdocshim + + + + DynamicLibrary + true + Unicode + + + DynamicLibrary + true + Unicode + + + DynamicLibrary + false + true + Unicode + + + DynamicLibrary + false + true + Unicode + + + + + + + + + + + + + + + + + + + true + $(Platform)\$(Configuration)\ + $(SolutionDir)$(Platform)\$(Configuration)\ + $(ProjectName)32 + + + true + $(Platform)\$(Configuration)\ + $(SolutionDir)$(Platform)\$(Configuration)\ + $(ProjectName)64 + + + false + $(Platform)\$(Configuration)\ + $(SolutionDir)$(Platform)\$(Configuration)\ + $(ProjectName)32 + + + false + $(Platform)\$(Configuration)\ + $(SolutionDir)$(Platform)\$(Configuration)\ + $(ProjectName)64 + + + + + + Level3 + Disabled + WIN32;_DEBUG;_WINDOWS;_USRDLL;%(PreprocessorDefinitions) + Default + false + false + ProgramDatabase + MultiThreaded + true + false + + + Windows + true + kernel32.lib;user32.lib + true + dll_entry + Default + + + + + + + Level3 + Disabled + WIN32;WIN64;_DEBUG;_WINDOWS;_USRDLL;%(PreprocessorDefinitions) + MultiThreaded + Default + false + false + ProgramDatabase + true + false + + + Windows + true + kernel32.lib;user32.lib + true + dll_entry + Default + + + + + Level3 + + + MaxSpeed + true + true + WIN32;RELEASE;NDEBUG;_WINDOWS;_USRDLL;%(PreprocessorDefinitions) + Default + false + false + ProgramDatabase + MultiThreaded + true + + + Windows + true + true + true + kernel32.lib;user32.lib + true + dll_entry + UseLinkTimeCodeGeneration + + + + + Level3 + + + MaxSpeed + true + true + WIN32;WIN64;RELEASE;NDEBUG;_WINDOWS;_USRDLL;%(PreprocessorDefinitions) + MultiThreaded + Default + false + false + ProgramDatabase + true + + + Windows + true + true + true + kernel32.lib;user32.lib + true + dll_entry + UseLinkTimeCodeGeneration + + + + + kernel32.lib;user32.lib + + + + + + + + + + + + \ No newline at end of file diff --git a/renderdocshim/renderdocshim.vcxproj.filters b/renderdocshim/renderdocshim.vcxproj.filters new file mode 100644 index 000000000..1de862269 --- /dev/null +++ b/renderdocshim/renderdocshim.vcxproj.filters @@ -0,0 +1,9 @@ + + + + + + + + + \ No newline at end of file diff --git a/renderdocui/Code/PersistantConfig.cs b/renderdocui/Code/PersistantConfig.cs index 4c177f160..fadf33c17 100644 --- a/renderdocui/Code/PersistantConfig.cs +++ b/renderdocui/Code/PersistantConfig.cs @@ -94,6 +94,8 @@ namespace renderdocui.Code public bool CheckUpdate_UpdateAvailable = false; public DateTime CheckUpdate_LastUpdate = new DateTime(2012, 06, 27); + public bool AllowGlobalHook = false; + public void SetupFormatter() { Formatter.MinFigures = Formatter_MinFigures; @@ -124,8 +126,12 @@ namespace renderdocui.Code RecentCaptureSettings.Clear(); } + public bool ReadOnly = false; + public void Serialize(string file) { + if (ReadOnly) return; + try { ReplayHostKeyValues.Clear(); diff --git a/renderdocui/Code/Win32PInvoke.cs b/renderdocui/Code/Win32PInvoke.cs index 7094b20e7..16b53365c 100644 --- a/renderdocui/Code/Win32PInvoke.cs +++ b/renderdocui/Code/Win32PInvoke.cs @@ -91,5 +91,17 @@ namespace renderdocui.Code [DllImport("shell32.dll")] public static extern void SHChangeNotify(HChangeNotifyEventID wEventId, HChangeNotifyFlags uFlags, IntPtr dwItem1, IntPtr dwItem2); + + [DllImport("kernel32.dll", CharSet = CharSet.Auto, SetLastError = true)] + private static extern uint GetShortPathName(string lpszLongPath, char[] lpszShortPath, int cchBuffer); + + public static string ShortPath(string longpath) + { + char[] buffer = new char[256]; + + GetShortPathName(longpath, buffer, buffer.Length); + + return new string(buffer); + } } } diff --git a/renderdocui/Interop/StaticExports.cs b/renderdocui/Interop/StaticExports.cs index 50d55e13b..3986d3bb3 100644 --- a/renderdocui/Interop/StaticExports.cs +++ b/renderdocui/Interop/StaticExports.cs @@ -36,6 +36,9 @@ namespace renderdoc [DllImport("renderdoc.dll", CharSet = CharSet.Unicode, CallingConvention = CallingConvention.Cdecl)] private static extern ReplayCreateStatus RENDERDOC_CreateReplayRenderer(string logfile, ref float progress, ref IntPtr rendPtr); + [DllImport("renderdoc.dll", CharSet = CharSet.Unicode, CallingConvention = CallingConvention.Cdecl)] + private static extern void RENDERDOC_StartGlobalHook(string pathmatch, string logfile, CaptureOptions opts); + [DllImport("renderdoc.dll", CharSet = CharSet.Unicode, CallingConvention = CallingConvention.Cdecl)] private static extern UInt32 RENDERDOC_ExecuteAndInject(string app, string workingDir, string cmdLine, string logfile, CaptureOptions opts, bool waitForExit); @@ -94,6 +97,11 @@ namespace renderdoc return new ReplayRenderer(rendPtr); } + public static void StartGlobalHook(string pathmatch, string logfile, CaptureOptions opts) + { + RENDERDOC_StartGlobalHook(pathmatch, logfile, opts); + } + public static UInt32 ExecuteAndInject(string app, string workingDir, string cmdLine, string logfile, CaptureOptions opts) { return RENDERDOC_ExecuteAndInject(app, workingDir, cmdLine, logfile, opts, false); diff --git a/renderdocui/Windows/Dialogs/CaptureDialog.Designer.cs b/renderdocui/Windows/Dialogs/CaptureDialog.Designer.cs index b08369125..5fab8a5bf 100644 --- a/renderdocui/Windows/Dialogs/CaptureDialog.Designer.cs +++ b/renderdocui/Windows/Dialogs/CaptureDialog.Designer.cs @@ -34,10 +34,14 @@ System.Windows.Forms.ColumnHeader pid; System.Windows.Forms.ColumnHeader name; System.Windows.Forms.Label label5; - System.Windows.Forms.GroupBox groupBox1; - this.flowLayoutPanel2 = new System.Windows.Forms.FlowLayoutPanel(); + this.globalLabel = new System.Windows.Forms.Label(); + this.actionsGroup = new System.Windows.Forms.GroupBox(); + this.actionsFlow = new System.Windows.Forms.FlowLayoutPanel(); this.queueFrameCap = new System.Windows.Forms.CheckBox(); this.queuedCapFrame = new System.Windows.Forms.NumericUpDown(); + this.globalGroup = new System.Windows.Forms.GroupBox(); + this.globalFlow = new System.Windows.Forms.FlowLayoutPanel(); + this.toggleGlobalHook = new System.Windows.Forms.CheckBox(); this.capOptsGroup = new System.Windows.Forms.GroupBox(); this.capOptsFlow = new System.Windows.Forms.FlowLayoutPanel(); this.AllowFullscreen = new System.Windows.Forms.CheckBox(); @@ -79,10 +83,11 @@ pid = ((System.Windows.Forms.ColumnHeader)(new System.Windows.Forms.ColumnHeader())); name = ((System.Windows.Forms.ColumnHeader)(new System.Windows.Forms.ColumnHeader())); label5 = new System.Windows.Forms.Label(); - groupBox1 = new System.Windows.Forms.GroupBox(); - groupBox1.SuspendLayout(); - this.flowLayoutPanel2.SuspendLayout(); + this.actionsGroup.SuspendLayout(); + this.actionsFlow.SuspendLayout(); ((System.ComponentModel.ISupportInitialize)(this.queuedCapFrame)).BeginInit(); + this.globalGroup.SuspendLayout(); + this.globalFlow.SuspendLayout(); this.capOptsGroup.SuspendLayout(); this.capOptsFlow.SuspendLayout(); this.panel3.SuspendLayout(); @@ -128,32 +133,48 @@ | System.Windows.Forms.AnchorStyles.Right))); label5.Location = new System.Drawing.Point(9, 16); label5.Name = "label5"; - label5.Size = new System.Drawing.Size(581, 23); + label5.Size = new System.Drawing.Size(473, 23); label5.TabIndex = 3; label5.Text = "NOTE: Injecting only works when the process has not used the target API"; // - // groupBox1 + // globalLabel // - groupBox1.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left) + this.globalLabel.AutoSize = true; + this.globalLabel.ForeColor = System.Drawing.Color.Red; + this.globalLabel.Location = new System.Drawing.Point(3, 3); + this.globalLabel.Margin = new System.Windows.Forms.Padding(3); + this.globalLabel.Name = "globalLabel"; + this.globalLabel.Size = new System.Drawing.Size(188, 39); + this.globalLabel.TabIndex = 2; + this.globalLabel.Text = "Text is set by code Text is set by code\r\nText is set by codeText is set by code\r\n" + + "Text is set by codeText is set by code"; + // + // actionsGroup + // + this.actionsGroup.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left) | System.Windows.Forms.AnchorStyles.Right))); - groupBox1.Controls.Add(this.flowLayoutPanel2); - groupBox1.Location = new System.Drawing.Point(10, 500); - groupBox1.Margin = new System.Windows.Forms.Padding(10); - groupBox1.Name = "groupBox1"; - groupBox1.Size = new System.Drawing.Size(603, 49); - groupBox1.TabIndex = 11; - groupBox1.TabStop = false; - groupBox1.Text = "Actions"; + this.actionsGroup.AutoSize = true; + this.actionsGroup.AutoSizeMode = System.Windows.Forms.AutoSizeMode.GrowAndShrink; + this.actionsGroup.Controls.Add(this.actionsFlow); + this.actionsGroup.Location = new System.Drawing.Point(10, 500); + this.actionsGroup.Margin = new System.Windows.Forms.Padding(10); + this.actionsGroup.Name = "actionsGroup"; + this.actionsGroup.Size = new System.Drawing.Size(195, 65); + this.actionsGroup.TabIndex = 11; + this.actionsGroup.TabStop = false; + this.actionsGroup.Text = "Actions"; + this.actionsGroup.Layout += new System.Windows.Forms.LayoutEventHandler(this.actionsGroup_Layout); // - // flowLayoutPanel2 + // actionsFlow // - this.flowLayoutPanel2.Controls.Add(this.queueFrameCap); - this.flowLayoutPanel2.Controls.Add(this.queuedCapFrame); - this.flowLayoutPanel2.Dock = System.Windows.Forms.DockStyle.Fill; - this.flowLayoutPanel2.Location = new System.Drawing.Point(3, 16); - this.flowLayoutPanel2.Name = "flowLayoutPanel2"; - this.flowLayoutPanel2.Size = new System.Drawing.Size(597, 30); - this.flowLayoutPanel2.TabIndex = 1; + this.actionsFlow.AutoSize = true; + this.actionsFlow.AutoSizeMode = System.Windows.Forms.AutoSizeMode.GrowAndShrink; + this.actionsFlow.Controls.Add(this.queueFrameCap); + this.actionsFlow.Controls.Add(this.queuedCapFrame); + this.actionsFlow.Location = new System.Drawing.Point(3, 16); + this.actionsFlow.Name = "actionsFlow"; + this.actionsFlow.Size = new System.Drawing.Size(283, 30); + this.actionsFlow.TabIndex = 1; // // queueFrameCap // @@ -188,6 +209,45 @@ 0, 0}); // + // globalGroup + // + this.globalGroup.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left) + | System.Windows.Forms.AnchorStyles.Right))); + this.globalGroup.AutoSize = true; + this.globalGroup.AutoSizeMode = System.Windows.Forms.AutoSizeMode.GrowAndShrink; + this.globalGroup.Controls.Add(this.globalFlow); + this.globalGroup.Location = new System.Drawing.Point(10, 585); + this.globalGroup.Margin = new System.Windows.Forms.Padding(10); + this.globalGroup.Name = "globalGroup"; + this.globalGroup.Size = new System.Drawing.Size(195, 80); + this.globalGroup.TabIndex = 12; + this.globalGroup.TabStop = false; + this.globalGroup.Text = "Global Process Hook"; + this.globalGroup.Layout += new System.Windows.Forms.LayoutEventHandler(this.globalGroup_Layout); + // + // globalFlow + // + this.globalFlow.AutoSize = true; + this.globalFlow.AutoSizeMode = System.Windows.Forms.AutoSizeMode.GrowAndShrink; + this.globalFlow.Controls.Add(this.globalLabel); + this.globalFlow.Controls.Add(this.toggleGlobalHook); + this.globalFlow.Location = new System.Drawing.Point(3, 16); + this.globalFlow.Name = "globalFlow"; + this.globalFlow.Size = new System.Drawing.Size(312, 45); + this.globalFlow.TabIndex = 0; + // + // toggleGlobalHook + // + this.toggleGlobalHook.Appearance = System.Windows.Forms.Appearance.Button; + this.toggleGlobalHook.AutoSize = true; + this.toggleGlobalHook.Location = new System.Drawing.Point(197, 3); + this.toggleGlobalHook.Name = "toggleGlobalHook"; + this.toggleGlobalHook.Size = new System.Drawing.Size(112, 23); + this.toggleGlobalHook.TabIndex = 3; + this.toggleGlobalHook.Text = "Enable Global Hook"; + this.toggleGlobalHook.UseVisualStyleBackColor = true; + this.toggleGlobalHook.CheckedChanged += new System.EventHandler(this.toggleGlobalHook_CheckedChanged); + // // capOptsGroup // this.capOptsGroup.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left) @@ -198,7 +258,7 @@ this.capOptsGroup.Location = new System.Drawing.Point(10, 367); this.capOptsGroup.Margin = new System.Windows.Forms.Padding(10); this.capOptsGroup.Name = "capOptsGroup"; - this.capOptsGroup.Size = new System.Drawing.Size(603, 113); + this.capOptsGroup.Size = new System.Drawing.Size(195, 113); this.capOptsGroup.TabIndex = 4; this.capOptsGroup.TabStop = false; this.capOptsGroup.Text = "Capture Options"; @@ -312,7 +372,7 @@ // // HookIntoChildren // - this.HookIntoChildren.Location = new System.Drawing.Point(411, 29); + this.HookIntoChildren.Location = new System.Drawing.Point(275, 29); this.HookIntoChildren.Name = "HookIntoChildren"; this.HookIntoChildren.Size = new System.Drawing.Size(130, 20); this.HookIntoChildren.TabIndex = 14; @@ -323,7 +383,7 @@ // // SaveAllInitials // - this.SaveAllInitials.Location = new System.Drawing.Point(3, 55); + this.SaveAllInitials.Location = new System.Drawing.Point(411, 29); this.SaveAllInitials.Name = "SaveAllInitials"; this.SaveAllInitials.Size = new System.Drawing.Size(130, 20); this.SaveAllInitials.TabIndex = 15; @@ -333,7 +393,7 @@ // // RefAllResources // - this.RefAllResources.Location = new System.Drawing.Point(139, 55); + this.RefAllResources.Location = new System.Drawing.Point(3, 55); this.RefAllResources.Name = "RefAllResources"; this.RefAllResources.Size = new System.Drawing.Size(130, 20); this.RefAllResources.TabIndex = 16; @@ -343,7 +403,7 @@ // // CaptureAllCmdLists // - this.CaptureAllCmdLists.Location = new System.Drawing.Point(275, 55); + this.CaptureAllCmdLists.Location = new System.Drawing.Point(139, 55); this.CaptureAllCmdLists.Name = "CaptureAllCmdLists"; this.CaptureAllCmdLists.Size = new System.Drawing.Size(130, 20); this.CaptureAllCmdLists.TabIndex = 17; @@ -354,7 +414,7 @@ // // AutoStart // - this.AutoStart.Location = new System.Drawing.Point(411, 55); + this.AutoStart.Location = new System.Drawing.Point(275, 55); this.AutoStart.Name = "AutoStart"; this.AutoStart.Size = new System.Drawing.Size(130, 20); this.AutoStart.TabIndex = 18; @@ -371,19 +431,19 @@ this.panel2.Controls.Add(this.save); this.panel2.Controls.Add(this.close); this.panel2.Controls.Add(this.capture); - this.panel2.Location = new System.Drawing.Point(3, 562); + this.panel2.Location = new System.Drawing.Point(3, 678); this.panel2.Name = "panel2"; - this.panel2.Size = new System.Drawing.Size(617, 26); + this.panel2.Size = new System.Drawing.Size(209, 26); this.panel2.TabIndex = 8; // // load // this.load.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left))); - this.load.Location = new System.Drawing.Point(104, 3); + this.load.Location = new System.Drawing.Point(50, 3); this.load.Name = "load"; - this.load.Size = new System.Drawing.Size(86, 23); + this.load.Size = new System.Drawing.Size(39, 23); this.load.TabIndex = 24; - this.load.Text = "Load Settings"; + this.load.Text = "Load"; this.toolTip.SetToolTip(this.load, "Load a saved set of capture settings"); this.load.UseVisualStyleBackColor = true; this.load.Click += new System.EventHandler(this.load_Click); @@ -393,9 +453,9 @@ this.save.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left))); this.save.Location = new System.Drawing.Point(4, 3); this.save.Name = "save"; - this.save.Size = new System.Drawing.Size(94, 23); + this.save.Size = new System.Drawing.Size(40, 23); this.save.TabIndex = 23; - this.save.Text = "Save Settings"; + this.save.Text = "Save"; this.toolTip.SetToolTip(this.save, "Save these capture settings to file to load later"); this.save.UseVisualStyleBackColor = true; this.save.Click += new System.EventHandler(this.save_Click); @@ -403,10 +463,10 @@ // close // this.close.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Right))); - this.close.Location = new System.Drawing.Point(540, 3); + this.close.Location = new System.Drawing.Point(162, 3); this.close.Margin = new System.Windows.Forms.Padding(0); this.close.Name = "close"; - this.close.Size = new System.Drawing.Size(70, 23); + this.close.Size = new System.Drawing.Size(41, 23); this.close.TabIndex = 22; this.close.Text = "Close"; this.close.UseVisualStyleBackColor = true; @@ -415,10 +475,10 @@ // capture // this.capture.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Right))); - this.capture.Location = new System.Drawing.Point(464, 3); + this.capture.Location = new System.Drawing.Point(105, 3); this.capture.Margin = new System.Windows.Forms.Padding(0); this.capture.Name = "capture"; - this.capture.Size = new System.Drawing.Size(70, 23); + this.capture.Size = new System.Drawing.Size(52, 23); this.capture.TabIndex = 21; this.capture.Text = "Capture"; this.toolTip.SetToolTip(this.capture, "Trigger a capture of the selected program"); @@ -466,14 +526,14 @@ | System.Windows.Forms.AnchorStyles.Right))); this.cmdline.Location = new System.Drawing.Point(137, 71); this.cmdline.Name = "cmdline"; - this.cmdline.Size = new System.Drawing.Size(460, 20); + this.cmdline.Size = new System.Drawing.Size(52, 20); this.cmdline.TabIndex = 4; this.toolTip.SetToolTip(this.cmdline, "The command-line that will be passed to the executable on launch"); // // workDirBrowse // this.workDirBrowse.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Right))); - this.workDirBrowse.Location = new System.Drawing.Point(573, 45); + this.workDirBrowse.Location = new System.Drawing.Point(165, 45); this.workDirBrowse.Name = "workDirBrowse"; this.workDirBrowse.Size = new System.Drawing.Size(24, 20); this.workDirBrowse.TabIndex = 3; @@ -488,7 +548,7 @@ | System.Windows.Forms.AnchorStyles.Right))); this.workDirPath.Location = new System.Drawing.Point(137, 45); this.workDirPath.Name = "workDirPath"; - this.workDirPath.Size = new System.Drawing.Size(430, 20); + this.workDirPath.Size = new System.Drawing.Size(22, 20); this.workDirPath.TabIndex = 2; this.toolTip.SetToolTip(this.workDirPath, "The working directory the executable will be launched in"); this.workDirPath.TextChanged += new System.EventHandler(this.workDirPath_TextChanged); @@ -498,7 +558,7 @@ // exeBrowse // this.exeBrowse.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Right))); - this.exeBrowse.Location = new System.Drawing.Point(573, 19); + this.exeBrowse.Location = new System.Drawing.Point(165, 18); this.exeBrowse.Name = "exeBrowse"; this.exeBrowse.Size = new System.Drawing.Size(24, 20); this.exeBrowse.TabIndex = 1; @@ -514,7 +574,7 @@ | System.Windows.Forms.AnchorStyles.Right))); this.exePath.Location = new System.Drawing.Point(137, 19); this.exePath.Name = "exePath"; - this.exePath.Size = new System.Drawing.Size(430, 20); + this.exePath.Size = new System.Drawing.Size(22, 20); this.exePath.TabIndex = 0; this.toolTip.SetToolTip(this.exePath, "The executable file to launch"); this.exePath.TextChanged += new System.EventHandler(this.exePath_TextChanged); @@ -524,7 +584,7 @@ // pidRefresh // this.pidRefresh.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Right))); - this.pidRefresh.Location = new System.Drawing.Point(518, 180); + this.pidRefresh.Location = new System.Drawing.Point(410, 180); this.pidRefresh.Name = "pidRefresh"; this.pidRefresh.Size = new System.Drawing.Size(75, 23); this.pidRefresh.TabIndex = 6; @@ -547,7 +607,7 @@ this.pidList.Location = new System.Drawing.Point(6, 42); this.pidList.MultiSelect = false; this.pidList.Name = "pidList"; - this.pidList.Size = new System.Drawing.Size(584, 129); + this.pidList.Size = new System.Drawing.Size(183, 129); this.pidList.TabIndex = 5; this.toolTip.SetToolTip(this.pidList, "Select the process to inject into - must not yet have utilised the target API"); this.pidList.UseCompatibleStateImageBehavior = false; @@ -555,23 +615,28 @@ // // tableLayoutPanel2 // + this.tableLayoutPanel2.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left) + | System.Windows.Forms.AnchorStyles.Right))); + this.tableLayoutPanel2.AutoSize = true; + this.tableLayoutPanel2.AutoSizeMode = System.Windows.Forms.AutoSizeMode.GrowAndShrink; this.tableLayoutPanel2.ColumnCount = 1; this.tableLayoutPanel2.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle(System.Windows.Forms.SizeType.Percent, 100F)); this.tableLayoutPanel2.Controls.Add(this.programGroup, 0, 0); - this.tableLayoutPanel2.Controls.Add(this.panel2, 0, 4); + this.tableLayoutPanel2.Controls.Add(this.panel2, 0, 5); this.tableLayoutPanel2.Controls.Add(this.capOptsGroup, 0, 2); this.tableLayoutPanel2.Controls.Add(this.processGroup, 0, 1); - this.tableLayoutPanel2.Controls.Add(groupBox1, 0, 3); - this.tableLayoutPanel2.Dock = System.Windows.Forms.DockStyle.Fill; + this.tableLayoutPanel2.Controls.Add(this.actionsGroup, 0, 3); + this.tableLayoutPanel2.Controls.Add(this.globalGroup, 0, 4); this.tableLayoutPanel2.Location = new System.Drawing.Point(0, 0); this.tableLayoutPanel2.Name = "tableLayoutPanel2"; - this.tableLayoutPanel2.RowCount = 5; + this.tableLayoutPanel2.RowCount = 6; this.tableLayoutPanel2.RowStyles.Add(new System.Windows.Forms.RowStyle()); this.tableLayoutPanel2.RowStyles.Add(new System.Windows.Forms.RowStyle()); this.tableLayoutPanel2.RowStyles.Add(new System.Windows.Forms.RowStyle()); this.tableLayoutPanel2.RowStyles.Add(new System.Windows.Forms.RowStyle()); this.tableLayoutPanel2.RowStyles.Add(new System.Windows.Forms.RowStyle()); - this.tableLayoutPanel2.Size = new System.Drawing.Size(623, 761); + this.tableLayoutPanel2.RowStyles.Add(new System.Windows.Forms.RowStyle()); + this.tableLayoutPanel2.Size = new System.Drawing.Size(215, 707); this.tableLayoutPanel2.TabIndex = 8; // // programGroup @@ -589,7 +654,7 @@ this.programGroup.Location = new System.Drawing.Point(10, 10); this.programGroup.Margin = new System.Windows.Forms.Padding(10); this.programGroup.Name = "programGroup"; - this.programGroup.Size = new System.Drawing.Size(603, 108); + this.programGroup.Size = new System.Drawing.Size(195, 108); this.programGroup.TabIndex = 10; this.programGroup.TabStop = false; this.programGroup.Text = "Program"; @@ -604,7 +669,7 @@ this.processGroup.Location = new System.Drawing.Point(10, 138); this.processGroup.Margin = new System.Windows.Forms.Padding(10); this.processGroup.Name = "processGroup"; - this.processGroup.Size = new System.Drawing.Size(603, 209); + this.processGroup.Size = new System.Drawing.Size(195, 209); this.processGroup.TabIndex = 9; this.processGroup.TabStop = false; this.processGroup.Text = "Process"; @@ -614,16 +679,22 @@ this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F); this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; this.AutoScroll = true; - this.AutoScrollMinSize = new System.Drawing.Size(360, 0); - this.ClientSize = new System.Drawing.Size(623, 761); + this.AutoScrollMinSize = new System.Drawing.Size(215, 0); + this.ClientSize = new System.Drawing.Size(215, 736); this.Controls.Add(this.tableLayoutPanel2); this.Font = new System.Drawing.Font("Microsoft Sans Serif", 8.25F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0))); this.Name = "CaptureDialog"; this.ShowHint = WeifenLuo.WinFormsUI.Docking.DockState.Document; this.Text = "CaptureDialog"; - groupBox1.ResumeLayout(false); - this.flowLayoutPanel2.ResumeLayout(false); + this.FormClosing += new System.Windows.Forms.FormClosingEventHandler(this.CaptureDialog_FormClosing); + this.actionsGroup.ResumeLayout(false); + this.actionsGroup.PerformLayout(); + this.actionsFlow.ResumeLayout(false); ((System.ComponentModel.ISupportInitialize)(this.queuedCapFrame)).EndInit(); + this.globalGroup.ResumeLayout(false); + this.globalGroup.PerformLayout(); + this.globalFlow.ResumeLayout(false); + this.globalFlow.PerformLayout(); this.capOptsGroup.ResumeLayout(false); this.capOptsGroup.PerformLayout(); this.capOptsFlow.ResumeLayout(false); @@ -636,6 +707,7 @@ this.programGroup.PerformLayout(); this.processGroup.ResumeLayout(false); this.ResumeLayout(false); + this.PerformLayout(); } @@ -676,10 +748,15 @@ private System.Windows.Forms.ListView pidList; private System.Windows.Forms.Button pidRefresh; private System.Windows.Forms.CheckBox CaptureAllCmdLists; - private System.Windows.Forms.FlowLayoutPanel flowLayoutPanel2; + private System.Windows.Forms.FlowLayoutPanel actionsFlow; private System.Windows.Forms.NumericUpDown queuedCapFrame; private System.Windows.Forms.CheckBox queueFrameCap; private System.Windows.Forms.GroupBox capOptsGroup; + private System.Windows.Forms.FlowLayoutPanel globalFlow; + private System.Windows.Forms.CheckBox toggleGlobalHook; + private System.Windows.Forms.GroupBox actionsGroup; + private System.Windows.Forms.GroupBox globalGroup; + private System.Windows.Forms.Label globalLabel; } } \ No newline at end of file diff --git a/renderdocui/Windows/Dialogs/CaptureDialog.cs b/renderdocui/Windows/Dialogs/CaptureDialog.cs index ba214fe9d..4b7b31f04 100644 --- a/renderdocui/Windows/Dialogs/CaptureDialog.cs +++ b/renderdocui/Windows/Dialogs/CaptureDialog.cs @@ -28,14 +28,18 @@ using System.Collections.Generic; using System.ComponentModel; using System.Data; using System.Drawing; -using System.Diagnostics; using System.Text; +using System.Threading; using System.IO; using System.Windows.Forms; using WeifenLuo.WinFormsUI.Docking; +using Microsoft.Win32; using renderdocui.Code; using renderdoc; +using Process = System.Diagnostics.Process; +using System.IO.Pipes; + namespace renderdocui.Windows.Dialogs { public partial class CaptureDialog : DockContent @@ -134,6 +138,8 @@ namespace renderdocui.Windows.Dialogs processGroup.Visible = true; programGroup.Visible = false; + globalGroup.Visible = false; + capture.Text = "Inject"; FillProcessList(); @@ -145,6 +151,8 @@ namespace renderdocui.Windows.Dialogs processGroup.Visible = false; programGroup.Visible = true; + globalGroup.Visible = m_Core.Config.AllowGlobalHook; + capture.Text = "Capture"; Text = "Capture Executable"; @@ -170,6 +178,8 @@ namespace renderdocui.Windows.Dialogs workDirPath.ForeColor = SystemColors.GrayText; SetSettings(defaults); + + UpdateGlobalHook(); } #region Callbacks @@ -445,6 +455,16 @@ namespace renderdocui.Windows.Dialogs capOptsFlow.MaximumSize = new Size(capOptsGroup.ClientRectangle.Width - 8, 0); } + private void actionsGroup_Layout(object sender, LayoutEventArgs e) + { + actionsFlow.MaximumSize = new Size(actionsGroup.ClientRectangle.Width - 8, 0); + } + + private void globalGroup_Layout(object sender, LayoutEventArgs e) + { + globalFlow.MaximumSize = new Size(globalGroup.ClientRectangle.Width - 8, 0); + } + private void workDirPath_Enter(object sender, EventArgs e) { if (workDirHint) @@ -470,13 +490,14 @@ namespace renderdocui.Windows.Dialogs private void exePath_TextChanged(object sender, EventArgs e) { UpdateWorkDirHint(); + UpdateGlobalHook(); } private void UpdateWorkDirHint() { if (workDirHint == false) return; - if(exePath.Text == "") + if (exePath.Text == "") { workDirPath.Text = ""; return; @@ -491,5 +512,335 @@ namespace renderdocui.Windows.Dialogs // invalid path or similar } } + + public void UpdateGlobalHook() + { + globalGroup.Visible = !InjectMode && m_Core.Config.AllowGlobalHook; + + if (exePath.Text.Length >= 4) + { + toggleGlobalHook.Enabled = true; + globalLabel.Text = "Global hooking is risky!" + Environment.NewLine + Environment.NewLine + + "Be sure you know what you're doing."; + + if (toggleGlobalHook.Checked) + globalLabel.Text += Environment.NewLine + "Emergency restore @ %TEMP%\\RenderDoc_RestoreGlobalHook.reg"; + } + else + { + toggleGlobalHook.Enabled = false; + globalLabel.Text = "Global hooking requires an executable path, or filename"; + } + } + + private string prevAppInit = ""; + private string prevAppInitWoW64 = ""; + private int prevAppInitEnabled = 0; + private int prevAppInitWoW64Enabled = 0; + + private AutoResetEvent wakeupEvent = new AutoResetEvent(false); + private bool pipeExit = false; + private Thread pipeThread = null; + private NamedPipeServerStream pipe32 = null; + private NamedPipeServerStream pipe64 = null; + + private void EnableAppInit(RegistryKey parent, string path, string dllname, out int prevEnabled, out string prevStr) + { + RegistryKey key = parent.OpenSubKey("Microsoft", true); + if (key == null) { prevEnabled = 0; prevStr = ""; return; } + + key = key.OpenSubKey("Windows NT", true); + if (key == null) { prevEnabled = 0; prevStr = ""; return; } + + key = key.OpenSubKey("CurrentVersion", true); + if (key == null) { prevEnabled = 0; prevStr = ""; return; } + + key = key.OpenSubKey("Windows", true); + if (key == null) { prevEnabled = 0; prevStr = ""; return; } + + object o = key.GetValue("LoadAppInit_DLLs"); + if (o == null || !(o is int)) { prevEnabled = 0; prevStr = ""; return; } + prevEnabled = (int)o; + + o = key.GetValue("AppInit_DLLs"); + if (o == null || !(o is string)) { prevEnabled = 0; prevStr = ""; return; } + prevStr = (string)o; + + key.SetValue("AppInit_DLLs", Win32PInvoke.ShortPath(Path.Combine(path, dllname))); + key.SetValue("LoadAppInit_DLLs", (int)1); + } + + private void RestoreAppInit(RegistryKey parent, int prevEnabled, string prevStr) + { + RegistryKey key = parent.OpenSubKey("Microsoft", true); + if (key == null) { prevEnabled = 0; prevStr = ""; return; } + + key = key.OpenSubKey("Windows NT", true); + if (key == null) { prevEnabled = 0; prevStr = ""; return; } + + key = key.OpenSubKey("CurrentVersion", true); + if (key == null) { prevEnabled = 0; prevStr = ""; return; } + + key = key.OpenSubKey("Windows", true); + if (key == null) { prevEnabled = 0; prevStr = ""; return; } + + key.SetValue("AppInit_DLLs", prevStr); + key.SetValue("LoadAppInit_DLLs", prevEnabled); + } + + private void PipeTick() + { + while (!pipeExit) + { + wakeupEvent.WaitOne(250); + } + + if (pipe32 != null) + { + if (pipe32.IsConnected) + { + using (StreamWriter writer = new StreamWriter(pipe32)) + { + writer.Write("exit"); + writer.Flush(); + } + } + + pipe32.Dispose(); + pipe32 = null; + } + + if (pipe64 != null) + { + if (pipe64.IsConnected) + { + using (StreamWriter writer = new StreamWriter(pipe64)) + { + writer.Write("exit"); + writer.Flush(); + } + } + + pipe64.Dispose(); + pipe64 = null; + } + } + + private void ExitPipeThread() + { + pipeExit = true; + wakeupEvent.Set(); + + if (pipeThread != null) + { + if (pipeThread.ThreadState != ThreadState.Aborted && + pipeThread.ThreadState != ThreadState.Stopped) + { + // try to shut down gracefully + pipeThread.Join(1000); + + if (pipeThread.ThreadState != ThreadState.Aborted && + pipeThread.ThreadState != ThreadState.Stopped) + { + pipeThread.Abort(); + pipeThread.Join(); + } + } + } + + pipeThread = null; + + if (pipe32 != null) + { + pipe32.Dispose(); + pipe32 = null; + } + + if (pipe64 != null) + { + pipe64.Dispose(); + pipe64 = null; + } + } + + private void toggleGlobalHook_CheckedChanged(object sender, EventArgs e) + { + if (!toggleGlobalHook.Enabled) + return; + + toggleGlobalHook.Enabled = false; + + if (toggleGlobalHook.Checked) + { + if(!Helpers.IsElevated) + { + DialogResult res = MessageBox.Show("RenderDoc needs to restart with admin privileges. Restart?", "Restart as admin", MessageBoxButtons.YesNoCancel, MessageBoxIcon.Question); + + if (res == DialogResult.Yes) + { + string capfile = Path.GetTempFileName() + ".cap"; + + AutoStart.Checked = false; + + SaveSettings(capfile); + + var process = new Process(); + process.StartInfo = new System.Diagnostics.ProcessStartInfo(Application.ExecutablePath, capfile); + process.StartInfo.Verb = "runas"; + try + { + process.Start(); + } + catch (Exception) + { + // don't restart if it failed for some reason (e.g. user clicked no to UAC) + toggleGlobalHook.Checked = false; + toggleGlobalHook.Enabled = true; + return; + } + + m_Core.Config.Serialize(Core.ConfigFilename); + m_Core.Config.ReadOnly = true; + m_Core.AppWindow.Close(); + return; + } + else + { + toggleGlobalHook.Checked = false; + toggleGlobalHook.Enabled = true; + return; + } + } + + exePath.Enabled = exeBrowse.Enabled = + workDirPath.Enabled = workDirBrowse.Enabled = + cmdline.Enabled = + capture.Enabled = save.Enabled = load.Enabled = false; + + foreach (Control c in capOptsFlow.Controls) + c.Enabled = false; + + foreach (Control c in actionsFlow.Controls) + c.Enabled = false; + + toggleGlobalHook.Text = "Disable Global Hook"; + + var path = Path.GetDirectoryName(Path.GetFullPath(Application.ExecutablePath)); + + var regfile = Path.Combine(Path.GetTempPath(), "RenderDoc_RestoreGlobalHook.reg"); + + if (Environment.Is64BitProcess) + { + EnableAppInit(Registry.LocalMachine.CreateSubKey("SOFTWARE").CreateSubKey("Wow6432Node"), + path, "x86\\renderdocshim32.dll", + out prevAppInitWoW64Enabled, out prevAppInitWoW64); + + EnableAppInit(Registry.LocalMachine.CreateSubKey("SOFTWARE"), + path, "renderdocshim64.dll", + out prevAppInitEnabled, out prevAppInit); + + using (FileStream s = File.OpenWrite(regfile)) + { + using(StreamWriter sw = new StreamWriter(s)) + { + sw.WriteLine("Windows Registry Editor Version 5.00"); + sw.WriteLine(""); + sw.WriteLine("[HKEY_LOCAL_MACHINE\\SOFTWARE\\Wow6432Node\\Microsoft\\Windows NT\\CurrentVersion\\Windows]"); + sw.WriteLine(String.Format("\"LoadAppInit_DLLs\"=dword:{0:X8}", prevAppInitWoW64Enabled)); + sw.WriteLine(String.Format("\"AppInit_DLLs\"=\"{0}\"", prevAppInitWoW64)); + sw.WriteLine(""); + sw.WriteLine("[HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\Windows]"); + sw.WriteLine(String.Format("\"LoadAppInit_DLLs\"=dword:{0:X8}", prevAppInitEnabled)); + sw.WriteLine(String.Format("\"AppInit_DLLs\"=\"{0}\"", prevAppInit)); + sw.Flush(); + } + } + } + else + { + // if this is a 64-bit OS, it will re-direct our request to Wow6432Node anyway, so we + // don't need to handle that manually + EnableAppInit(Registry.LocalMachine.CreateSubKey("SOFTWARE"), path, "renderdocshim32.dll", + out prevAppInitEnabled, out prevAppInit); + + using (FileStream s = File.OpenWrite(regfile)) + { + using (StreamWriter sw = new StreamWriter(s)) + { + sw.WriteLine("Windows Registry Editor Version 5.00"); + sw.WriteLine(""); + sw.WriteLine("[HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\Windows]"); + sw.WriteLine(String.Format("\"LoadAppInit_DLLs\"=dword:{0:X8}", prevAppInitEnabled)); + sw.WriteLine(String.Format("\"AppInit_DLLs\"=\"{0}\"", prevAppInit)); + sw.Flush(); + } + } + } + + ExitPipeThread(); + + pipeExit = false; + + pipe32 = new NamedPipeServerStream("RenderDoc.GlobalHookControl32"); + pipe64 = new NamedPipeServerStream("RenderDoc.GlobalHookControl64"); + + pipeThread = Helpers.NewThread(new ThreadStart(PipeTick)); + + pipeThread.Start(); + + string exe = exePath.Text; + + string logfile = exe; + if (logfile.Contains("/")) logfile = logfile.Substring(logfile.LastIndexOf('/') + 1); + if (logfile.Contains("\\")) logfile = logfile.Substring(logfile.LastIndexOf('\\') + 1); + if (logfile.Contains(".")) logfile = logfile.Substring(0, logfile.IndexOf('.')); + logfile = m_Core.TempLogFilename(logfile); + + StaticExports.StartGlobalHook(exe, logfile, GetSettings().Options); + } + else + { + ExitPipeThread(); + + exePath.Enabled = exeBrowse.Enabled = + workDirPath.Enabled = workDirBrowse.Enabled = + cmdline.Enabled = + capture.Enabled = save.Enabled = load.Enabled = true; + + foreach (Control c in capOptsFlow.Controls) + c.Enabled = true; + + foreach (Control c in actionsFlow.Controls) + c.Enabled = true; + + toggleGlobalHook.Text = "Enable Global Hook"; + + if (Environment.Is64BitProcess) + { + RestoreAppInit(Registry.LocalMachine.CreateSubKey("SOFTWARE").CreateSubKey("Wow6432Node"), prevAppInitWoW64Enabled, prevAppInitWoW64); + RestoreAppInit(Registry.LocalMachine.CreateSubKey("SOFTWARE"), prevAppInitEnabled, prevAppInit); + } + else + { + // if this is a 64-bit OS, it will re-direct our request to Wow6432Node anyway, so we + // don't need to handle that manually + RestoreAppInit(Registry.LocalMachine.CreateSubKey("SOFTWARE"), prevAppInitEnabled, prevAppInit); + } + + var regfile = Path.Combine(Path.GetTempPath(), "RenderDoc_RestoreGlobalHook.reg"); + + if (File.Exists(regfile)) File.Delete(regfile); + } + + toggleGlobalHook.Enabled = true; + + UpdateGlobalHook(); + } + + private void CaptureDialog_FormClosing(object sender, FormClosingEventArgs e) + { + if (toggleGlobalHook.Checked) + toggleGlobalHook.Checked = false; + } } } diff --git a/renderdocui/Windows/Dialogs/CaptureDialog.resx b/renderdocui/Windows/Dialogs/CaptureDialog.resx index 624222232..8e85281e7 100644 --- a/renderdocui/Windows/Dialogs/CaptureDialog.resx +++ b/renderdocui/Windows/Dialogs/CaptureDialog.resx @@ -135,9 +135,6 @@ False - - False - 17, 17 @@ -150,4 +147,7 @@ 382, 17 + + 485, 17 + \ No newline at end of file diff --git a/renderdocui/Windows/Dialogs/SettingsDialog.Designer.cs b/renderdocui/Windows/Dialogs/SettingsDialog.Designer.cs index 029a06111..f6223979e 100644 --- a/renderdocui/Windows/Dialogs/SettingsDialog.Designer.cs +++ b/renderdocui/Windows/Dialogs/SettingsDialog.Designer.cs @@ -32,6 +32,7 @@ System.Windows.Forms.TableLayoutPanel tableLayoutPanel1; System.Windows.Forms.GroupBox groupBox1; System.Windows.Forms.TableLayoutPanel tableLayoutPanel2; + System.Windows.Forms.Label label13; System.Windows.Forms.Label label6; System.Windows.Forms.Label label4; System.Windows.Forms.Label label1; @@ -47,9 +48,13 @@ System.Windows.Forms.GroupBox groupBox4; System.Windows.Forms.Label label8; System.Windows.Forms.Label label9; - TreelistView.TreeListColumn treeListColumn1 = new TreelistView.TreeListColumn("Section", "Section"); + TreelistView.TreeListColumn treeListColumn1 = ((TreelistView.TreeListColumn)(new TreelistView.TreeListColumn("Section", "Section"))); + this.ok = new System.Windows.Forms.Button(); + this.toolTip = new System.Windows.Forms.ToolTip(this.components); + this.browserCaptureDialog = new System.Windows.Forms.FolderBrowserDialog(); this.settingsTabs = new renderdocui.Controls.TablessControl(); this.generalTab = new System.Windows.Forms.TabPage(); + this.AllowGlobalHook = new System.Windows.Forms.CheckBox(); this.Formatter_PosExp = new System.Windows.Forms.NumericUpDown(); this.Formatter_NegExp = new System.Windows.Forms.NumericUpDown(); this.rdcAssoc = new System.Windows.Forms.Button(); @@ -69,12 +74,10 @@ this.EventBrowser_TimeUnit = new System.Windows.Forms.ComboBox(); this.EventBrowser_HideEmpty = new System.Windows.Forms.CheckBox(); this.pagesTree = new TreelistView.TreeListView(); - this.ok = new System.Windows.Forms.Button(); - this.toolTip = new System.Windows.Forms.ToolTip(this.components); - this.browserCaptureDialog = new System.Windows.Forms.FolderBrowserDialog(); tableLayoutPanel1 = new System.Windows.Forms.TableLayoutPanel(); groupBox1 = new System.Windows.Forms.GroupBox(); tableLayoutPanel2 = new System.Windows.Forms.TableLayoutPanel(); + label13 = new System.Windows.Forms.Label(); label6 = new System.Windows.Forms.Label(); label4 = new System.Windows.Forms.Label(); label1 = new System.Windows.Forms.Label(); @@ -128,6 +131,21 @@ tableLayoutPanel1.Size = new System.Drawing.Size(580, 353); tableLayoutPanel1.TabIndex = 1; // + // ok + // + this.ok.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Right))); + this.ok.Location = new System.Drawing.Point(502, 327); + this.ok.Name = "ok"; + this.ok.Size = new System.Drawing.Size(75, 23); + this.ok.TabIndex = 100; + this.ok.Text = "OK"; + this.ok.UseVisualStyleBackColor = true; + this.ok.Click += new System.EventHandler(this.ok_Click); + // + // browserCaptureDialog + // + this.browserCaptureDialog.RootFolder = System.Environment.SpecialFolder.MyComputer; + // // settingsTabs // this.settingsTabs.Alignment = System.Windows.Forms.TabAlignment.Left; @@ -170,6 +188,8 @@ tableLayoutPanel2.ColumnCount = 2; tableLayoutPanel2.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle(System.Windows.Forms.SizeType.Percent, 100F)); tableLayoutPanel2.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle()); + tableLayoutPanel2.Controls.Add(this.AllowGlobalHook, 1, 7); + tableLayoutPanel2.Controls.Add(label13, 0, 7); tableLayoutPanel2.Controls.Add(this.Formatter_PosExp, 1, 5); tableLayoutPanel2.Controls.Add(this.Formatter_NegExp, 1, 4); tableLayoutPanel2.Controls.Add(label6, 0, 3); @@ -182,14 +202,15 @@ tableLayoutPanel2.Controls.Add(label7, 0, 5); tableLayoutPanel2.Controls.Add(this.Formatter_MaxFigures, 1, 3); tableLayoutPanel2.Controls.Add(this.Formatter_MinFigures, 1, 2); - tableLayoutPanel2.Controls.Add(label3, 0, 7); - tableLayoutPanel2.Controls.Add(this.CheckUpdate_AllowChecks, 1, 7); + tableLayoutPanel2.Controls.Add(label3, 0, 8); + tableLayoutPanel2.Controls.Add(this.CheckUpdate_AllowChecks, 1, 8); tableLayoutPanel2.Controls.Add(label11, 0, 6); tableLayoutPanel2.Controls.Add(this.browseCaptureDirectory, 1, 6); tableLayoutPanel2.Dock = System.Windows.Forms.DockStyle.Fill; tableLayoutPanel2.Location = new System.Drawing.Point(3, 16); tableLayoutPanel2.Name = "tableLayoutPanel2"; - tableLayoutPanel2.RowCount = 9; + tableLayoutPanel2.RowCount = 10; + tableLayoutPanel2.RowStyles.Add(new System.Windows.Forms.RowStyle()); tableLayoutPanel2.RowStyles.Add(new System.Windows.Forms.RowStyle()); tableLayoutPanel2.RowStyles.Add(new System.Windows.Forms.RowStyle()); tableLayoutPanel2.RowStyles.Add(new System.Windows.Forms.RowStyle()); @@ -201,6 +222,35 @@ tableLayoutPanel2.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Percent, 100F)); tableLayoutPanel2.Size = new System.Drawing.Size(361, 285); tableLayoutPanel2.TabIndex = 0; + // + // AllowGlobalHook + // + this.AllowGlobalHook.AutoSize = true; + this.AllowGlobalHook.Checked = true; + this.AllowGlobalHook.CheckState = System.Windows.Forms.CheckState.Checked; + this.AllowGlobalHook.Location = new System.Drawing.Point(268, 194); + this.AllowGlobalHook.Name = "AllowGlobalHook"; + this.AllowGlobalHook.Size = new System.Drawing.Size(15, 14); + this.AllowGlobalHook.TabIndex = 16; + this.toolTip.SetToolTip(this.AllowGlobalHook, "Allow RenderDoc to insert a global hook into all processes to catch the execution" + + " of the desired process, without directly launching it."); + this.AllowGlobalHook.UseVisualStyleBackColor = true; + this.AllowGlobalHook.CheckedChanged += new System.EventHandler(this.AllowGlobalHook_CheckedChanged); + // + // label13 + // + label13.Anchor = ((System.Windows.Forms.AnchorStyles)((((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom) + | System.Windows.Forms.AnchorStyles.Left) + | System.Windows.Forms.AnchorStyles.Right))); + label13.AutoSize = true; + label13.Location = new System.Drawing.Point(3, 191); + label13.Name = "label13"; + label13.Size = new System.Drawing.Size(259, 20); + label13.TabIndex = 15; + label13.Text = "Allow global process hooking - be careful!"; + label13.TextAlign = System.Drawing.ContentAlignment.MiddleLeft; + this.toolTip.SetToolTip(label13, "Allows RenderDoc to phone home to http://renderdoc.org to anonymously check for n" + + "ew versions."); // // Formatter_PosExp // @@ -408,7 +458,7 @@ | System.Windows.Forms.AnchorStyles.Left) | System.Windows.Forms.AnchorStyles.Right))); label3.AutoSize = true; - label3.Location = new System.Drawing.Point(3, 191); + label3.Location = new System.Drawing.Point(3, 211); label3.Name = "label3"; label3.Size = new System.Drawing.Size(259, 20); label3.TabIndex = 12; @@ -422,7 +472,7 @@ this.CheckUpdate_AllowChecks.AutoSize = true; this.CheckUpdate_AllowChecks.Checked = true; this.CheckUpdate_AllowChecks.CheckState = System.Windows.Forms.CheckState.Checked; - this.CheckUpdate_AllowChecks.Location = new System.Drawing.Point(268, 194); + this.CheckUpdate_AllowChecks.Location = new System.Drawing.Point(268, 214); this.CheckUpdate_AllowChecks.Name = "CheckUpdate_AllowChecks"; this.CheckUpdate_AllowChecks.Size = new System.Drawing.Size(15, 14); this.CheckUpdate_AllowChecks.TabIndex = 8; @@ -701,21 +751,6 @@ this.pagesTree.ViewOptions.ShowPlusMinus = false; this.pagesTree.AfterSelect += new System.Windows.Forms.TreeViewEventHandler(this.pagesTree_AfterSelect); // - // ok - // - this.ok.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Right))); - this.ok.Location = new System.Drawing.Point(502, 327); - this.ok.Name = "ok"; - this.ok.Size = new System.Drawing.Size(75, 23); - this.ok.TabIndex = 100; - this.ok.Text = "OK"; - this.ok.UseVisualStyleBackColor = true; - this.ok.Click += new System.EventHandler(this.ok_Click); - // - // browserCaptureDialog - // - this.browserCaptureDialog.RootFolder = System.Environment.SpecialFolder.MyComputer; - // // SettingsDialog // this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F); @@ -779,5 +814,6 @@ private System.Windows.Forms.CheckBox EventBrowser_HideEmpty; private System.Windows.Forms.Button browseCaptureDirectory; private System.Windows.Forms.FolderBrowserDialog browserCaptureDialog; + private System.Windows.Forms.CheckBox AllowGlobalHook; } } \ No newline at end of file diff --git a/renderdocui/Windows/Dialogs/SettingsDialog.cs b/renderdocui/Windows/Dialogs/SettingsDialog.cs index 1feb1919b..82e1ed668 100644 --- a/renderdocui/Windows/Dialogs/SettingsDialog.cs +++ b/renderdocui/Windows/Dialogs/SettingsDialog.cs @@ -60,6 +60,8 @@ namespace renderdocui.Windows.Dialogs TextureViewer_ResetRange.Checked = m_Core.Config.TextureViewer_ResetRange; ShaderViewer_FriendlyNaming.Checked = m_Core.Config.ShaderViewer_FriendlyNaming; CheckUpdate_AllowChecks.Checked = m_Core.Config.CheckUpdate_AllowChecks; + + AllowGlobalHook.Checked = m_Core.Config.AllowGlobalHook; { Type type = m_Core.Config.EventBrowser_TimeUnit.GetType(); @@ -142,6 +144,16 @@ namespace renderdocui.Windows.Dialogs m_Core.Config.Serialize(Core.ConfigFilename); } + private void AllowGlobalHook_CheckedChanged(object sender, EventArgs e) + { + m_Core.Config.AllowGlobalHook = AllowGlobalHook.Checked; + + m_Core.Config.Serialize(Core.ConfigFilename); + + if (m_Core.CaptureDialog != null) + m_Core.CaptureDialog.UpdateGlobalHook(); + } + private void EventBrowser_TimeUnit_SelectionChangeCommitted(object sender, EventArgs e) { m_Core.Config.EventBrowser_TimeUnit = (PersistantConfig.TimeUnit)EventBrowser_TimeUnit.SelectedIndex; diff --git a/renderdocui/Windows/Dialogs/SettingsDialog.resx b/renderdocui/Windows/Dialogs/SettingsDialog.resx index 0a75d9349..9338a19db 100644 --- a/renderdocui/Windows/Dialogs/SettingsDialog.resx +++ b/renderdocui/Windows/Dialogs/SettingsDialog.resx @@ -129,6 +129,9 @@ 17, 17 + + False + False