diff --git a/renderdoccmd/renderdoccmd.cpp b/renderdoccmd/renderdoccmd.cpp index 54eccc267..30b721f29 100644 --- a/renderdoccmd/renderdoccmd.cpp +++ b/renderdoccmd/renderdoccmd.cpp @@ -50,27 +50,29 @@ uint32_t wtoi(wchar_t *str) return ret; } -bool argequal(const char *a, const char *b) +bool argequal(const std::string &a, const std::string &b) { - if(a == NULL || b == NULL) + if(a.length() != b.length()) return false; - while(*a && *b) + for(size_t i = 0; i < a.length(); i++) { - // only compare ASCII characters in UTF-8 string - if((*a & 0x80) == 0 && (*b & 0x80) == 0 && tolower(*a) != tolower(*b)) - break; + char ca = a[i]; + char cb = b[i]; - a++; - b++; + // only compare ASCII characters in UTF-8 string + if((ca & 0x80) == 0 && (cb & 0x80) == 0 && tolower(ca) != tolower(cb)) + return false; } - // if both reached null terminator then strings are equal - return *a == 0 && *b == 0; + return true; } -void readCapOpts(const char *str, CaptureOptions *opts) +void readCapOpts(const std::string &str, CaptureOptions *opts) { + if(str.length() < sizeof(CaptureOptions)) + return; + // serialise from string with two chars per byte byte *b = (byte *)opts; for(size_t i = 0; i < sizeof(CaptureOptions); i++) @@ -131,7 +133,7 @@ void DisplayRendererPreview(ReplayRenderer *renderer) DisplayRendererPreview(renderer, d); } -int renderdoccmd(int argc, char **argv) +int renderdoccmd(const std::vector &argv) { CaptureOptions opts; @@ -142,18 +144,18 @@ int renderdoccmd(int argc, char **argv) opts.DelayForDebugger = 5; opts.HookIntoChildren = true; - if(argc >= 2) + if(argv.size() >= 2) { // fall through and print usage if(argequal(argv[1], "--help") || argequal(argv[1], "-h")) { } // if we were given a logfile, load it and continually replay it. - else if(strstr(argv[1], ".rdc") != NULL) + else if(strstr(argv[1].c_str(), ".rdc") != NULL) { float progress = 0.0f; ReplayRenderer *renderer = NULL; - auto status = RENDERDOC_CreateReplayRenderer(argv[1], &progress, &renderer); + auto status = RENDERDOC_CreateReplayRenderer(argv[1].c_str(), &progress, &renderer); if(renderer) { @@ -167,7 +169,7 @@ int renderdoccmd(int argc, char **argv) // dump the image from a logfile if(argequal(argv[1], "--thumb") || argequal(argv[1], "-t")) { - if(argc >= 3) + if(argv.size() >= 3) { string jpgname = argv[2]; @@ -186,16 +188,16 @@ int renderdoccmd(int argc, char **argv) } uint32_t len = 0; - bool32 ret = RENDERDOC_GetThumbnail(argv[2], NULL, len); + bool32 ret = RENDERDOC_GetThumbnail(argv[2].c_str(), NULL, len); if(!ret) { - fprintf(stderr, "No thumbnail in '%s' or error retrieving it", argv[2]); + fprintf(stderr, "No thumbnail in '%s' or error retrieving it", argv[2].c_str()); } else { byte *jpgbuf = new byte[len]; - RENDERDOC_GetThumbnail(argv[2], jpgbuf, len); + RENDERDOC_GetThumbnail(argv[2].c_str(), jpgbuf, len); FILE *f = fopen(jpgname.c_str(), "wb"); @@ -221,11 +223,11 @@ int renderdoccmd(int argc, char **argv) // replay a logfile else if(argequal(argv[1], "--replay") || argequal(argv[1], "-r")) { - if(argc >= 3) + if(argv.size() >= 3) { float progress = 0.0f; ReplayRenderer *renderer = NULL; - auto status = RENDERDOC_CreateReplayRenderer(argv[2], &progress, &renderer); + auto status = RENDERDOC_CreateReplayRenderer(argv[2].c_str(), &progress, &renderer); if(renderer) { @@ -246,9 +248,9 @@ int renderdoccmd(int argc, char **argv) // can't do this on other platforms as there's no nice extension // and we don't want to just launch any single parameter in case it's // -h or -help or some other guess/typo - else if(strstr(argv[1], ".exe") != NULL) + else if(strstr(argv[1].c_str(), ".exe") != NULL) { - uint32_t ident = RENDERDOC_ExecuteAndInject(argv[1], NULL, NULL, NULL, &opts, false); + uint32_t ident = RENDERDOC_ExecuteAndInject(argv[1].c_str(), NULL, NULL, NULL, &opts, false); if(ident == 0) fprintf(stderr, "Failed to create & inject\n"); @@ -261,26 +263,28 @@ int renderdoccmd(int argc, char **argv) // capture a program with default capture options else if(argequal(argv[1], "--capture") || argequal(argv[1], "-c")) { - if(argc >= 4) + if(argv.size() >= 4) { - uint32_t ident = RENDERDOC_ExecuteAndInject(argv[2], NULL, argv[3], NULL, &opts, false); + uint32_t ident = + RENDERDOC_ExecuteAndInject(argv[2].c_str(), NULL, argv[3].c_str(), NULL, &opts, false); if(ident == 0) - fprintf(stderr, "Failed to create & inject to '%s' with params \"%s\"\n", argv[2], argv[3]); + fprintf(stderr, "Failed to create & inject to '%s' with params \"%s\"\n", argv[2].c_str(), + argv[3].c_str()); else - fprintf(stderr, "Created & injected '%s' with params \"%s\" as %d\n", argv[2], argv[3], - ident); + fprintf(stderr, "Created & injected '%s' with params \"%s\" as %d\n", argv[2].c_str(), + argv[3].c_str(), ident); return ident; } - else if(argc >= 3) + else if(argv.size() >= 3) { - uint32_t ident = RENDERDOC_ExecuteAndInject(argv[2], NULL, NULL, NULL, &opts, false); + uint32_t ident = RENDERDOC_ExecuteAndInject(argv[2].c_str(), NULL, NULL, NULL, &opts, false); if(ident == 0) - fprintf(stderr, "Failed to create & inject to '%s'\n", argv[2]); + fprintf(stderr, "Failed to create & inject to '%s'\n", argv[2].c_str()); else - fprintf(stderr, "Created & injected '%s' as %d\n", argv[2], ident); + fprintf(stderr, "Created & injected '%s' as %d\n", argv[2].c_str(), ident); return ident; } @@ -292,9 +296,9 @@ int renderdoccmd(int argc, char **argv) // inject into a running process with default capture options else if(argequal(argv[1], "--inject") || argequal(argv[1], "-i")) { - if(argc >= 3) + if(argv.size() >= 3) { - char *pid = argv[2]; + const char *pid = argv[2].c_str(); while(*pid == '"' || isspace(*pid)) pid++; @@ -323,10 +327,10 @@ int renderdoccmd(int argc, char **argv) // replay a logfile over the network on a remote host else if(argequal(argv[1], "--remotereplay") || argequal(argv[1], "-rr")) { - if(argc >= 4) + if(argv.size() >= 4) { RemoteRenderer *remote = NULL; - auto status = RENDERDOC_CreateRemoteReplayConnection(argv[2], &remote); + auto status = RENDERDOC_CreateRemoteReplayConnection(argv[2].c_str(), &remote); if(remote == NULL || status != eReplayCreate_Success) return 1; @@ -334,7 +338,7 @@ int renderdoccmd(int argc, char **argv) float progress = 0.0f; ReplayRenderer *renderer = NULL; - status = RemoteRenderer_CreateProxyRenderer(remote, 0, argv[3], &progress, &renderer); + status = RemoteRenderer_CreateProxyRenderer(remote, 0, argv[3].c_str(), &progress, &renderer); if(renderer) { @@ -353,20 +357,20 @@ int renderdoccmd(int argc, char **argv) // not documented/useful for manual use on the cmd line, used internally else if(argequal(argv[1], "--cap32for64")) { - if(argc >= 5) + if(argv.size() >= 5) { - char *pid = argv[2]; + const char *pid = argv[2].c_str(); while(*pid == '"' || isspace(*pid)) pid++; uint32_t pidNum = (uint32_t)atoi(pid); - char *log = argv[3]; + const char *log = argv[3].c_str(); if(log[0] == 0) log = NULL; CaptureOptions cmdopts; - readCapOpts(argv[4], &cmdopts); + readCapOpts(argv[4].c_str(), &cmdopts); return RENDERDOC_InjectIntoProcess(pidNum, log, &cmdopts, false); } @@ -414,3 +418,13 @@ int renderdoccmd(int argc, char **argv) return 1; } + +int renderdoccmd(int argc, char **c_argv) +{ + std::vector argv; + argv.resize(argc); + for(int i = 0; i < argc; i++) + argv[i] = c_argv[i]; + + return renderdoccmd(argv); +} diff --git a/renderdoccmd/renderdoccmd.vcxproj b/renderdoccmd/renderdoccmd.vcxproj index 32a3895eb..f9a2c4749 100644 --- a/renderdoccmd/renderdoccmd.vcxproj +++ b/renderdoccmd/renderdoccmd.vcxproj @@ -163,6 +163,12 @@ + + true + + + true + true @@ -192,4 +198,4 @@ - \ No newline at end of file + diff --git a/renderdoccmd/renderdoccmd.vcxproj.filters b/renderdoccmd/renderdoccmd.vcxproj.filters index 3b59c8378..4d9cd79c3 100644 --- a/renderdoccmd/renderdoccmd.vcxproj.filters +++ b/renderdoccmd/renderdoccmd.vcxproj.filters @@ -7,6 +7,8 @@ 3rdparty + + diff --git a/renderdoccmd/renderdoccmd_win32.cpp b/renderdoccmd/renderdoccmd_win32.cpp index 4afeca6b3..cf2e53a87 100644 --- a/renderdoccmd/renderdoccmd_win32.cpp +++ b/renderdoccmd/renderdoccmd_win32.cpp @@ -265,9 +265,9 @@ void DisplayRendererPreview(ReplayRenderer *renderer, TextureDisplay displayCfg) DestroyWindow(wnd); } -int renderdoccmd(int argc, char **argv); -bool argequal(const char *a, const char *b); -void readCapOpts(const char *str, CaptureOptions *opts); +int renderdoccmd(const std::vector &argv); +bool argequal(const std::string &a, const std::string &b); +void readCapOpts(const std::string &str, CaptureOptions *opts); int WINAPI wWinMain(_In_ HINSTANCE hInst, _In_opt_ HINSTANCE hPrevInstance, _In_ LPWSTR lpCmdLine, _In_ int nShowCmd) @@ -277,29 +277,24 @@ int WINAPI wWinMain(_In_ HINSTANCE hInst, _In_opt_ HINSTANCE hPrevInstance, _In_ wargv = CommandLineToArgvW(GetCommandLine(), &argc); - std::vector argv_storage; - std::vector argv_pointers; + std::vector argv; - argv_storage.resize(argc); - argv_pointers.resize(argc); - for(int i = 0; i < argc; i++) + argv.resize(argc); + for(size_t i = 0; i < argv.size(); i++) { size_t len = wcslen(wargv[i]); len *= 4; // worst case, every UTF-8 character takes 4 bytes - argv_storage[i].resize(len + 1); - argv_storage[i][len] = 0; - argv_pointers[i] = &argv_storage[i][0]; + argv[i].resize(len + 1); + argv[i][len] = 0; + char *cstr = (char *)&argv[i][0]; - WideCharToMultiByte(CP_UTF8, 0, wargv[i], -1, argv_pointers[i], (int)len + 1, NULL, NULL); + WideCharToMultiByte(CP_UTF8, 0, wargv[i], -1, cstr, (int)len + 1, NULL, NULL); + + argv[i].resize(strlen(cstr)); } - char *argv_backup[] = {"", NULL}; - char **argv = NULL; - - if(argc > 0) - argv = &argv_pointers[0]; - else - argv = argv_backup; + if(argv.empty()) + argv.push_back("renderdoccmd"); LocalFree(wargv); @@ -325,7 +320,7 @@ int WINAPI wWinMain(_In_ HINSTANCE hInst, _In_opt_ HINSTANCE hPrevInstance, _In_ } // special WIN32 option for launching the crash handler - if(argc == 3 && !_stricmp(argv[1], "--update")) + if(argv.size() == 3 && argequal(argv[1], "--update")) { string originalpath = argv[2]; wstring wide_path; @@ -527,7 +522,7 @@ int WINAPI wWinMain(_In_ HINSTANCE hInst, _In_opt_ HINSTANCE hPrevInstance, _In_ CrashGenerationServer *crashServer = NULL; // special WIN32 option for launching the crash handler - if(argc == 2 && !_stricmp(argv[1], "--crashhandle")) + if(argv.size() == 2 && argequal(argv[1], "--crashhandle")) { wchar_t tempPath[MAX_PATH] = {0}; GetTempPathW(MAX_PATH - 1, tempPath); @@ -706,15 +701,15 @@ int WINAPI wWinMain(_In_ HINSTANCE hInst, _In_opt_ HINSTANCE hPrevInstance, _In_ // 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], "--globalhook")) + if(argv.size() == 5 && argequal(argv[1], "--globalhook")) { - char *pathmatch = argv[2]; - char *log = argv[3]; + std::string &pathmatch = argv[2]; + std::string &log = argv[3]; - size_t len = strlen(pathmatch); + size_t len = pathmatch.length(); wstring wpathmatch; wpathmatch.resize(len); - MultiByteToWideChar(CP_UTF8, 0, pathmatch, -1, &wpathmatch[0], (int)len); + MultiByteToWideChar(CP_UTF8, 0, pathmatch.c_str(), -1, &wpathmatch[0], (int)len); wpathmatch.resize(wcslen(wpathmatch.c_str())); CaptureOptions cmdopts; @@ -786,7 +781,7 @@ int WINAPI wWinMain(_In_ HINSTANCE hInst, _In_opt_ HINSTANCE hPrevInstance, _In_ wcsncpy_s(shimdata->pathmatchstring, wpathmatch.c_str(), _TRUNCATE); wcsncpy_s(shimdata->rdocpath, rdocpath, _TRUNCATE); - strncpy_s(shimdata->log, log, _TRUNCATE); + strncpy_s(shimdata->log, log.c_str(), _TRUNCATE); memcpy(shimdata->opts, &cmdopts, sizeof(CaptureOptions)); static_assert(sizeof(CaptureOptions) <= sizeof(shimdata->opts), @@ -816,5 +811,5 @@ int WINAPI wWinMain(_In_ HINSTANCE hInst, _In_opt_ HINSTANCE hPrevInstance, _In_ return 0; } - return renderdoccmd(argc, argv); + return renderdoccmd(argv); }