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