Example #1
0
void PrintCrashInformation(PEXCEPTION_POINTERS except)
{
	echo("-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-\n");
	echo("Server has crashed. Reason was:\n");
	echo("   %s at 0x%08X\n", GetExceptionDescription(except->ExceptionRecord->ExceptionCode),	(unsigned long)except->ExceptionRecord->ExceptionAddress);
	echo("-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-\n");
}
Example #2
0
// called when an exception is detected (see below); provides detailed
// debugging information and exits.
//
// note: keep memory allocs and locking to an absolute minimum, because
// they may deadlock the process!
long __stdcall wseh_ExceptionFilter(struct _EXCEPTION_POINTERS* ep)
{
	// OutputDebugString raises an exception, which OUGHT to be swallowed
	// by WaitForDebugEvent but sometimes isn't. if we see it, ignore it.
	if(ep->ExceptionRecord->ExceptionCode == 0x40010006)	// DBG_PRINTEXCEPTION_C
		return EXCEPTION_CONTINUE_EXECUTION;

	// if run in a debugger, let it handle exceptions (tends to be more
	// convenient since it can bring up the crash location)
	if(IsDebuggerPresent())
		return EXCEPTION_CONTINUE_SEARCH;

	// make sure we don't recurse infinitely if this function raises an
	// SEH exception. (we may only have the guard page's 4 KB worth of
	// stack space if the exception is EXCEPTION_STACK_OVERFLOW)
	static intptr_t nestingLevel = 0;
	cpu_AtomicAdd(&nestingLevel, 1);
	if(nestingLevel >= 3)
		return EXCEPTION_CONTINUE_SEARCH;

	// someone is already holding the dbghelp lock - this is bad.
	// we'll report this problem first and then try to display the
	// exception info regardless (maybe dbghelp won't blow up).
	if(wutil_IsLocked(WDBG_SYM_CS) == 1)
		DEBUG_DISPLAY_ERROR(L"Exception raised while critical section is held - may deadlock..");

	// a dump file is essential for debugging, so write it before
	// anything else goes wrong (especially before showing the error
	// dialog because the user could choose to exit immediately)
	wdbg_sym_WriteMinidump(ep);

	// extract details from ExceptionRecord.
	wchar_t descriptionBuf[150];
	const wchar_t* description = GetExceptionDescription(ep, descriptionBuf, ARRAY_SIZE(descriptionBuf));
	wchar_t file[DEBUG_FILE_CHARS] = {0};
	int line = 0;
	wchar_t func[DEBUG_SYMBOL_CHARS] = {0};
	GetExceptionLocus(ep, file, &line, func);

	wchar_t message[500];
	const wchar_t* messageFormat =
		L"Much to our regret we must report the program has encountered an error.\r\n"
		L"\r\n"
		L"Please let us know at http://trac.wildfiregames.com/ and attach the crashlog.txt and crashlog.dmp files.\r\n"
		L"\r\n"
		L"Details: unhandled exception (%ls)\r\n";
	swprintf_s(message, ARRAY_SIZE(message), messageFormat, description);

	size_t flags = 0;
	if(ep->ExceptionRecord->ExceptionFlags & EXCEPTION_NONCONTINUABLE)
		flags = DE_NO_CONTINUE;
	const wchar_t* const lastFuncToSkip = WIDEN(STRINGIZE(DECORATED_NAME(wseh_ExceptionFilter)));
	ErrorReaction er = debug_DisplayError(message, flags, ep->ContextRecord, lastFuncToSkip, file,line,utf8_from_wstring(func).c_str(), 0);
	ENSURE(er == ER_CONTINUE);	// nothing else possible

	// invoke the Win32 default handler - it calls ExitProcess for
	// most exception types.
	return EXCEPTION_CONTINUE_SEARCH;
}
Example #3
0
void PrintCrashInformation(PEXCEPTION_POINTERS except)
{
	echo("-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-\n");
	echo("Server has crashed. Reason was:\n");
	echo("   %s at 0x%08X\n", GetExceptionDescription(except->ExceptionRecord->ExceptionCode),
	     (unsigned long)except->ExceptionRecord->ExceptionAddress);
#ifdef REPACK
	echo("%s repack by %s has crashed. Visit %s for support.", REPACK, REPACK_AUTHOR, REPACK_WEBSITE);
#endif
	echo("-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-\n");
}
Example #4
0
void PrintCrashInformation(PEXCEPTION_POINTERS except)
{
	time_t curtime = time(NULL);
	tm * pTime = localtime(&curtime);

	echo("-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-\n");
	echo("Server has crashed. Reason was:\n");
	echo("   %s at 0x%08X\n", GetExceptionDescription(except->ExceptionRecord->ExceptionCode),
		(unsigned long)except->ExceptionRecord->ExceptionAddress);
	if(pTime)
		echo("Logged at: %u %u %u %u %u", pTime->tm_mon, pTime->tm_mday, pTime->tm_hour, pTime->tm_min, pTime->tm_sec);
	echo("-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-\n");
	echo("Call Stack: \n");
	CStackWalker sw;
	sw.ShowCallstack();
	echo("-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-\n");
}
// Entry point into the main exception handling routine.  This routine is put into an except()
// statment at the beginning of a thread and is called anytime that there is a program exception
// The data is stored in a file called ErrorLog.txt in the data directory.
//
// data:			pointer to the exception data
// Message:		Any message	that should be printed out in the error log file
//
// returns: 
//
int __cdecl RecordExceptionInfo(PEXCEPTION_POINTERS data, const char *Message)
{
	static bool BeenHere = false;

	// Going recursive! That must mean this routine crashed!
	if (BeenHere) {
		return EXCEPTION_CONTINUE_SEARCH;
	}

	BeenHere = true;

	char	ModuleName[MAX_PATH];
	char	FileName[MAX_PATH] = "Unknown";
	// Create a filename to record the error information to.
	// Storing it in the executable directory works well.
	if (GetModuleFileName(0, ModuleName, sizeof(ModuleName)) <= 0) {
		ModuleName[0] = 0;
	}

	char *FilePart = GetFilePart(ModuleName);

	// Extract the file name portion and remove it's file extension. We'll
	// use that name shortly.
	lstrcpy(FileName, FilePart);
	char *lastperiod = strrchr(FileName, '.');
	if (lastperiod) {
		lastperiod[0] = 0;
	}

	// Replace the executable filename with our error log file name.
	lstrcpy(FilePart, "errorlog.txt");
	HANDLE LogFile = CreateFile(ModuleName, GENERIC_WRITE, 0, 0,
				OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL | FILE_FLAG_WRITE_THROUGH, 0);
	if (LogFile == INVALID_HANDLE_VALUE) {
		OutputDebugString("Error creating exception report");
		return EXCEPTION_CONTINUE_SEARCH;
	}

	// Append to the error log.
	SetFilePointer(LogFile, 0, 0, FILE_END);
	// Print out some blank lines to separate this error log from any previous ones.
	hprintf(LogFile, "\r\n\r\n\r\n\r\n");
	PEXCEPTION_RECORD	Exception = data->ExceptionRecord;
	PCONTEXT			Context = data->ContextRecord;

	char	CrashModulePathName[MAX_PATH];
	char	*CrashModuleFileName = "Unknown";
	MEMORY_BASIC_INFORMATION	MemInfo;
	// VirtualQuery can be used to get the allocation base associated with a
	// code address, which is the same as the ModuleHandle. This can be used
	// to get the filename of the module that the crash happened in.
	if (VirtualQuery((void*)Context->Eip, &MemInfo, sizeof(MemInfo)) && GetModuleFileName((HINSTANCE)MemInfo.AllocationBase, CrashModulePathName, sizeof(CrashModulePathName)) > 0) {
		CrashModuleFileName = GetFilePart(CrashModulePathName);
	}

	// Print out the beginning of the error log in a Win95 error window
	// compatible format.
	hprintf(LogFile, "%s caused %s in module %s at %04x:%08x.\r\n",
				FileName, GetExceptionDescription(Exception->ExceptionCode),
				CrashModuleFileName, Context->SegCs, Context->Eip);
	hprintf(LogFile, "Exception handler called in %s.\r\n", Message);
	RecordSystemInformation(LogFile);
	// If the exception was an access violation, print out some additional
	// information, to the error log and the debugger.
	if (Exception->ExceptionCode == STATUS_ACCESS_VIOLATION && Exception->NumberParameters >= 2) {
		char DebugMessage[1000];
		const char* readwrite = "Read from";
		if (Exception->ExceptionInformation[0]) {
			readwrite = "Write to";
		}

		wsprintf(DebugMessage, "%s location %08x caused an access violation.\r\n", readwrite, Exception->ExceptionInformation[1]);

#ifdef	_DEBUG
		// The VisualC++ debugger doesn't actually tell you whether a read
		// or a write caused the access violation, nor does it tell what
		// address was being read or written. So I fixed that.
		OutputDebugString("Exception handler: ");
		OutputDebugString(DebugMessage);
#endif

		hprintf(LogFile, "%s", DebugMessage);
	}

	// Print out the register values in a Win95 error window compatible format.
	hprintf(LogFile, "\r\n");
	hprintf(LogFile, "Registers:\r\n");
	hprintf(LogFile, "EAX=%08x CS=%04x EIP=%08x EFLGS=%08x\r\n",
				Context->Eax, Context->SegCs, Context->Eip, Context->EFlags);
	hprintf(LogFile, "EBX=%08x SS=%04x ESP=%08x EBP=%08x\r\n",
				Context->Ebx, Context->SegSs, Context->Esp, Context->Ebp);
	hprintf(LogFile, "ECX=%08x DS=%04x ESI=%08x FS=%04x\r\n",
				Context->Ecx, Context->SegDs, Context->Esi, Context->SegFs);
	hprintf(LogFile, "EDX=%08x ES=%04x EDI=%08x GS=%04x\r\n",
				Context->Edx, Context->SegEs, Context->Edi, Context->SegGs);
	hprintf(LogFile, "Bytes at CS:EIP:\r\n");

	// Print out the bytes of code at the instruction pointer. Since the
	// crash may have been caused by an instruction pointer that was bad,
	// this code needs to be wrapped in an exception handler, in case there
	// is no memory to read. If the dereferencing of code[] fails, the
	// exception handler will print '??'.
	unsigned char *code = (unsigned char*)Context->Eip;
	for (int codebyte = 0; codebyte < NumCodeBytes; codebyte++) {
#ifdef _MSC_VER
		__try {
#endif
			hprintf(LogFile, "%02x ", code[codebyte]);
#ifdef _MSC_VER
		}
		__except(EXCEPTION_EXECUTE_HANDLER) {
			hprintf(LogFile, "?? ");
		}
#endif
	}

#ifdef _MSC_VER
	// Time to print part or all of the stack to the error log. This allows
	// us to figure out the call stack, parameters, local variables, etc.
	hprintf(LogFile, "\r\n"
					 "Stack dump:\r\n");
	__try {
		// Esp contains the bottom of the stack, or at least the bottom of
		// the currently used area.
		DWORD* pStack = (DWORD *)Context->Esp;
		DWORD* pStackTop;
		__asm
		{
			// Load the top (highest address) of the stack from the
			// thread information block. It will be found there in
			// Win9x and Windows NT.
			mov	eax, fs:[4]
			mov pStackTop, eax
		}
		if (pStackTop > pStack + MaxStackDump) {
			pStackTop = pStack + MaxStackDump;
		}

		int Count = 0;
		// Too many calls to WriteFile can take a long time, causing
		// confusing delays when programs crash. Therefore I implemented
		// simple buffering for the stack dumping code instead of calling
		// hprintf directly.
		char	buffer[1000] = "";
		const int safetyzone = 50;
		char*	nearend = buffer + sizeof(buffer) - safetyzone;
		char*	output = buffer;
		while (pStack + 1 <= pStackTop) 	{
			if ((Count % StackColumns) == 0) {
				output += wsprintf(output, "%08x: ", pStack);
			}

			char *Suffix = " ";
			if ((++Count % StackColumns) == 0 || pStack + 2 > pStackTop) {
				Suffix = "\r\n";
			}

			output += wsprintf(output, "%08x%s", *pStack, Suffix);
			pStack++;
			// Check for when the buffer is almost full, and flush it to disk.
			if (output > nearend) {
				hprintf(LogFile, "%s", buffer);
				buffer[0] = 0;
				output = buffer;
			}
		}
		// Print out any final characters from the cache.
		hprintf(LogFile, "%s", buffer);
	}
	__except(EXCEPTION_EXECUTE_HANDLER) {
		hprintf(LogFile, "Exception encountered during stack dump.\r\n");
	}
#endif

#ifndef NDEBUG
	if (safe_string[0])
		hprintf(LogFile, "Last safe point: %s\r\n", safe_string);
#endif

	RecordModuleList(LogFile);

	CloseHandle(LogFile);
	// Return the magic value which tells Win32 that this handler didn't
	// actually handle the exception - so that things will proceed as per
	// normal.

	return EXCEPTION_CONTINUE_SEARCH;
}
void ExceptionHandler(unsigned int, PEXCEPTION_POINTERS lpCeption)
{
	//Get time
	SYSTEMTIME st;
	GetLocalTime(&st);
	TCHAR szTime[120] = {0};
	sprintf_s(szTime, 120, "%d-%d-%d-%d-%d-%d", st.wYear, st.wMonth, st.wDay, st.wHour, st.wMinute, st.wSecond);

	//Get current module name
	TCHAR* lpCurModuleName = _T("Current Module name");
	TCHAR szModuleName[MAX_PATH] = {0};
	if (GetModuleFileName(NULL, szModuleName, MAX_PATH) > 0)
		lpCurModuleName = GetFilePart(szModuleName);

	//Create log file
	TCHAR szFilePath[MAX_PATH] = {0};
	TCHAR szLogPath[MAX_PATH] = {0};
	GetCurrentDirectory(MAX_PATH, szFilePath);
	sprintf_s(szLogPath, MAX_PATH, "%s\\Exception-%s.log", szFilePath, szTime);

	HANDLE hLogFile = CreateFile(szLogPath, GENERIC_WRITE, 0, 0, 
		CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL | FILE_FLAG_WRITE_THROUGH, 0);
	if (hLogFile == INVALID_HANDLE_VALUE)
		return;// EXCEPTION_CONTINUE_SEARCH;

	PEXCEPTION_RECORD Exception = lpCeption->ExceptionRecord;
	PCONTEXT          Context   = lpCeption->ContextRecord;
	TCHAR szCrashModuleName[MAX_PATH] = {0};
	TCHAR* lpCrashName = _T("Exception Process Name");
	MEMORY_BASIC_INFORMATION memInfo;
	// VirtualQuery can be used to get the allocation base associated with a
	// code address, which is the same as the ModuleHandle. This can be used
	// to get the filename of the module that the crash happened in.
	if (VirtualQuery((LPCVOID)Context->Eip, &memInfo, sizeof(memInfo)) && (GetModuleFileName((HMODULE)memInfo.AllocationBase, szCrashModuleName, MAX_PATH) > 0))
		lpCrashName = GetFilePart(szCrashModuleName);
	WriteLogFile(hLogFile, "%s caused %s(0x%08x) in module %s at %04x:%08x.\r\n",
		lpCurModuleName, GetExceptionDescription(Exception->ExceptionCode), Exception->ExceptionCode, lpCrashName, Context->SegCs, Context->Eip);

	//Write system info to logfile
	DumpSystemInformation(hLogFile, lpCurModuleName);

	// Print out the bytes of code at the instruction pointer. Since the
	// crash may have been caused by an instruction pointer that was bad,
	// this code needs to be wrapped in an exception handler, in case there
	// is no memory to read. If the dereferencing of code[] fails, the
	// exception handler will print '??'.
	WriteLogFile(hLogFile, _T("\r\n\r\nCode Start CS:EIP:\r\n"));
	BYTE * code = (BYTE *)Context->Eip;
	for (int codebyte = 0; codebyte < 16; codebyte++)
	{
		__try
		{
			WriteLogFile(hLogFile, _T("%02x "), code[codebyte]);
		}
		__except(EXCEPTION_EXECUTE_HANDLER)
		{
			WriteLogFile(hLogFile, _T("?? "));
		}
	}
	//Write Stack information to logfile
	DumpStackStak(hLogFile, lpCeption);
	//Write module of process information to logfile
	DumpModuleList(hLogFile);
	CloseHandle(hLogFile);
	
	//Create dump file
	sprintf_s(szLogPath, MAX_PATH, "%s\\Exception-%s.dmp", szFilePath, szTime);
	HANDLE hDumpFile = CreateFile(szLogPath, GENERIC_WRITE, 0, 0, 
		CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL | FILE_FLAG_WRITE_THROUGH, 0);
	if (hDumpFile == INVALID_HANDLE_VALUE)
		return;// EXCEPTION_CONTINUE_SEARCH;
	
	MINIDUMP_EXCEPTION_INFORMATION eInfo;
	eInfo.ThreadId = GetCurrentThreadId();
	eInfo.ExceptionPointers = lpCeption;
	eInfo.ClientPointers = FALSE;
	MiniDumpWriteDump(GetCurrentProcess(), GetCurrentProcessId(), hDumpFile, MiniDumpNormal, &eInfo, NULL, NULL);
	CloseHandle(hDumpFile);
}
Example #7
0
void DoReport(LPCTSTR lpstrCmdLine, BOOL *pIsHandled)
{
	WSADATA wsaData = {0};
	WSAStartup(MAKEWORD(2, 2), &wsaData);

	//LogFinal(LOG::KBugReport) << L"Bugreport启动命令行: " << lpstrCmdLine;

	REPORT_CONTEXT report;
	std::wstring strProductName;

	const TCHAR * p = _tcsstr(lpstrCmdLine, _T("pid="));
	if (p)
	{
		*pIsHandled = TRUE;

		DWORD client_process_id = _tcstoul(p + _tcslen(_T("pid=")), 0, 0);

		p = _tcsstr(lpstrCmdLine, _T("context="));
		if (p)
		{
			void *addr = (void*)_tcstoul(p + _tcslen(_T("context=")), 0, 0);
			//YYBrowser Begin
			//by ZC. 2013-10-30 11:26.
			// hClientProcess客户进程,即是启动YGCrashReport的进程,不一定是崩溃的目标进程。
			HANDLE client_process_handle = ::OpenProcess(PROCESS_QUERY_INFORMATION|PROCESS_VM_READ, FALSE, client_process_id);
			// 崩溃目标进程。			
			HANDLE target_process_handle = NULL;
			//YYBrowser End
			if (!client_process_handle)
				LogFinal(LOG::KBugReport) << L"打开进程句柄失败";

			//解释REPORT_PARAMS
			CRASH_LAUNCH_PARAMS crash_launch_params = {0};
			DWORD cbRead = 0;
			if (addr && ::ReadProcessMemory(client_process_handle, addr, &crash_launch_params, sizeof(crash_launch_params), &cbRead))
			{
				LogFinal(LOG::KBugReport) << L"读取REPORT_PARAMS成功";
				
				std::set<std::wstring> setSuspectModule;
				std::set<std::wstring> setModule;
				std::wstring strPathNoExt = GenerateNewFilePath(crash_launch_params.dwPID);					

				report.strZipFilePath = strPathNoExt + _T(".zip");
				report.strOSVer = GetOSVer();

				AtoW(crash_launch_params.szProductName, -1, strProductName);
				
				report.dwReportId = crash_launch_params.dwReportId;
				report.strUserId = crash_launch_params.szUserId;
				report.strProductId = crash_launch_params.szProductId;
				report.strProductVer = crash_launch_params.szProductVer;
				report.strProductVerDetail = crash_launch_params.szProductVerDetail;
				//AtoW(crash_launch_params.szRestartExePath, -1, report.wstrRestartExePath);

				report.strDynaReleaseVer = crash_launch_params.szDynaReleaseVer;
			
				WriteBugInfo(report.dwReportId);
				report.dwCount24Hour = GetBugCount(report.dwReportId);

				//parse 自定义文件路径
				if (crash_launch_params.nFileCount > 0)
				{
					char *pPaths = new char[MAX_PATH * crash_launch_params.nFileCount];
					if (::ReadProcessMemory(client_process_handle, crash_launch_params.lpszCustomFilePaths, pPaths, MAX_PATH * crash_launch_params.nFileCount, &cbRead))
					{
						for (UINT k = 0; k < cbRead / MAX_PATH; k++)
						{
							std::wstring wstrPath;
							AtoW(pPaths + k * MAX_PATH, -1, wstrPath);
							report.vecOtherFilePath.push_back(wstrPath);
						}
					}
					delete [] pPaths;
					pPaths = NULL;
				}	
				
				//生成log
				std::string strLog;
				char szTemp[1024] = {0};


				//Date
				time_t curTime = 0;
				time(&curTime);
				strftime(szTemp, _countof(szTemp)-1, "%Y-%m-%d %H.%M.%S\r\n", localtime(&curTime));
				strLog += szTemp;
				strLog += "\r\n";

				//异常信息
				strLog += "Exception:\r\n";
				const char *pModName = strrchr(crash_launch_params.szExcepModPath, '\\');
				if (pModName)
					pModName++;
				else
					pModName = crash_launch_params.szExcepModPath;
			
				report.strExcepModuleName = pModName;
				_snprintf_s(szTemp, _countof(szTemp), _TRUNCATE, "Module=%s\r\n", pModName);
				strLog += szTemp;

				//YYBrowser Begin
				//打开目标进程。by ZC. 2013-10-30 11:30.
				target_process_handle = ::OpenProcess(PROCESS_QUERY_INFORMATION|PROCESS_VM_READ, FALSE, crash_launch_params.dwPID);
				//YYBrowser End
				//YYBrowser Begin
				//从目标进程中读出结构异常。by ZC. 2013-10-30 11:28.
				if (crash_launch_params.pExceptionInfo) {
					EXCEPTION_RECORD excep = {0};
					CONTEXT ct = {0};
					EXCEPTION_POINTERS ptr = {0};
					if (::ReadProcessMemory(target_process_handle, crash_launch_params.pExceptionInfo, &ptr, sizeof(ptr), &cbRead)
						&& ::ReadProcessMemory(target_process_handle, ptr.ExceptionRecord, &excep, sizeof(excep), &cbRead)
						&& ::ReadProcessMemory(target_process_handle, ptr.ContextRecord, &ct, sizeof(ct), &cbRead))
					{
						report.dwExcepAddr = (DWORD)excep.ExceptionAddress;
						report.dwExcepCode = excep.ExceptionCode;
						report.strExcepDiscription = GetExceptionDescription(excep.ExceptionCode);

						_snprintf_s(szTemp, _countof(szTemp), _TRUNCATE, "ExceptionCode=0x%08x, %s\r\n", excep.ExceptionCode, GetExceptionDescription(excep.ExceptionCode));
						strLog += szTemp;

						_snprintf_s(szTemp, _countof(szTemp), _TRUNCATE, "eip=0x%08x, ebp=0x%08x, esp=0x%08x, eax=0x%08x, ebx=0x%08x, ecx=0x%08x, edx=0x%08x, esi=0x%08x, edi=0x%08x\r\n", ct.Eip, ct.Ebp, ct.Esp, ct.Eax, ct.Ebx, ct.Ecx, ct.Edx, ct.Esi, ct.Edi);
						strLog += szTemp;
					}
					strLog += "\r\n";
				}
				//YYBrowser End

				strLog += "Summary:\r\n";
				strLog += GetSummary(client_process_handle);
				strLog += "UserId(YY)=" + report.strUserId + "\r\n";
				strLog += "ProductVer=" + report.strProductVer + "\r\n";
				strLog += "DynaReleaseVer=" + report.strDynaReleaseVer + "\r\n";				
				strLog += "ProductVerDetail=" + report.strProductVerDetail + "\r\n";
				_snprintf_s(szTemp, _countof(szTemp), _TRUNCATE, "ReportId=%u\r\n", report.dwReportId);
				strLog += szTemp;

				strLog += "\r\n";
				
				std::string strLoginHistoryLog;
				std::string strLoginHistory = ReadLoginHistory(strLoginHistoryLog);

				//用户自定义信息
				strLog += "CustomProperty:\r\n";
				char *pCustomProperty = new char[crash_launch_params.cchCustomProperty + 1];
				if (::ReadProcessMemory(client_process_handle, crash_launch_params.lpszCustomProperty, pCustomProperty, crash_launch_params.cchCustomProperty, &cbRead))
				{
					pCustomProperty[cbRead/sizeof(char)] = 0;

					report.strCustomProperty = pCustomProperty;
					
				}

				strLog += report.strCustomProperty;

				if(strLoginHistory.size()>0)
				{
					if(report.strCustomProperty.size()>0)
					{
						report.strCustomProperty+="&";
					}

					report.strCustomProperty+=strLoginHistory;
				}
			
				if(strLoginHistoryLog.size()>0)
				{
					strLog += "\r\n";
					strLog += strLoginHistoryLog;
				}
				strLog += "\r\n";

				//CallStack
				strLog += "Call Stack:\r\n";
				char *pCallStack = new char[crash_launch_params.cchCallStack + 1];
				cbRead = 0;
				if (::ReadProcessMemory(client_process_handle, crash_launch_params.lpszCallStack, pCallStack, crash_launch_params.cchCallStack, &cbRead))
				{
					pCallStack[cbRead/sizeof(char)] = 0;
					strLog += pCallStack;
				}
				strLog += "\r\n";

				//收集进程列表&检测运行环境
				std::string  strProcListA;
				std::wstring strProcListW;
				report.dwRunEnvironment = CheckRunEnvironment(strProcListW);
				WtoA(strProcListW.c_str(), -1, strProcListA);
				strLog += "Process List:\r\n";
				strLog += strProcListA;
				strLog += "\r\n";

				//收集版本的语言种类,不写入日志
				report.strProductLang = GetLanguageName();

				//模块列表
				strLog += "Module List:\r\n";
				strLog += GetModuleList(target_process_handle,&setModule,&setSuspectModule);
				strLog += "\r\n";
				
				//程序Log
				strLog += "Log:\r\n";
				TCHAR szExePath[MAX_PATH] = {0};
				GetModuleFileNameEx(target_process_handle, NULL, szExePath, _countof(szExePath));
				TCHAR *p = _tcsrchr(szExePath, _T('.'));
				if (p)
					*p = 0;
				TCHAR* pExeName = _tcsrchr(szExePath, _T('\\'));
				if (pExeName)
					pExeName++;
				else
					pExeName = szExePath;
				
				const DWORD dwMaxLogSize = 1024 * 200;
			//	char *pContent = new char [dwMaxLogSize];
			//	GetLastLog(pExeName, reportParams.dwPID, 0, pContent, dwMaxLogSize);
			//	strLog += pContent;
			//	delete [] pContent;
			//	pContent = NULL;
				strLog += "\r\n\r\n";
				/************************************************************************/
				/*功能:在日志文件中添加安装目录下所有dll和rcc文件的md5*/	
                /***************************只有yy.exe崩溃时,才会计算相关文件的md5*/
                if (StrCmpIA(crash_launch_params.szProductId, "YY") == 0)
                {
                    strLog += "[List *.dll and *.rcc files MD5:] \r\n\r\n";		
                    TCHAR szCurrentProcesspath[MAX_PATH] = {0};                
                    if ( GetModuleFileName(NULL,szCurrentProcesspath,_countof(szCurrentProcesspath)) > 0)
                    {
                        TCHAR* p_findDir = _tcsrchr(szCurrentProcesspath,_T('\\'));    
                        std::wstring rawCurrentProcessPath = szCurrentProcesspath;
                        std::wstring strCurrentProcesspath  =  rawCurrentProcessPath.substr(0, p_findDir - szCurrentProcesspath);

                        strLog += dwCalculateMD5(strCurrentProcesspath.c_str());                  
                    }
                    else
                    {
                        strLog += "Get the files'MD5 failed!";
                    }
                }
                else
                {
                    strLog += "Hint:\r\nThe crash was caused by the other products except the YY!";
                }				
                /************************************************************************/
				TCHAR szLogPath[_MAX_PATH] = {0};
				_sntprintf_s(szLogPath, _countof(szLogPath), _TRUNCATE, _T("%s.txt"), strPathNoExt.c_str());
				report.strLogPath = szLogPath;

				LogFinal(LOG::KBugReport) << L"写入log文件: " << szLogPath;
				
				HANDLE hFile = ::CreateFile(szLogPath, GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, CREATE_ALWAYS, NULL, NULL);
				DWORD dwWriten = 0;
				::WriteFile(hFile, strLog.c_str(), strLog.size(), &dwWriten, NULL);
				::CloseHandle(hFile);
	
				//生成dump
				TCHAR szDumpPath[_MAX_PATH] = {0};
				_sntprintf_s(szDumpPath, _countof(szDumpPath), _TRUNCATE, _T("%s.dmp"), strPathNoExt.c_str());

				LogFinal(LOG::KBugReport) << L"生成dump文件: " << szDumpPath;
				int nDumpType = (MiniDumpNormal|MiniDumpWithHandleData|MiniDumpWithIndirectlyReferencedMemory|MiniDumpWithUnloadedModules|MiniDumpWithProcessThreadData);
				if (!CreateDump(szDumpPath, crash_launch_params.dwPID, crash_launch_params.dwTID, crash_launch_params.pExceptionInfo, nDumpType, MyMiniDumpCallBack, &crash_launch_params))
				{
					crash_launch_params.curCustomDataIdx = 0;
					CreateDump(szDumpPath, crash_launch_params.dwPID, crash_launch_params.dwTID, crash_launch_params.pExceptionInfo, MiniDumpNormal, MyMiniDumpCallBack, &crash_launch_params);
				}
				report.strDumpPath = szDumpPath;

				//生成fulldump
				CRegKey key;
				LONG lResult = key.Open(HKEY_CURRENT_USER, _T("Software\\duowan\\bugreport"), KEY_READ);
				if (ERROR_SUCCESS == lResult)
				{
					TCHAR	szFullDump[1024] = {0};
					DWORD dwSize = _countof(szFullDump);
					lResult = key.QueryValue(szFullDump, _T("fulldump"), &dwSize);
					if (ERROR_SUCCESS == lResult)
					{
						szFullDump[dwSize] = 0;
						if (_tcsicmp(szFullDump, _T("yes")) == 0)
						{
							nDumpType = (MiniDumpNormal 
								| MiniDumpWithFullMemory 
								| MiniDumpWithIndirectlyReferencedMemory 
								| MiniDumpWithHandleData
								| MiniDumpWithUnloadedModules
								| MiniDumpWithProcessThreadData);

							TCHAR szFullDumpPath[_MAX_PATH] = {0};
							::GetTempPath(_countof(szFullDumpPath), szFullDumpPath);
							_tcsncat_s(szFullDumpPath, _countof(szFullDumpPath), _T("duowan\\fulldump.dmp"), _TRUNCATE);

							LogFinal(LOG::KBugReport) << L"生成fulldump文件: " << szFullDumpPath;

							CreateDump(szFullDumpPath, crash_launch_params.dwPID, crash_launch_params.dwTID, crash_launch_params.pExceptionInfo, nDumpType, MyMiniDumpCallBack, &crash_launch_params);
						}
					}
				}

				::SetEvent(crash_launch_params.evDumpComplete);

				if (crash_launch_params.bShowReportUI)
				{
					LogFinal(LOG::KBugReport) << L"开始弹出崩溃界面";
					
					std::string strRecv;
					bool bShowModifyStatus = false;

					//if(GetBugModifyStatus(&report,strRecv))
					//{
					//	const char* p = strstr(strRecv.c_str(),"return=true");
					//	if(p)
					//	{
					//		bShowModifyStatus = true;
					//	}
					//}

					CMessageLoop theLoop;
					_Module.AddMessageLoop(&theLoop);

					CDlgReport dlgMain(strProductName.c_str(), &report, crash_launch_params.dwPID, &setModule, &setSuspectModule, bShowModifyStatus, strRecv.c_str());
					dlgMain.Create(NULL);

					dlgMain.ShowWindow(SW_SHOW);

					theLoop.Run();

					_Module.RemoveMessageLoop();
				}
				else
				{
					SendReport(&report, &setModule, &setSuspectModule);
				}
			}
			else
			{
				LogFinal(LOG::KBugReport) << L"读取崩溃进程REPORT_PARAMS失败";
			}

			::CloseHandle(target_process_handle);
			::CloseHandle(client_process_handle);
		}
	}
}