PUBLIC HttpUri *httpCloneUri(HttpUri *base, int flags) { HttpUri *up; char *path, *cp, *tok; if ((up = mprAllocObj(HttpUri, manageUri)) == 0) { up->valid = 0; return 0; } if (!base || !base->valid) { up->valid = 0; return up; } if (base->scheme) { up->scheme = sclone(base->scheme); } else if (flags & HTTP_COMPLETE_URI) { up->scheme = sclone("http"); } up->secure = (smatch(up->scheme, "https") || smatch(up->scheme, "wss")); up->webSockets = (smatch(up->scheme, "ws") || smatch(up->scheme, "wss")); if (base->host) { up->host = sclone(base->host); } else if (flags & HTTP_COMPLETE_URI) { up->host = sclone("localhost"); } if (base->port) { up->port = base->port; } else if (flags & HTTP_COMPLETE_URI) { up->port = up->secure ? 443 : 80; } path = base->path; if (path) { while (path[0] == '/' && path[1] == '/') { path++; } up->path = sclone(path); } if (flags & (HTTP_COMPLETE_URI | HTTP_COMPLETE_URI_PATH)) { if (up->path == 0 || *up->path == '\0') { up->path = sclone("/"); } } if (base->reference) { up->reference = sclone(base->reference); } if (base->query) { up->query = sclone(base->query); } if (up->path && (tok = srchr(up->path, '.')) != 0) { if ((cp = srchr(up->path, '/')) != 0) { if (cp <= tok) { up->ext = sclone(&tok[1]); } } else { up->ext = sclone(&tok[1]); } } up->valid = 1; return up; }
BOOL STDCALL OSGetLoadedModuleList(HANDLE hProcess, StringList &ModuleList) { HMODULE hMods[1024]; DWORD count; if (EnumProcessModulesEx(hProcess, hMods, sizeof(hMods), &count, LIST_MODULES_ALL)) { for (UINT i=0; i<(count / sizeof(HMODULE)); i++) { TCHAR szFileName[MAX_PATH]; if (GetModuleFileNameEx(hProcess, hMods[i], szFileName, _countof(szFileName)-1)) { TCHAR *p; p = srchr(szFileName, '\\'); if (p) { *p = 0; p++; } slwr (p); ModuleList << p; } } } else return 0; return 1; }
String GetPathExtension(CTSTR lpPath) { assert(lpPath); if(!lpPath) return String(); TSTR lpExtensionStart = srchr(lpPath, '.'); if(lpExtensionStart) return String(lpExtensionStart+1); else return String(); }
String GetPathFileName(CTSTR lpPath, BOOL bExtension) { assert(lpPath); if(!lpPath) return String(); OSFindData ofd; HANDLE hFind = OSFindFirstFile(lpPath, ofd); if(!hFind) ofd.bDirectory = FALSE; else OSFindClose(hFind); if(!ofd.bDirectory) { CTSTR lpDirectoryEnd = srchr(lpPath, '/'); if(!lpDirectoryEnd) lpDirectoryEnd = srchr(lpPath, '/'); if(lpDirectoryEnd) lpPath = lpDirectoryEnd+1; } String newPath = lpPath; if(newPath.IsValid()) { if(!bExtension) { TSTR pDot = srchr(newPath, '.'); if(pDot) newPath.SetLength((int)((((UPARAM)pDot)-((UPARAM)newPath.Array()))/sizeof(TCHAR))); } } return newPath; }
String GetPathDirectory(CTSTR lpPath) { assert(lpPath); if(!lpPath) return String(); OSFindData ofd; HANDLE hFind = OSFindFirstFile(lpPath, ofd); if(!hFind) ofd.bDirectory = FALSE; else OSFindClose(hFind); int nDirectoryEnd; if(!ofd.bDirectory) { CTSTR lpDirectoryEnd = srchr(lpPath, '/'); if(!lpDirectoryEnd) lpDirectoryEnd = srchr(lpPath, '/'); if(lpDirectoryEnd) nDirectoryEnd = (int)((((UPARAM)lpDirectoryEnd)-((UPARAM)lpPath))/sizeof(TCHAR)); else nDirectoryEnd = slen(lpPath); } else nDirectoryEnd = slen(lpPath); String newPath = lpPath; newPath.SetLength(nDirectoryEnd); return newPath; }
String GetPathWithoutExtension(CTSTR lpPath) { assert(lpPath); if(!lpPath) return String(); TSTR lpExtensionStart = srchr(lpPath, '.'); if(lpExtensionStart) { UINT newLength = (UINT)(UPARAM)(lpExtensionStart-lpPath); if(!newLength) return String(); String newString; newString.SetLength(newLength); scpy_n(newString, lpPath, newLength); return newString; } else return String(lpPath); }
static void trimPathToDirname(HttpUri *uri) { char *path, *cp; int len; path = uri->path; len = (int) slen(path); if (path[len - 1] == '/') { if (len > 1) { path[len - 1] = '\0'; } } else { if ((cp = srchr(path, '/')) != 0) { if (cp > path) { *cp = '\0'; } else { cp[1] = '\0'; } } else if (*path) { path[0] = '\0'; } } }
String HTTPGetString (CTSTR url, CTSTR extraHeaders, int *responseCode, String verb) { HINTERNET hSession = NULL; HINTERNET hConnect = NULL; HINTERNET hRequest = NULL; URL_COMPONENTS urlComponents; BOOL secure = FALSE; String result = ""; String body = TEXT(""); String nurl = url; String hostName, path; const TCHAR *acceptTypes[] = { TEXT("*/*"), NULL }; if (verb == TEXT("POST")){ CTSTR s = srchr(url, TEXT('?')); body = String(s + 1); nurl = nurl.Left(s - url); } hostName.SetLength(256); path.SetLength(1024); zero(&urlComponents, sizeof(urlComponents)); urlComponents.dwStructSize = sizeof(urlComponents); urlComponents.lpszHostName = hostName; urlComponents.dwHostNameLength = hostName.Length(); urlComponents.lpszUrlPath = path; urlComponents.dwUrlPathLength = path.Length(); WinHttpCrackUrl(nurl, 0, 0, &urlComponents); if (urlComponents.nPort == 443) secure = TRUE; hSession = WinHttpOpen(TEXT("gecko test"), WINHTTP_ACCESS_TYPE_DEFAULT_PROXY, WINHTTP_NO_PROXY_NAME, WINHTTP_NO_PROXY_BYPASS, 0); if (!hSession) goto failure; hConnect = WinHttpConnect(hSession, hostName, secure ? INTERNET_DEFAULT_HTTPS_PORT : INTERNET_DEFAULT_HTTP_PORT, 0); if (!hConnect) goto failure; hRequest = WinHttpOpenRequest(hConnect, verb, path, NULL, WINHTTP_NO_REFERER, acceptTypes, secure ? WINHTTP_FLAG_SECURE|WINHTTP_FLAG_REFRESH : WINHTTP_FLAG_REFRESH); if (!hRequest) goto failure; BOOL bResults = WinHttpSendRequest(hRequest, extraHeaders, extraHeaders ? -1 : 0, body.Array(), body.Length(), body.Length(), 0); // End the request. if (bResults) bResults = WinHttpReceiveResponse(hRequest, NULL); else goto failure; TCHAR statusCode[8]; DWORD statusCodeLen; statusCodeLen = sizeof(statusCode); if (!WinHttpQueryHeaders (hRequest, WINHTTP_QUERY_STATUS_CODE, WINHTTP_HEADER_NAME_BY_INDEX, &statusCode, &statusCodeLen, WINHTTP_NO_HEADER_INDEX)) goto failure; *responseCode = wcstoul(statusCode, NULL, 10); if (bResults && *responseCode == 200) { CHAR buffer[16384]; DWORD dwSize, dwOutSize; do { // Check for available data. dwSize = 0; if (!WinHttpQueryDataAvailable(hRequest, &dwSize)) goto failure; if (!WinHttpReadData(hRequest, (LPVOID)buffer, dwSize, &dwOutSize)) { goto failure; } else { if (!dwOutSize) break; // Ensure the string is terminated. buffer[dwOutSize] = 0; String b = String((LPCSTR)buffer); result.AppendString(b); } } while (dwSize > 0); } failure: if (hSession) WinHttpCloseHandle(hSession); if (hConnect) WinHttpCloseHandle(hConnect); if (hRequest) WinHttpCloseHandle(hRequest); return result; }
static bool inRange(MprVersion *vp, cchar *expr) { char *cp, *ver, *op, *base, *pre, *all; cchar *high, *low; uint64 factor, min, max, num; while (isspace((uchar) *expr)) expr++; if (srmatch(expr, semExpr, &all, &op, &ver, NULL) <= 0) { mprLog("error", 5, "Bad version expression: %s", expr); return 0; } if (smatch(op, "~")) { /* ~VER Compatible with VER at the level of specificity given. ~1.2.3 == (>=1.2.3 <1.3.0) Compatible at the patch level ~1.2 == 1.2.x Compatible at the minor level ~1 == 1.x Compatible at the major level */ if (partCount(ver) == 3 && (cp = srchr(ver, '.')) != 0) { high = sjoin(snclone(ver, cp - ver), ".", MAX_VER_STR, NULL); if ((cp = schr(ver, '-')) != 0) { high = sjoin(high, cp, NULL); } return inRange(vp, sjoin(">=", ver, NULL)) && inRange(vp, sjoin("<", high, NULL)); } return inRange(vp, completeVersion(ver, "x")); } if (smatch(op, "^")) { /* ^VER Compatible with VER at the most significant level. ^0.2.3 == 0.2.3 <= VER < 0.3.0 ^1.2.3 == 1.2.3 <= VER < 2.0.0 So convert to a range */ high = ver; for (cp = ver, factor = VER_FACTOR * VER_FACTOR; *cp; cp++) { if (*cp == '.') { factor /= VER_FACTOR; } else if (isdigit((uchar) *cp) && *cp != '0') { num = (stoi(cp) + 1) * factor; high = numberToVersion(num); if ((cp = schr(ver, '-')) != 0) { high = sjoin(high, cp, NULL); } break; } } return inRange(vp, sjoin(">=", ver, NULL)) && inRange(vp, sjoin("<", high, NULL)); } ver = completeVersion(ver, "x"); if (srmatch(ver, semCriteria, &all, &base, &pre, NULL) <= 0) { mprLog("error", 5, "Cannot match version %s", ver); return 0; } if (vp->preVersion) { if (!pre) { return 0; } if (snumber(vp->preVersion)) { if (stoi(pre) < stoi(vp->preVersion)) { return 0; } } else { if (scmp(pre, vp->preVersion) < 0 && !smatch(pre, "-")) { return 0; } } } min = 0; max = MAX_VER * VER_FACTOR * VER_FACTOR; if (schr(ver, 'x')) { if (smatch(op, ">=")) { // 1.2.3 >= 2.x.x ... 1.2.3 >= 2.0.0 low = sreplace(ver, "x", "0"); min = versionToNumber(low); } else if (smatch(op, "<=")) { // 1.2.3 < 2.x.x ... 1.2.3 <2.MAX.MAX high = sreplace(ver, "x", MAX_VER_STR); max = versionToNumber(high); } else if (*op == '>') { // 1.2.3 > 2.x.x ... 1.2.3 > 2.0.0 low = sreplace(ver, "x", "0"); min = versionToNumber(low) + 1; } else if (*op == '<') { // 1.2.3 < 2.x.x ... 1.2.3 <2.MAX.MAX high = sreplace(ver, "x", MAX_VER_STR); max = versionToNumber(high) - 1; } else { low = sreplace(ver, "x", "0"); high = sreplace(ver, "x", MAX_VER_STR); return inRange(vp, sjoin(">=", low, NULL)) && inRange(vp, sjoin("<", high, NULL)); } } else if (smatch(op, ">=")) { min = versionToNumber(base); } else if (smatch(op, "<=")) { max = versionToNumber(base); } else if (*op == '>') { min = versionToNumber(base) + 1; } else if (*op == '<') { max = versionToNumber(base) - 1; } else { min = max = versionToNumber(base); } if (min <= vp->numberVersion && vp->numberVersion <= max) { return 1; } return 0; }
LONG CALLBACK OBSExceptionHandler (PEXCEPTION_POINTERS exceptionInfo) { HANDLE hProcess; HMODULE hDbgHelp; MINIDUMP_EXCEPTION_INFORMATION miniInfo; STACKFRAME64 frame = {0}; CONTEXT context = *exceptionInfo->ContextRecord; SYMBOL_INFO *symInfo; DWORD64 fnOffset; TCHAR logPath[MAX_PATH]; OSVERSIONINFOEX osInfo; SYSTEMTIME timeInfo; ENUMERATELOADEDMODULES64 fnEnumerateLoadedModules64; SYMSETOPTIONS fnSymSetOptions; SYMINITIALIZE fnSymInitialize; STACKWALK64 fnStackWalk64; SYMFUNCTIONTABLEACCESS64 fnSymFunctionTableAccess64; SYMGETMODULEBASE64 fnSymGetModuleBase64; SYMFROMADDR fnSymFromAddr; SYMCLEANUP fnSymCleanup; MINIDUMPWRITEDUMP fnMiniDumpWriteDump; SYMGETMODULEINFO64 fnSymGetModuleInfo64; DWORD i; DWORD64 InstructionPtr; DWORD imageType; TCHAR searchPath[MAX_PATH], *p; static BOOL inExceptionHandler = FALSE; moduleinfo_t moduleInfo; //always break into a debugger if one is present if (IsDebuggerPresent ()) return EXCEPTION_CONTINUE_SEARCH; //exception codes < 0x80000000 are typically informative only and not crash worthy //0xe06d7363 indicates a c++ exception was thrown, let's just hope it was caught. //this is no longer needed since we're an unhandled handler vs a vectored handler /*if (exceptionInfo->ExceptionRecord->ExceptionCode < 0x80000000 || exceptionInfo->ExceptionRecord->ExceptionCode == 0xe06d7363 || exceptionInfo->ExceptionRecord->ExceptionCode == 0x800706b5) return EXCEPTION_CONTINUE_SEARCH;*/ //uh oh, we're crashing inside ourselves... this is really bad! if (inExceptionHandler) return EXCEPTION_CONTINUE_SEARCH; inExceptionHandler = TRUE; //load dbghelp dynamically hDbgHelp = LoadLibrary (TEXT("DBGHELP")); if (!hDbgHelp) return EXCEPTION_CONTINUE_SEARCH; fnEnumerateLoadedModules64 = (ENUMERATELOADEDMODULES64)GetProcAddress (hDbgHelp, "EnumerateLoadedModulesW64"); fnSymSetOptions = (SYMSETOPTIONS)GetProcAddress (hDbgHelp, "SymSetOptions"); fnSymInitialize = (SYMINITIALIZE)GetProcAddress (hDbgHelp, "SymInitialize"); fnSymFunctionTableAccess64 = (SYMFUNCTIONTABLEACCESS64)GetProcAddress (hDbgHelp, "SymFunctionTableAccess64"); fnSymGetModuleBase64 = (SYMGETMODULEBASE64)GetProcAddress (hDbgHelp, "SymGetModuleBase64"); fnStackWalk64 = (STACKWALK64)GetProcAddress (hDbgHelp, "StackWalk64"); fnSymFromAddr = (SYMFROMADDR)GetProcAddress (hDbgHelp, "SymFromAddrW"); fnSymCleanup = (SYMCLEANUP)GetProcAddress (hDbgHelp, "SymCleanup"); fnSymGetModuleInfo64 = (SYMGETMODULEINFO64)GetProcAddress (hDbgHelp, "SymGetModuleInfo64"); fnMiniDumpWriteDump = (MINIDUMPWRITEDUMP)GetProcAddress (hDbgHelp, "MiniDumpWriteDump"); if (!fnEnumerateLoadedModules64 || !fnSymSetOptions || !fnSymInitialize || !fnSymFunctionTableAccess64 || !fnSymGetModuleBase64 || !fnStackWalk64 || !fnSymFromAddr || !fnSymCleanup || !fnSymGetModuleInfo64) { FreeLibrary (hDbgHelp); return EXCEPTION_CONTINUE_SEARCH; } hProcess = GetCurrentProcess(); fnSymSetOptions (SYMOPT_UNDNAME | SYMOPT_FAIL_CRITICAL_ERRORS | SYMOPT_LOAD_ANYTHING); GetModuleFileName (NULL, searchPath, _countof(searchPath)-1); p = srchr (searchPath, '\\'); if (p) *p = 0; //create a log file GetSystemTime (&timeInfo); for (i = 1;;) { tsprintf_s (logPath, _countof(logPath)-1, TEXT("%s\\crashDumps\\OBSCrashLog%.4d-%.2d-%.2d_%d.txt"), lpAppDataPath, timeInfo.wYear, timeInfo.wMonth, timeInfo.wDay, i); if (GetFileAttributes(logPath) == INVALID_FILE_ATTRIBUTES) break; i++; } XFile crashDumpLog; if (!crashDumpLog.Open(logPath, XFILE_WRITE, XFILE_CREATENEW)) { FreeLibrary (hDbgHelp); return EXCEPTION_CONTINUE_SEARCH; } //initialize debug symbols fnSymInitialize (hProcess, NULL, TRUE); #ifdef _WIN64 InstructionPtr = context.Rip; frame.AddrPC.Offset = InstructionPtr; frame.AddrFrame.Offset = context.Rbp; frame.AddrStack.Offset = context.Rsp; imageType = IMAGE_FILE_MACHINE_AMD64; #else InstructionPtr = context.Eip; frame.AddrPC.Offset = InstructionPtr; frame.AddrFrame.Offset = context.Ebp; frame.AddrStack.Offset = context.Esp; imageType = IMAGE_FILE_MACHINE_I386; #endif frame.AddrFrame.Mode = AddrModeFlat; frame.AddrPC.Mode = AddrModeFlat; frame.AddrStack.Mode = AddrModeFlat; symInfo = (SYMBOL_INFO *)LocalAlloc (LPTR, sizeof(*symInfo) + 256); symInfo->SizeOfStruct = sizeof(SYMBOL_INFO); symInfo->MaxNameLen = 256; fnOffset = 0; //get os info memset (&osInfo, 0, sizeof(osInfo)); osInfo.dwOSVersionInfoSize = sizeof(OSVERSIONINFOEX); if (!GetVersionEx ((OSVERSIONINFO *)&osInfo)) { osInfo.dwOSVersionInfoSize = sizeof(OSVERSIONINFO); GetVersionEx ((OSVERSIONINFO *)&osInfo); } String cpuInfo; HKEY key; // get cpu info if(RegOpenKey(HKEY_LOCAL_MACHINE, TEXT("HARDWARE\\DESCRIPTION\\System\\CentralProcessor\\0"), &key) == ERROR_SUCCESS) { DWORD dwSize = 1024; cpuInfo.SetLength(dwSize); if (RegQueryValueEx(key, TEXT("ProcessorNameString"), NULL, NULL, (LPBYTE)cpuInfo.Array(), &dwSize) != ERROR_SUCCESS) cpuInfo = TEXT("<unable to query>"); RegCloseKey(key); } else cpuInfo = TEXT("<unable to query>"); //determine which module the crash occured in scpy (moduleInfo.moduleName, TEXT("<unknown>")); moduleInfo.faultAddress = InstructionPtr; fnEnumerateLoadedModules64 (hProcess, (PENUMLOADED_MODULES_CALLBACK64)EnumerateLoadedModulesProcInfo, (VOID *)&moduleInfo); slwr (moduleInfo.moduleName); BOOL isPlugin = FALSE; if (sstr (moduleInfo.moduleName, TEXT("plugins\\"))) isPlugin = TRUE; String strModuleInfo; String crashMessage; fnEnumerateLoadedModules64(hProcess, (PENUMLOADED_MODULES_CALLBACK64)RecordAllLoadedModules, (VOID *)&strModuleInfo); crashMessage << TEXT("OBS has encountered an unhandled exception and has terminated. If you are able to\r\n") TEXT("reproduce this crash, please submit this crash report on the forums at\r\n") TEXT("http://www.obsproject.com/ - include the contents of this crash log and the\r\n") TEXT("minidump .dmp file (if available) as well as your regular OBS log files and\r\n") TEXT("a description of what you were doing at the time of the crash.\r\n") TEXT("\r\n") TEXT("This crash appears to have occured in the '") << moduleInfo.moduleName << TEXT("' module.\r\n\r\n"); crashDumpLog.WriteStr(crashMessage.Array()); crashDumpLog.WriteStr(FormattedString(TEXT("**** UNHANDLED EXCEPTION: %x\r\nFault address: %I64p (%s)\r\n"), exceptionInfo->ExceptionRecord->ExceptionCode, InstructionPtr, moduleInfo.moduleName)); crashDumpLog.WriteStr(TEXT("OBS version: ") OBS_VERSION_STRING TEXT("\r\n")); crashDumpLog.WriteStr(FormattedString(TEXT("Windows version: %d.%d (Build %d) %s\r\nCPU: %s\r\n\r\n"), osInfo.dwMajorVersion, osInfo.dwMinorVersion, osInfo.dwBuildNumber, osInfo.szCSDVersion, cpuInfo.Array())); crashDumpLog.WriteStr(TEXT("Crashing thread stack trace:\r\n")); #ifdef _WIN64 crashDumpLog.WriteStr(TEXT("Stack EIP Arg0 Arg1 Arg2 Arg3 Address\r\n")); #else crashDumpLog.WriteStr(TEXT("Stack EIP Arg0 Arg1 Arg2 Arg3 Address\r\n")); #endif crashDumpLog.FlushFileBuffers(); while (fnStackWalk64 (imageType, hProcess, GetCurrentThread(), &frame, &context, NULL, (PFUNCTION_TABLE_ACCESS_ROUTINE64)fnSymFunctionTableAccess64, (PGET_MODULE_BASE_ROUTINE64)fnSymGetModuleBase64, NULL)) { scpy (moduleInfo.moduleName, TEXT("<unknown>")); moduleInfo.faultAddress = frame.AddrPC.Offset; fnEnumerateLoadedModules64 (hProcess, (PENUMLOADED_MODULES_CALLBACK64)EnumerateLoadedModulesProcInfo, (VOID *)&moduleInfo); slwr (moduleInfo.moduleName); p = srchr (moduleInfo.moduleName, '\\'); if (p) p++; else p = moduleInfo.moduleName; #ifdef _WIN64 if (fnSymFromAddr (hProcess, frame.AddrPC.Offset, &fnOffset, symInfo) && !(symInfo->Flags & SYMFLAG_EXPORT)) { crashDumpLog.WriteStr(FormattedString(TEXT("%016I64X %016I64X %016I64X %016I64X %016I64X %016I64X %s!%s+0x%I64x\r\n"), frame.AddrStack.Offset, frame.AddrPC.Offset, frame.Params[0], frame.Params[1], frame.Params[2], frame.Params[3], p, symInfo->Name, fnOffset)); } else { crashDumpLog.WriteStr(FormattedString(TEXT("%016I64X %016I64X %016I64X %016I64X %016I64X %016I64X %s!0x%I64x\r\n"), frame.AddrStack.Offset, frame.AddrPC.Offset, frame.Params[0], frame.Params[1], frame.Params[2], frame.Params[3], p, frame.AddrPC.Offset)); } #else if (fnSymFromAddr (hProcess, frame.AddrPC.Offset, &fnOffset, symInfo) && !(symInfo->Flags & SYMFLAG_EXPORT)) { crashDumpLog.WriteStr(FormattedString(TEXT("%08.8I64X %08.8I64X %08.8X %08.8X %08.8X %08.8X %s!%s+0x%I64x\r\n"), frame.AddrStack.Offset, frame.AddrPC.Offset, (DWORD)frame.Params[0], (DWORD)frame.Params[1], (DWORD)frame.Params[2], (DWORD)frame.Params[3], p, symInfo->Name, fnOffset)); } else { crashDumpLog.WriteStr(FormattedString(TEXT("%08.8I64X %08.8I64X %08.8X %08.8X %08.8X %08.8X %s!0x%I64x\r\n"), frame.AddrStack.Offset, frame.AddrPC.Offset, (DWORD)frame.Params[0], (DWORD)frame.Params[1], (DWORD)frame.Params[2], (DWORD)frame.Params[3], p, frame.AddrPC.Offset )); } #endif crashDumpLog.FlushFileBuffers(); } //if we manually crashed due to a deadlocked thread, record some extra info if (exceptionInfo->ExceptionRecord->ExceptionCode == EXCEPTION_BREAKPOINT) { HANDLE hVideoThread = NULL, hEncodeThread = NULL; App->GetThreadHandles (&hVideoThread, &hEncodeThread); if (hVideoThread) { crashDumpLog.WriteStr(TEXT("\r\nVideo thread stack trace:\r\n")); #ifdef _WIN64 crashDumpLog.WriteStr(TEXT("Stack EIP Arg0 Arg1 Arg2 Arg3 Address\r\n")); #else crashDumpLog.WriteStr(TEXT("Stack EIP Arg0 Arg1 Arg2 Arg3 Address\r\n")); #endif crashDumpLog.FlushFileBuffers(); context.ContextFlags = CONTEXT_ALL; GetThreadContext (hVideoThread, &context); ZeroMemory (&frame, sizeof(frame)); #ifdef _WIN64 InstructionPtr = context.Rip; frame.AddrPC.Offset = InstructionPtr; frame.AddrFrame.Offset = context.Rbp; frame.AddrStack.Offset = context.Rsp; imageType = IMAGE_FILE_MACHINE_AMD64; #else InstructionPtr = context.Eip; frame.AddrPC.Offset = InstructionPtr; frame.AddrFrame.Offset = context.Ebp; frame.AddrStack.Offset = context.Esp; imageType = IMAGE_FILE_MACHINE_I386; #endif frame.AddrFrame.Mode = AddrModeFlat; frame.AddrPC.Mode = AddrModeFlat; frame.AddrStack.Mode = AddrModeFlat; while (fnStackWalk64 (imageType, hProcess, hVideoThread, &frame, &context, NULL, (PFUNCTION_TABLE_ACCESS_ROUTINE64)fnSymFunctionTableAccess64, (PGET_MODULE_BASE_ROUTINE64)fnSymGetModuleBase64, NULL)) { scpy (moduleInfo.moduleName, TEXT("<unknown>")); moduleInfo.faultAddress = frame.AddrPC.Offset; fnEnumerateLoadedModules64 (hProcess, (PENUMLOADED_MODULES_CALLBACK64)EnumerateLoadedModulesProcInfo, (VOID *)&moduleInfo); slwr (moduleInfo.moduleName); p = srchr (moduleInfo.moduleName, '\\'); if (p) p++; else p = moduleInfo.moduleName; #ifdef _WIN64 if (fnSymFromAddr (hProcess, frame.AddrPC.Offset, &fnOffset, symInfo) && !(symInfo->Flags & SYMFLAG_EXPORT)) { crashDumpLog.WriteStr(FormattedString(TEXT("%016I64X %016I64X %016I64X %016I64X %016I64X %016I64X %s!%s+0x%I64x\r\n"), frame.AddrStack.Offset, frame.AddrPC.Offset, frame.Params[0], frame.Params[1], frame.Params[2], frame.Params[3], p, symInfo->Name, fnOffset)); } else { crashDumpLog.WriteStr(FormattedString(TEXT("%016I64X %016I64X %016I64X %016I64X %016I64X %016I64X %s!0x%I64x\r\n"), frame.AddrStack.Offset, frame.AddrPC.Offset, frame.Params[0], frame.Params[1], frame.Params[2], frame.Params[3], p, frame.AddrPC.Offset)); } #else if (fnSymFromAddr (hProcess, frame.AddrPC.Offset, &fnOffset, symInfo) && !(symInfo->Flags & SYMFLAG_EXPORT)) { crashDumpLog.WriteStr(FormattedString(TEXT("%08.8I64X %08.8I64X %08.8X %08.8X %08.8X %08.8X %s!%s+0x%I64x\r\n"), frame.AddrStack.Offset, frame.AddrPC.Offset, (DWORD)frame.Params[0], (DWORD)frame.Params[1], (DWORD)frame.Params[2], (DWORD)frame.Params[3], p, symInfo->Name, fnOffset)); } else { crashDumpLog.WriteStr(FormattedString(TEXT("%08.8I64X %08.8I64X %08.8X %08.8X %08.8X %08.8X %s!0x%I64x\r\n"), frame.AddrStack.Offset, frame.AddrPC.Offset, (DWORD)frame.Params[0], (DWORD)frame.Params[1], (DWORD)frame.Params[2], (DWORD)frame.Params[3], p, frame.AddrPC.Offset )); } #endif crashDumpLog.FlushFileBuffers(); } } if (hEncodeThread) { crashDumpLog.WriteStr(TEXT("\r\nEncode thread stack trace:\r\n")); #ifdef _WIN64 crashDumpLog.WriteStr(TEXT("Stack EIP Arg0 Arg1 Arg2 Arg3 Address\r\n")); #else crashDumpLog.WriteStr(TEXT("Stack EIP Arg0 Arg1 Arg2 Arg3 Address\r\n")); #endif crashDumpLog.FlushFileBuffers(); context.ContextFlags = CONTEXT_ALL; GetThreadContext (hEncodeThread, &context); ZeroMemory (&frame, sizeof(frame)); #ifdef _WIN64 InstructionPtr = context.Rip; frame.AddrPC.Offset = InstructionPtr; frame.AddrFrame.Offset = context.Rbp; frame.AddrStack.Offset = context.Rsp; imageType = IMAGE_FILE_MACHINE_AMD64; #else InstructionPtr = context.Eip; frame.AddrPC.Offset = InstructionPtr; frame.AddrFrame.Offset = context.Ebp; frame.AddrStack.Offset = context.Esp; imageType = IMAGE_FILE_MACHINE_I386; #endif frame.AddrFrame.Mode = AddrModeFlat; frame.AddrPC.Mode = AddrModeFlat; frame.AddrStack.Mode = AddrModeFlat; while (fnStackWalk64 (imageType, hProcess, hEncodeThread, &frame, &context, NULL, (PFUNCTION_TABLE_ACCESS_ROUTINE64)fnSymFunctionTableAccess64, (PGET_MODULE_BASE_ROUTINE64)fnSymGetModuleBase64, NULL)) { scpy (moduleInfo.moduleName, TEXT("<unknown>")); moduleInfo.faultAddress = frame.AddrPC.Offset; fnEnumerateLoadedModules64 (hProcess, (PENUMLOADED_MODULES_CALLBACK64)EnumerateLoadedModulesProcInfo, (VOID *)&moduleInfo); slwr (moduleInfo.moduleName); p = srchr (moduleInfo.moduleName, '\\'); if (p) p++; else p = moduleInfo.moduleName; #ifdef _WIN64 if (fnSymFromAddr (hProcess, frame.AddrPC.Offset, &fnOffset, symInfo) && !(symInfo->Flags & SYMFLAG_EXPORT)) { crashDumpLog.WriteStr(FormattedString(TEXT("%016I64X %016I64X %016I64X %016I64X %016I64X %016I64X %s!%s+0x%I64x\r\n"), frame.AddrStack.Offset, frame.AddrPC.Offset, frame.Params[0], frame.Params[1], frame.Params[2], frame.Params[3], p, symInfo->Name, fnOffset)); } else { crashDumpLog.WriteStr(FormattedString(TEXT("%016I64X %016I64X %016I64X %016I64X %016I64X %016I64X %s!0x%I64x\r\n"), frame.AddrStack.Offset, frame.AddrPC.Offset, frame.Params[0], frame.Params[1], frame.Params[2], frame.Params[3], p, frame.AddrPC.Offset)); } #else if (fnSymFromAddr (hProcess, frame.AddrPC.Offset, &fnOffset, symInfo) && !(symInfo->Flags & SYMFLAG_EXPORT)) { crashDumpLog.WriteStr(FormattedString(TEXT("%08.8I64X %08.8I64X %08.8X %08.8X %08.8X %08.8X %s!%s+0x%I64x\r\n"), frame.AddrStack.Offset, frame.AddrPC.Offset, (DWORD)frame.Params[0], (DWORD)frame.Params[1], (DWORD)frame.Params[2], (DWORD)frame.Params[3], p, symInfo->Name, fnOffset)); } else { crashDumpLog.WriteStr(FormattedString(TEXT("%08.8I64X %08.8I64X %08.8X %08.8X %08.8X %08.8X %s!0x%I64x\r\n"), frame.AddrStack.Offset, frame.AddrPC.Offset, (DWORD)frame.Params[0], (DWORD)frame.Params[1], (DWORD)frame.Params[2], (DWORD)frame.Params[3], p, frame.AddrPC.Offset )); } #endif crashDumpLog.FlushFileBuffers(); } } } //generate a minidump if possible if (fnMiniDumpWriteDump) { TCHAR dumpPath[MAX_PATH]; HANDLE hFile; tsprintf_s (dumpPath, _countof(dumpPath)-1, TEXT("%s\\crashDumps\\OBSCrashDump%.4d-%.2d-%.2d_%d.dmp"), lpAppDataPath, timeInfo.wYear, timeInfo.wMonth, timeInfo.wDay, i); hFile = CreateFile (dumpPath, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL); if (hFile != INVALID_HANDLE_VALUE) { MINIDUMP_TYPE dumpFlags = (MINIDUMP_TYPE)(MiniDumpWithIndirectlyReferencedMemory | MiniDumpWithUnloadedModules | MiniDumpWithProcessThreadData); miniInfo.ClientPointers = TRUE; miniInfo.ExceptionPointers = exceptionInfo; miniInfo.ThreadId = GetCurrentThreadId (); if (fnMiniDumpWriteDump (hProcess, GetCurrentProcessId(), hFile, dumpFlags, &miniInfo, NULL, NULL)) { crashDumpLog.WriteStr(FormattedString(TEXT("\r\nA minidump was saved to %s.\r\nPlease include this file when posting a crash report.\r\n"), dumpPath)); } else { CloseHandle (hFile); DeleteFile (dumpPath); } } } else { crashDumpLog.WriteStr(TEXT("\r\nA minidump could not be created. Please check dbghelp.dll is present.\r\n")); } crashDumpLog.WriteStr("\r\nList of loaded modules:\r\n"); #ifdef _WIN64 crashDumpLog.WriteStr("Base Address Module\r\n"); #else crashDumpLog.WriteStr("Base Address Module\r\n"); #endif crashDumpLog.WriteStr(strModuleInfo); crashDumpLog.Close(); LocalFree (symInfo); fnSymCleanup (hProcess); if (OBSMessageBox(hwndMain, TEXT("Woops! OBS has crashed. Would you like to view a crash report?"), NULL, MB_ICONERROR | MB_YESNO) == IDYES) ShellExecute(NULL, NULL, logPath, NULL, searchPath, SW_SHOWDEFAULT); FreeLibrary (hDbgHelp); //we really shouldn't be returning here, if we're at the bottom of the VEH chain this is a pretty legitimate crash //and if we return we could end up invoking a second crash handler or other weird / annoying things //ExitProcess(exceptionInfo->ExceptionRecord->ExceptionCode); return EXCEPTION_CONTINUE_SEARCH; }
/* Create and initialize a URI. This accepts full URIs with schemes (http:) and partial URLs Support IPv4 and [IPv6]. Supported forms: SCHEME://[::]:PORT/URI SCHEME://HOST:PORT/URI [::]:PORT/URI :PORT/URI HOST:PORT/URI PORT/URI /URI URI NOTE: HOST/URI is not supported and requires a scheme prefix. This is because it is ambiguous with a relative uri path. Missing fields are null or zero. */ PUBLIC HttpUri *httpCreateUri(cchar *uri, int flags) { HttpUri *up; char *tok, *next; if ((up = mprAllocObj(HttpUri, manageUri)) == 0) { return 0; } tok = sclone(uri); /* [scheme://][hostname[:port]][/path[.ext]][#ref][?query] First trim query and then reference from the end */ if ((next = schr(tok, '?')) != 0) { *next++ = '\0'; up->query = sclone(next); } if ((next = schr(tok, '#')) != 0) { *next++ = '\0'; up->reference = sclone(next); } /* [scheme://][hostname[:port]][/path] */ if ((next = scontains(tok, "://")) != 0) { up->scheme = snclone(tok, (next - tok)); if (smatch(up->scheme, "http")) { if (flags & HTTP_COMPLETE_URI) { up->port = 80; } } else if (smatch(up->scheme, "ws")) { if (flags & HTTP_COMPLETE_URI) { up->port = 80; } up->webSockets = 1; } else if (smatch(up->scheme, "https")) { if (flags & HTTP_COMPLETE_URI) { up->port = 443; } up->secure = 1; } else if (smatch(up->scheme, "wss")) { if (flags & HTTP_COMPLETE_URI) { up->port = 443; } up->secure = 1; up->webSockets = 1; } tok = &next[3]; } /* [hostname[:port]][/path] */ if (*tok == '[' && ((next = strchr(tok, ']')) != 0)) { /* IPv6 [::]:port/uri */ up->host = snclone(&tok[1], (next - tok) - 1); tok = ++next; } else if (*tok && *tok != '/' && *tok != ':' && (up->scheme || strchr(tok, ':'))) { /* Supported forms: scheme://hostname hostname:port */ if ((next = spbrk(tok, ":/")) == 0) { next = &tok[slen(tok)]; } up->host = snclone(tok, next - tok); tok = next; } assert(tok); /* [:port][/path] */ if (*tok == ':') { up->port = atoi(++tok); if ((tok = schr(tok, '/')) == 0) { tok = ""; } } assert(tok); /* [/path] */ if (*tok) { up->path = sclone(tok); /* path[.ext[/extra]] */ if ((tok = srchr(up->path, '.')) != 0) { if (tok[1]) { if ((next = srchr(up->path, '/')) != 0) { if (next < tok) { up->ext = sclone(++tok); } } else { up->ext = sclone(++tok); } } } } if (flags & (HTTP_COMPLETE_URI | HTTP_COMPLETE_URI_PATH)) { if (up->path == 0 || *up->path == '\0') { up->path = sclone("/"); } } up->secure = smatch(up->scheme, "https") || smatch(up->scheme, "wss"); up->webSockets = (smatch(up->scheme, "ws") || smatch(up->scheme, "wss")); if (flags & HTTP_COMPLETE_URI) { if (!up->scheme) { up->scheme = sclone("http"); } if (!up->host) { up->host = sclone("localhost"); } if (!up->port) { up->port = up->secure ? 443 : 80; } } up->valid = httpValidUriChars(uri); return up; }
/* Create and initialize a URI. This accepts full URIs with schemes (http:) and partial URLs */ PUBLIC HttpUri *httpCreateUriFromParts(cchar *scheme, cchar *host, int port, cchar *path, cchar *reference, cchar *query, int flags) { HttpUri *up; char *cp, *tok; if ((up = mprAllocObj(HttpUri, manageUri)) == 0) { up->valid = 0; return 0; } if (!httpValidUriChars(scheme) || !httpValidUriChars(host) || !httpValidUriChars(path) || !httpValidUriChars(reference) || !httpValidUriChars(query)) { up->valid = 0; return up; } if (scheme) { up->scheme = sclone(scheme); up->secure = (smatch(up->scheme, "https") || smatch(up->scheme, "wss")); up->webSockets = (smatch(up->scheme, "ws") || smatch(up->scheme, "wss")); } else if (flags & HTTP_COMPLETE_URI) { up->scheme = "http"; } if (host) { if (*host == '[' && ((cp = strchr(host, ']')) != 0)) { up->host = snclone(&host[1], (cp - host) - 2); if ((cp = schr(++cp, ':')) && port == 0) { port = (int) stoi(++cp); } } else { up->host = sclone(host); if ((cp = schr(up->host, ':')) && port == 0) { port = (int) stoi(++cp); } } } else if (flags & HTTP_COMPLETE_URI) { up->host = sclone("localhost"); } if (port) { up->port = port; } if (path) { while (path[0] == '/' && path[1] == '/') { path++; } up->path = sclone(path); } if (flags & (HTTP_COMPLETE_URI | HTTP_COMPLETE_URI_PATH)) { if (up->path == 0 || *up->path == '\0') { up->path = sclone("/"); } } if (reference) { up->reference = sclone(reference); } if (query) { up->query = sclone(query); } if ((tok = srchr(up->path, '.')) != 0) { if ((cp = srchr(up->path, '/')) != 0) { if (cp <= tok) { up->ext = sclone(&tok[1]); } } else { up->ext = sclone(&tok[1]); } } up->valid = 1; return up; }
DWORD WINAPI CheckUpdateThread (VOID *arg) { int responseCode; TCHAR extraHeaders[256]; BYTE manifestHash[20]; TCHAR manifestPath[MAX_PATH]; tsprintf_s (manifestPath, _countof(manifestPath)-1, TEXT("%s\\updates\\packages.xconfig"), lpAppDataPath); if (!CryptAcquireContext(&hProvider, NULL, NULL, PROV_RSA_FULL, CRYPT_VERIFYCONTEXT)) { Log (TEXT("Updater: CryptAcquireContext failed: %08x"), GetLastError()); return 1; } extraHeaders[0] = 0; if (CalculateFileHash(manifestPath, manifestHash)) { TCHAR hashString[41]; HashToString(manifestHash, hashString); tsprintf_s (extraHeaders, _countof(extraHeaders)-1, TEXT("If-None-Match: %s"), hashString); } //this is an arbitrary random number that we use to count the number of unique OBS installations //and is not associated with any kind of identifiable information String strGUID = GlobalConfig->GetString(TEXT("General"), TEXT("InstallGUID")); if (strGUID.IsEmpty()) { GenerateGUID(strGUID); if (strGUID.IsValid()) GlobalConfig->SetString(TEXT("General"), TEXT("InstallGUID"), strGUID); } if (strGUID.IsValid()) { if (extraHeaders[0]) scat(extraHeaders, TEXT("\n")); scat(extraHeaders, TEXT("X-OBS-GUID: ")); scat(extraHeaders, strGUID); } if (HTTPGetFile(TEXT("https://obsproject.com/update/packages.xconfig"), manifestPath, extraHeaders, &responseCode)) { if (responseCode == 200 || responseCode == 304) { String updateInfo; BOOL updatesAvailable; updateInfo = Str("Updater.NewUpdates"); if (ParseUpdateManifest(manifestPath, &updatesAvailable, updateInfo)) { if (updatesAvailable) { updateInfo << TEXT("\r\n") << Str("Updater.DownloadNow"); if (MessageBox (NULL, updateInfo.Array(), Str("Updater.UpdatesAvailable"), MB_ICONQUESTION|MB_YESNO) == IDYES) { if (App->IsRunning()) { if (MessageBox (NULL, Str("Updater.RunningWarning"), NULL, MB_ICONEXCLAMATION|MB_YESNO) == IDNO) goto abortUpdate; } TCHAR updateFilePath[MAX_PATH]; TCHAR cwd[MAX_PATH]; GetModuleFileName(NULL, cwd, _countof(cwd)-1); TCHAR *p = srchr(cwd, '\\'); if (p) *p = 0; tsprintf_s (updateFilePath, _countof(updateFilePath)-1, TEXT("%s\\updates\\updater.exe"), lpAppDataPath); //note, can't use CreateProcess to launch as admin. SHELLEXECUTEINFO execInfo; zero(&execInfo, sizeof(execInfo)); execInfo.cbSize = sizeof(execInfo); execInfo.lpFile = updateFilePath; #ifndef _WIN64 execInfo.lpParameters = TEXT("Win32"); #else execInfo.lpParameters = TEXT("Win64"); #endif execInfo.lpDirectory = cwd; execInfo.nShow = SW_SHOWNORMAL; if (!ShellExecuteEx (&execInfo)) { AppWarning(TEXT("Can't launch updater '%s': %d"), updateFilePath, GetLastError()); goto abortUpdate; } //force OBS to perform another update check immediately after updating in case of issues //with the new version GlobalConfig->SetInt(TEXT("General"), TEXT("LastUpdateCheck"), 0); //since we're in a separate thread we can't just PostQuitMessage ourselves SendMessage(hwndMain, WM_CLOSE, 0, 0); } } } } } abortUpdate: CryptReleaseContext(hProvider, 0); return 0; }
void GraphicsCaptureSource::AttemptCapture() { OSDebugOut(TEXT("attempting to capture..\n")); if (scmpi(strWindowClass, L"dwm") == 0) { hwndTarget = FindWindow(strWindowClass, NULL); } else { FindWindowData fwd; //FIXME: duplicated code, but we need OpenProcess here char pOPStr[12]; mcpy(pOPStr, "NpflUvhel{x", 12); //OpenProcess obfuscated for (int i = 0; i<11; i++) pOPStr[i] ^= i ^ 1; fwd.pOpenProcess = (OPPROC)GetProcAddress(GetModuleHandle(TEXT("KERNEL32")), pOPStr); fwd.classname = strWindowClass; fwd.exename = strExecutable; fwd.hwnd = nullptr; EnumWindows(GraphicsCaptureFindWindow, (LPARAM)&fwd); hwndTarget = fwd.hwnd; } // use foregroundwindow as fallback (should be NULL if not using hotkey capture) if (!hwndTarget) hwndTarget = hwndNextTarget; hwndNextTarget = nullptr; OSDebugOut(L"Window: %s: ", strWindowClass.Array()); if (hwndTarget) { OSDebugOut(L"Valid window\n"); targetThreadID = GetWindowThreadProcessId(hwndTarget, &targetProcessID); if (!targetThreadID || !targetProcessID) { AppWarning(TEXT("GraphicsCaptureSource::AttemptCapture: GetWindowThreadProcessId failed, GetLastError = %u"), GetLastError()); bErrorAcquiring = true; return; } } else { OSDebugOut(L"Bad window\n"); if (!bUseHotkey && !warningID) { //Log(TEXT("GraphicsCaptureSource::AttemptCapture: Window '%s' [%s] not found."), strWindowClass.Array(), strExecutable.Array()); //warningID = API->AddStreamInfo(Str("Sources.SoftwareCaptureSource.WindowNotFound"), StreamInfoPriority_High); } bCapturing = false; return; } if (injectHelperProcess && WaitForSingleObject(injectHelperProcess, 0) == WAIT_TIMEOUT) return; if(warningID) { //API->RemoveStreamInfo(warningID); warningID = 0; } //------------------------------------------- // see if we already hooked the process. if not, inject DLL char pOPStr[12]; mcpy(pOPStr, "NpflUvhel{x", 12); //OpenProcess obfuscated for (int i=0; i<11; i++) pOPStr[i] ^= i^1; OPPROC pOpenProcess = (OPPROC)GetProcAddress(GetModuleHandle(TEXT("KERNEL32")), pOPStr); DWORD permission = useSafeHook ? (PROCESS_QUERY_INFORMATION | PROCESS_VM_READ) : (PROCESS_ALL_ACCESS); HANDLE hProcess = (*pOpenProcess)(permission, FALSE, targetProcessID); if(hProcess) { DWORD dwSize = MAX_PATH; wchar_t processName[MAX_PATH]; memset(processName, 0, sizeof(processName)); QueryFullProcessImageName(hProcess, 0, processName, &dwSize); if (dwSize != 0 && scmpi(processName, lastProcessName) != 0) { if (processName[0]) { wchar_t *fileName = srchr(processName, '\\'); Log(L"Trying to hook process: %s", (fileName ? fileName+1 : processName)); } scpy_n(lastProcessName, processName, MAX_PATH-1); } //------------------------------------------- // load keepalive event hOBSIsAlive = CreateEvent(NULL, FALSE, FALSE, String() << OBS_KEEPALIVE_EVENT << UINT(targetProcessID)); //------------------------------------------- hwndCapture = hwndTarget; hSignalRestart = OpenEvent(EVENT_ALL_ACCESS, FALSE, String() << RESTART_CAPTURE_EVENT << UINT(targetProcessID)); if(hSignalRestart) { OSDebugOut(L"Setting signal for process ID %u\n", targetProcessID); SetEvent(hSignalRestart); bCapturing = true; captureWaitCount = 0; } else { BOOL bSameBit = TRUE; BOOL b32bit = TRUE; if (Is64BitWindows()) { BOOL bCurrentProcessWow64, bTargetProcessWow64; IsWow64Process(GetCurrentProcess(), &bCurrentProcessWow64); IsWow64Process(hProcess, &bTargetProcessWow64); bSameBit = (bCurrentProcessWow64 == bTargetProcessWow64); } if(Is64BitWindows()) IsWow64Process(hProcess, &b32bit); //verify the hook DLL is accessible String strDLL; DWORD dwDirSize = GetCurrentDirectory(0, NULL); strDLL.SetLength(dwDirSize); GetCurrentDirectory(dwDirSize, strDLL); strDLL << TEXT("\\plugins\\GraphicsCapture\\GraphicsCaptureHook"); if (!b32bit) strDLL << TEXT("64"); strDLL << TEXT(".dll"); if (!CheckFileIntegrity(strDLL.Array())) { OSDebugOut(L"Error acquiring\n"); bErrorAcquiring = true; } else { if (bSameBit && !useSafeHook) { if (InjectLibrary(hProcess, strDLL)) { captureWaitCount = 0; OSDebugOut(L"Inject successful\n"); bCapturing = true; } else { AppWarning(TEXT("GraphicsCaptureSource::AttemptCapture: Failed to inject library, GetLastError = %u"), GetLastError()); bErrorAcquiring = true; } } else { String strDLLPath; DWORD dwDirSize = GetCurrentDirectory(0, NULL); strDLLPath.SetLength(dwDirSize); GetCurrentDirectory(dwDirSize, strDLLPath); strDLLPath << TEXT("\\plugins\\GraphicsCapture"); String strHelper = strDLLPath; strHelper << ((b32bit) ? TEXT("\\injectHelper.exe") : TEXT("\\injectHelper64.exe")); if (!CheckFileIntegrity(strHelper.Array())) { bErrorAcquiring = true; } else { String strCommandLine; strCommandLine << TEXT("\"") << strHelper << TEXT("\" "); if (useSafeHook) strCommandLine << UIntString(targetThreadID) << " 1"; else strCommandLine << UIntString(targetProcessID) << " 0"; //--------------------------------------- PROCESS_INFORMATION pi; STARTUPINFO si; zero(&pi, sizeof(pi)); zero(&si, sizeof(si)); si.cb = sizeof(si); if (CreateProcess(strHelper, strCommandLine, NULL, NULL, FALSE, 0, NULL, strDLLPath, &si, &pi)) { int exitCode = 0; CloseHandle(pi.hThread); if (!useSafeHook) { WaitForSingleObject(pi.hProcess, INFINITE); GetExitCodeProcess(pi.hProcess, (DWORD*)&exitCode); CloseHandle(pi.hProcess); } else { injectHelperProcess = pi.hProcess; } if (exitCode == 0) { captureWaitCount = 0; bCapturing = true; } else { AppWarning(TEXT("GraphicsCaptureSource::AttemptCapture: Failed to inject library, error code = %d"), exitCode); bErrorAcquiring = true; } } else { AppWarning(TEXT("GraphicsCaptureSource::AttemptCapture: Could not create inject helper, GetLastError = %u"), GetLastError()); bErrorAcquiring = true; } } } } } //save a copy of the process handle which we injected into, this lets us check for process exit in Tick() if (!hTargetProcess) { if (!DuplicateHandle(GetCurrentProcess(), hProcess, GetCurrentProcess(), &hTargetProcess, 0, FALSE, DUPLICATE_SAME_ACCESS)) { Log(TEXT("Warning: Couldn't DuplicateHandle, %d"), GetLastError()); } } CloseHandle(hProcess); if (!bCapturing) { CloseHandle(hOBSIsAlive); hOBSIsAlive = NULL; } } else { AppWarning(TEXT("GraphicsCaptureSource::AttemptCapture: OpenProcess failed, GetLastError = %u"), GetLastError()); bErrorAcquiring = true; } }