Ejemplo n.º 1
0
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;
}
Ejemplo n.º 2
0
int WINAPI wWinMain(_In_ HINSTANCE hInst,
	_In_opt_ HINSTANCE hPrevInstance,
	_In_ LPWSTR lpCmdLine,
	_In_ int nShowCmd)
{
	LPWSTR *wargv;
	int argc;

	wargv = CommandLineToArgvW(GetCommandLine(), &argc);

	char **argv = new char*[argc];

	for(int i=0; i < argc; i++)
	{
		size_t len = wcslen(wargv[i]);
		len *= 4; // worst case, every UTF-8 character takes 4 bytes
		argv[i] = new char[len + 1];
		argv[i][len] = 0;
	
		WideCharToMultiByte(CP_UTF8, 0, wargv[i], -1, &argv[i][0], (int)len+1, NULL, NULL);
	}

	LocalFree(wargv);

	hInstance = hInst;
	
	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;
	}

	// special WIN32 option for launching the crash handler
	if(argc == 3 && !_stricmp(argv[1], "--update"))
	{
		string originalpath = argv[2];
		wstring wide_path;

		{
			wchar_t *conv = new wchar_t[originalpath.size()+1];

			MultiByteToWideChar(CP_UTF8, 0, originalpath.c_str(), -1, conv, int(originalpath.size()+1));

			wide_path = conv;
		}

		// Wait for UI to exit
		Sleep(3000);

		mz_zip_archive zip;
		ZeroMemory(&zip, sizeof(zip));

		mz_bool b = mz_zip_reader_init_file(&zip, "./update.zip", 0);

		if(b)
		{
			mz_uint numfiles = mz_zip_reader_get_num_files(&zip);

			// first create directories
			for(mz_uint i=0; i < numfiles; i++)
			{
				if(mz_zip_reader_is_file_a_directory(&zip, i))
				{
					mz_zip_archive_file_stat zstat;
					mz_zip_reader_file_stat(&zip, i, &zstat);

					const char *fn = zstat.m_filename;
					// skip first directory because it's RenderDoc_Version_Bitness/
					fn = strchr(fn, '/');
					if(fn) fn++;

					if(*fn)
					{
						wchar_t conv[MAX_PATH] = {0};
						wchar_t *wfn = conv;

						// I know the zip only contains ASCII chars, just upcast
						while(*fn) *(wfn++) = wchar_t(*(fn++));

						wstring target = wide_path + conv;

						wfn = &target[0];

						// convert slashes because CreateDirectory barfs on
						// proper slashes.
						while(*(wfn++)) { if(*wfn == L'/') *wfn = L'\\'; }

						CreateDirectoryW(target.c_str(), NULL);
					}
				}
			}

			for(mz_uint i=0; i < numfiles; i++)
			{
				if(!mz_zip_reader_is_file_a_directory(&zip, i))
				{
					mz_zip_archive_file_stat zstat;
					mz_zip_reader_file_stat(&zip, i, &zstat);

					const char *fn = zstat.m_filename;
					// skip first directory because it's RenderDoc_Version_Bitness/
					fn = strchr(fn, '/');
					if(fn) fn++;

					if(*fn)
					{
						wchar_t conv[MAX_PATH] = {0};
						wchar_t *wfn = conv;

						// I know the zip only contains ASCII chars, just upcast
						while(*fn) *(wfn++) = wchar_t(*(fn++));

						wstring target = wide_path + conv;

						wfn = &target[0];

						// convert slashes just to be consistent
						while(*(wfn++)) { if(*wfn == L'/') *wfn = L'\\'; }

						mz_zip_reader_extract_to_wfile(&zip, i, target.c_str(), 0);
					}
				}
			}
		}

		// run original UI exe and tell it an update succeeded
		wstring cmdline = L"\"";
		cmdline += wide_path;
		cmdline += L"/renderdocui.exe\" --updatedone";

		wchar_t *paramsAlloc = new wchar_t[512];

		wcscpy_s(paramsAlloc, 511, cmdline.c_str());

		PROCESS_INFORMATION pi;
		STARTUPINFOW si;
		ZeroMemory(&pi, sizeof(pi));
		ZeroMemory(&si, sizeof(si));

		CreateProcessW(NULL, paramsAlloc, NULL, NULL, FALSE, 0, NULL, NULL, &si, &pi);

		if(pi.dwProcessId != 0)
		{
			CloseHandle(pi.hProcess);
			CloseHandle(pi.hThread);
		}

		return 0;
	}

#if defined(RELEASE)
	CrashGenerationServer *crashServer = NULL;

	// special WIN32 option for launching the crash handler
	if(argc == 2 && !_stricmp(argv[1], "--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;
	}
#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], "--globalhook"))
	{
		char *pathmatch = argv[2];
		char *log = argv[3];

		size_t len = strlen(pathmatch);
		wstring wpathmatch; wpathmatch.resize(len);
		MultiByteToWideChar(CP_UTF8, 0, pathmatch, -1, &wpathmatch[0], (int)len);
		wpathmatch.resize(wcslen(wpathmatch.c_str()));
		
		CaptureOptions cmdopts;
		readCapOpts(argv[4], &cmdopts);

		// 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(wpathmatch.length() < 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, wpathmatch.c_str(), _TRUNCATE);
				wcsncpy_s(shimdata->rdocpath, rdocpath, _TRUNCATE);
				strncpy_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;
	}

	int retval = renderdoccmd(argc, argv);
	
	for(int i=0; i < argc; i++)
		delete[] argv[i];
	delete[] argv;

	return retval;
}
Ejemplo n.º 3
0
  virtual int Execute(cmdline::parser &parser, const CaptureOptions &)
  {
    CrashGenerationServer *crashServer = NULL;

    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"https://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;
  }