コード例 #1
0
ファイル: renderdoccmd.cpp プロジェクト: CSRedRat/renderdoc
int WINAPI wWinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPWSTR lpCmdLine, int nShowCmd )
{
    LPWSTR *argv;
    int argc;
 
	argv = CommandLineToArgvW(GetCommandLine(), &argc);

	WNDCLASSEX wc;
	wc.cbSize        = sizeof(WNDCLASSEX);
	wc.style         = 0;
	wc.lpfnWndProc   = WndProc;
	wc.cbClsExtra    = 0;
	wc.cbWndExtra    = 0;
	wc.hInstance     = hInstance;
	wc.hIcon         = LoadIcon(NULL, MAKEINTRESOURCE(IDI_ICON));
	wc.hCursor       = LoadCursor(NULL, IDC_ARROW);
	wc.hbrBackground = (HBRUSH)(COLOR_WINDOW+1);
	wc.lpszMenuName  = NULL;
	wc.lpszClassName = L"renderdoccmd";
	wc.hIconSm       = LoadIcon(NULL, MAKEINTRESOURCE(IDI_ICON));

	if(!RegisterClassEx(&wc))
	{
		return 1;
	}
	
	CrashGenerationServer *crashServer = NULL;

	if(argc == 2 && !_wcsicmp(argv[1], L"crashhandle"))
	{
		wchar_t tempPath[MAX_PATH] = {0};
		GetTempPathW(MAX_PATH-1, tempPath);

		Sleep(100);

		wstring dumpFolder = tempPath;
		dumpFolder += L"RenderDocDumps";

		CreateDirectoryW(dumpFolder.c_str(), NULL);

		crashServer = new CrashGenerationServer(L"\\\\.\\pipe\\RenderDocBreakpadServer",
												NULL, NULL, NULL, OnClientCrashed, NULL,
												OnClientExited, NULL, NULL, NULL, true,
												&dumpFolder);

		if (!crashServer->Start()) {
			delete crashServer;
			crashServer = NULL;
			return 1;
		}

		CrashHandlerInst = hInstance;
		
		CrashHandlerWnd = CreateWindowEx(WS_EX_CLIENTEDGE, L"renderdoccmd", L"renderdoccmd", WS_OVERLAPPEDWINDOW,
			CW_USEDEFAULT, CW_USEDEFAULT, 10, 10,
			NULL, NULL, hInstance, NULL);

		HANDLE hIcon = LoadImage(CrashHandlerInst, MAKEINTRESOURCE(IDI_ICON), IMAGE_ICON, 16, 16, 0);

		if(hIcon)
		{
			SendMessage(CrashHandlerWnd, WM_SETICON, ICON_SMALL, (LPARAM)hIcon);
			SendMessage(CrashHandlerWnd, WM_SETICON, ICON_BIG, (LPARAM)hIcon);
		}

		ShowWindow(CrashHandlerWnd, SW_HIDE);
		
		HANDLE readyEvent = CreateEventA(NULL, TRUE, FALSE, "RENDERDOC_CRASHHANDLE");

		if(readyEvent != NULL)
		{
			SetEvent(readyEvent);

			CloseHandle(readyEvent);
		}

		MSG msg;
		ZeroMemory(&msg, sizeof(msg));
		while(!exitServer)
		{
			// Check to see if any messages are waiting in the queue
			while(PeekMessage(&msg, NULL, 0, 0, PM_REMOVE))
			{
				// Translate the message and dispatch it to WindowProc()
				TranslateMessage(&msg);
				DispatchMessage(&msg);
			}

			// If the message is WM_QUIT, exit the while loop
			if(msg.message == WM_QUIT)
				break;
			
			Sleep(100);
		}
		
		delete crashServer;
		crashServer = NULL;

		if(!dump.empty())
		{
			logpath = L"";

			string report = "";

			for(size_t i=0; i < customInfo.size(); i++)
			{
				wstring name = customInfo[i].name;
				wstring val = customInfo[i].value;

				if(name == L"logpath")
				{
					logpath = val;
				}
				else if(name == L"ptime")
				{
					// breakpad uptime, ignore.
				}
				else
				{
					report += string(name.begin(), name.end()) + ": " + string(val.begin(), val.end()) + "\n";
				}
			}

			DialogBox(CrashHandlerInst, MAKEINTRESOURCE(IDD_CRASH_HANDLER), CrashHandlerWnd, (DLGPROC)CrashHandlerProc);
			
			report += "\n\nRepro steps/Notes:\n\n" + reproSteps;

			{
				FILE *f = NULL;
				_wfopen_s(&f, logpath.c_str(), L"r");
				if(f)
				{
					fseek(f, 0, SEEK_END);
					long filesize = ftell(f);
					fseek(f, 0, SEEK_SET);

					if(filesize > 10)
					{
						char *error_log = new char[filesize+1];
						memset(error_log, 0, filesize+1);

						fread(error_log, 1, filesize, f);

						char *managed_callstack = strstr(error_log, "--- Begin C# Exception Data ---");
						if(managed_callstack)
						{
							report += managed_callstack;
							report += "\n\n";
						}

						delete[] error_log;
					}
					
					fclose(f);
				}
			}

			if(uploadReport)
			{
				mz_zip_archive zip;
				ZeroMemory(&zip, sizeof(zip));

				wstring destzip = dumpFolder + L"\\report.zip";

				DeleteFileW(destzip.c_str());

				mz_zip_writer_init_wfile(&zip, destzip.c_str(), 0);
				mz_zip_writer_add_mem(&zip, "report.txt", report.c_str(), report.length(), MZ_BEST_COMPRESSION);

				if(uploadDump && !dump.empty())
					mz_zip_writer_add_wfile(&zip, "minidump.dmp", dump.c_str(), NULL, 0, MZ_BEST_COMPRESSION);

				if(uploadLog && !logpath.empty())
					mz_zip_writer_add_wfile(&zip, "error.log", logpath.c_str(), NULL, 0, MZ_BEST_COMPRESSION);

				mz_zip_writer_finalize_archive(&zip);
				mz_zip_writer_end(&zip);

				int timeout = 10000;
				wstring body = L"";
				int code = 0;

				std::map<wstring, wstring> params;

				google_breakpad::HTTPUpload::SendRequest(L"http://renderdoc.org/bugsubmit", params,
					dumpFolder + L"\\report.zip", L"report", &timeout, &body, &code);

				DeleteFileW(destzip.c_str());
			}
		}

		if(!dump.empty())
			DeleteFileW(dump.c_str());

		if(!logpath.empty())
			DeleteFileW(logpath.c_str());

		return 0;
	}

	HMODULE renderdoc = LoadLibrary(_T("renderdoc.dll"));

	if(!renderdoc)
	{
		OutputDebugString(_T("Couldn't load library!"));
		return 1;
	}
	
	CaptureOptions opts;
	opts.AllowFullscreen = false;
	opts.AllowVSync = false;
	opts.DelayForDebugger = 5;
	opts.HookIntoChildren = true;
	
	if(argc == 2)
	{
		// if we were given an exe, inject into it
		if(wcsstr(argv[1], L".exe") != NULL)
		{
			uint32_t ident = RENDERDOC_ExecuteAndInject(argv[1], NULL, NULL, NULL, &opts, false);

			if(ident == 0)
				printf("Failed to create & inject\n");
			else
				printf("Created & injected as %d\n", ident);

			return ident;
		}
		// if we were given a logfile, load it and continually replay it.
		else if(wcsstr(argv[1], L".rdc") != NULL)
		{
			float progress = 0.0f;
			ReplayRenderer *renderer = NULL;
			auto status = RENDERDOC_CreateReplayRenderer(argv[1], &progress, &renderer);

			if(renderer && status == eReplayCreate_Success)
				DisplayRendererPreview(renderer, hInstance);

			delete renderer;
			return 0;
		}
		else if(wcsstr(argv[1], L"-replayhost") != NULL)
		{
			RENDERDOC_SpawnReplayHost(NULL);
			return 1;
		}
	}
	else if(argc == 3)
	{
		if(!_wcsicmp(argv[1], L"-inject"))
		{
			wchar_t *pid = argv[2];
			while(*pid == L'"' || iswspace(*pid)) pid++;

			DWORD pidNum = (DWORD)_wtoi(pid);

			uint32_t ident = RENDERDOC_InjectIntoProcess(pidNum, NULL, &opts, false);

			if(ident == 0)
				printf("Failed to inject\n");
			else
				printf("Injected as %d\n", ident);

			return ident;
		}
		else
		{
			uint32_t ident = RENDERDOC_ExecuteAndInject(argv[1], NULL, NULL, argv[2], &opts, false);

			if(ident == 0)
				printf("Failed to create & inject\n");
			else
				printf("Created & injected as %d\n", ident);

			return ident;
		}
	}
	else if(argc == 4)
	{
		if(argc == 4 && wcsstr(argv[1], L"-replay") != NULL)
		{
			RemoteRenderer *remote = NULL;
			auto status = RENDERDOC_CreateRemoteReplayConnection(argv[2], &remote);

			if(remote == NULL || status != eReplayCreate_Success)
				return 1;

			float progress = 0.0f;

			ReplayRenderer *renderer = NULL;
			status = RemoteRenderer_CreateProxyRenderer(remote, 0, argv[3], &progress, &renderer);

			if(renderer && status == eReplayCreate_Success)
				DisplayRendererPreview(renderer, hInstance);

			RemoteRenderer_Shutdown(remote);
			return 0;
		}
	}
	else if(argc == 5)
	{
		if(!_wcsicmp(argv[1], L"-cap32for64"))
		{
			wchar_t *pid = argv[2];
			while(*pid == L'"' || iswspace(*pid)) pid++;

			DWORD pidNum = (DWORD)_wtoi(pid);
			
			wchar_t *log = argv[3];
			
			CaptureOptions cmdopts;

			string optstring(&argv[4][0], &argv[4][0] + wcslen(argv[4]));

			cmdopts.FromString(optstring);

			return RENDERDOC_InjectIntoProcess(pidNum, log, &cmdopts, false);
		}
		else if(!_wcsicmp(argv[1], L"-remotecontrol"))
		{
			wchar_t *host = argv[2];
			wchar_t *ident = argv[3];
			while(*ident == L'"' || iswspace(*ident)) ident++;
			bool force = argv[4][0] != '0';

			DWORD identNum = (DWORD)_wtoi(ident);

			wchar_t username[256] = {0};
			DWORD usersize = 255; 
			GetEnvironmentVariableW(L"renderdoc_username", username, usersize);

			RemoteAccess *access = RENDERDOC_CreateRemoteAccessConnection(host, identNum, username, force);

			if(access == NULL)
			{
				printf("Failed to connect\n");
			}
			else
			{
				printf("Target: %ls, API: %ls, Busy: %ls\n", RemoteAccess_GetTarget(access), RemoteAccess_GetAPI(access), RemoteAccess_GetBusyClient(access));

				fflush(stdout);

				volatile bool run = true;

				while(run)
				{
					RemoteMessage msg;
					RemoteAccess_ReceiveMessage(access, &msg);

					if(msg.Type == eRemoteMsg_Disconnected)
					{
						printf("Disconnected\n");
						RemoteAccess_Shutdown(access);
						access = NULL;
						break;
					}
					else if(msg.Type == eRemoteMsg_Busy)
					{
						printf("Busy: %ls\n", msg.Busy.ClientName.elems);
						RemoteAccess_Shutdown(access);
						access = NULL;
						break;
					}
					else if(msg.Type == eRemoteMsg_Noop)
					{
					}
					else if(msg.Type == eRemoteMsg_RegisterAPI)
					{
						printf("Updated - Target: %ls, API: %ls\n", RemoteAccess_GetTarget(access), RemoteAccess_GetAPI(access));
					}
					else if(msg.Type == eRemoteMsg_NewCapture)
					{
						printf("Got capture - %d @ %llu, %d bytes of thumbnail\n", msg.NewCapture.ID, msg.NewCapture.timestamp, msg.NewCapture.thumbnail.count);
					}

					fflush(stdout);
				}

				if(access)
				{
					RemoteAccess_Shutdown(access);
					access = NULL;
				}
			}

			fflush(stdout);

			return 0;
		}
	}

	MessageBoxW(NULL, L"renderdoccmd Usage:\n\n" \
						L"renderdoccmd.exe \"full path to exe\" [\"path to capture logfile to save to\"]\n" \
						L"renderdoccmd.exe \"full path to logfile to replay\"\n" \
						L"renderdoccmd.exe -inject \"Process ID\"\n",
						L"renderdoccmd", MB_OK);
	return 1;
}
コード例 #2
0
ファイル: renderdoccmd.cpp プロジェクト: FeuernD/renderdoc
int renderdoccmd(int argc, wchar_t **argv)
{
	CaptureOptions opts;
	opts.AllowFullscreen = false;
	opts.AllowVSync = false;
	opts.DelayForDebugger = 5;
	opts.HookIntoChildren = true;

	if(argc >= 2)
	{
		// fall through and print usage
		if(argequal(argv[1], L"--help") || argequal(argv[1], L"-h"))
		{
		}
		// if we were given a logfile, load it and continually replay it.
		else if(wcsstr(argv[1], L".rdc") != NULL)
		{
			float progress = 0.0f;
			ReplayRenderer *renderer = NULL;
			auto status = RENDERDOC_CreateReplayRenderer(argv[1], &progress, &renderer);

			if(renderer && status == eReplayCreate_Success)
				DisplayRendererPreview(renderer);

			ReplayRenderer_Shutdown(renderer);
			return 0;
		}
		// replay a logfile
		else if(argequal(argv[1], L"--replay") || argequal(argv[1], L"-r"))
		{
			if(argc >= 3)
			{
				float progress = 0.0f;
				ReplayRenderer *renderer = NULL;
				auto status = RENDERDOC_CreateReplayRenderer(argv[2], &progress, &renderer);

				if(renderer && status == eReplayCreate_Success)
					DisplayRendererPreview(renderer);

				ReplayRenderer_Shutdown(renderer);
				return 0;
			}
			else
			{
				fprintf(stderr, "Not enough parameters to --replay");
			}
		}
#ifdef WIN32
		// if we were given an executable on windows, inject into it
		// 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(wcsstr(argv[1], L".exe") != NULL)
		{
			uint32_t ident = RENDERDOC_ExecuteAndInject(argv[1], NULL, NULL, NULL, &opts, false);

			if(ident == 0)
				fprintf(stderr, "Failed to create & inject\n");
			else
				fprintf(stderr, "Created & injected as %d\n", ident);

			return ident;
		}
#endif
		// capture a program with default capture options
		else if(argequal(argv[1], L"--capture") || argequal(argv[1], L"-c"))
		{
			if(argc >= 3)
			{
				uint32_t ident = RENDERDOC_ExecuteAndInject(argv[2], NULL, NULL, NULL, &opts, false);

				if(ident == 0)
					fprintf(stderr, "Failed to create & inject to '%ls'\n", argv[2]);
				else
					fprintf(stderr, "Created & injected '%ls' as %d\n", argv[2], ident);

				return ident;
			}
			else
			{
				fprintf(stderr, "Not enough parameters to --capture");
			}
		}
		// inject into a running process with default capture options
		else if(argequal(argv[1], L"--inject") || argequal(argv[1], L"-i"))
		{
			if(argc >= 3)
			{
				wchar_t *pid = argv[2];
				while(*pid == L'"' || iswspace(*pid)) pid++;

				uint32_t pidNum = (uint32_t)wtoi(pid);

				uint32_t ident = RENDERDOC_InjectIntoProcess(pidNum, NULL, &opts, false);

				if(ident == 0)
					printf("Failed to inject to %u\n", pidNum);
				else
					printf("Injected to %u as %u\n", pidNum, ident);

				return ident;
			}
			else
			{
				fprintf(stderr, "Not enough parameters to --inject");
			}
		}
		// spawn remote replay host
		else if(argequal(argv[1], L"--replayhost") || argequal(argv[1], L"-rh"))
		{
			RENDERDOC_SpawnReplayHost(NULL);
			return 1;
		}
		// replay a logfile over the network on a remote host
		else if(argequal(argv[1], L"--remotereplay") || argequal(argv[1], L"-rr"))
		{
			if(argc >= 4)
			{
				RemoteRenderer *remote = NULL;
				auto status = RENDERDOC_CreateRemoteReplayConnection(argv[2], &remote);

				if(remote == NULL || status != eReplayCreate_Success)
					return 1;

				float progress = 0.0f;

				ReplayRenderer *renderer = NULL;
				status = RemoteRenderer_CreateProxyRenderer(remote, 0, argv[3], &progress, &renderer);

				if(renderer && status == eReplayCreate_Success)
					DisplayRendererPreview(renderer);

				RemoteRenderer_Shutdown(remote);
				return 0;
			}
			else
			{
				fprintf(stderr, "Not enough parameters to --remotereplay");
			}
		}
		// not documented/useful for manual use on the cmd line, used internally
		else if(argequal(argv[1], L"--cap32for64"))
		{
			if(argc >= 5)
			{
				wchar_t *pid = argv[2];
				while(*pid == L'"' || iswspace(*pid)) pid++;

				uint32_t pidNum = (uint32_t)wtoi(pid);

				wchar_t *log = argv[3];

				CaptureOptions cmdopts;

				string optstring(&argv[4][0], &argv[4][0] + wcslen(argv[4]));

				cmdopts.FromString(optstring);

				return RENDERDOC_InjectIntoProcess(pidNum, log, &cmdopts, false);
			}
			else
			{
				fprintf(stderr, "Not enough parameters to --cap32for64");
			}
		}
	}
	
	fprintf(stderr, "renderdoccmd usage:\n\n");
	fprintf(stderr, "  <file.rdc>                        Launch a preview window that replays this logfile and\n");
	fprintf(stderr, "                                    displays the backbuffer.\n");
#ifdef WIN32
	fprintf(stderr, "  <program.exe>                     Launch a capture of this program with default options.\n");
#endif
	fprintf(stderr, "\n");												      
	fprintf(stderr, "  -h,  --help                       Displays this help message.\n");
	fprintf(stderr, "  -c,  --capture PROGRAM            Launches capture of the program with default options.\n");
	fprintf(stderr, "  -i,  --inject PID                 Injects into the specified PID to capture.\n");
	fprintf(stderr, "  -r,  --replay LOGFILE             Launch a preview window that replays this logfile and\n");
	fprintf(stderr, "                                    displays the backbuffer.\n");
	fprintf(stderr, "  -rh, --replayhost                 Starts a replay host server that can be used to remotely\n");
	fprintf(stderr, "                                    replay logfiles from another machine.\n");
	fprintf(stderr, "  -rr, --remotereplay HOST LOGFILE  Launch a replay of the logfile and display a preview\n");
	fprintf(stderr, "                                    window. Use the remote host to replay all commands.\n");

	return 1;
}