OSFileChangeData * STDCALL OSMonitorFileStart(String path, bool suppressLogging) { HANDLE hDirectory; OSFileChangeData *data = (OSFileChangeData *)Allocate(sizeof(*data)); String strDirectory = path; strDirectory.FindReplace(TEXT("\\"), TEXT("/")); strDirectory = GetPathDirectory(strDirectory); strDirectory.FindReplace(TEXT("/"), TEXT("\\")); strDirectory << TEXT("\\"); scpy_n (data->strDirectory, strDirectory.Array(), _countof(data->strDirectory)-1); hDirectory = CreateFile(data->strDirectory, FILE_LIST_DIRECTORY, FILE_SHARE_READ|FILE_SHARE_WRITE|FILE_SHARE_DELETE, NULL, OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS|FILE_FLAG_OVERLAPPED, NULL); if(hDirectory != INVALID_HANDLE_VALUE) { DWORD test; zero(&data->directoryChange, sizeof(data->directoryChange)); data->directoryChange.hEvent = CreateEvent (NULL, TRUE, FALSE, NULL); if(ReadDirectoryChangesW(hDirectory, data->changeBuffer, 2048, FALSE, FILE_NOTIFY_CHANGE_FILE_NAME | FILE_NOTIFY_CHANGE_LAST_WRITE | FILE_NOTIFY_CHANGE_SIZE, &test, &data->directoryChange, NULL)) { scpy_n (data->targetFileName, path.Array(), _countof(data->targetFileName)-1); data->hDirectory = hDirectory; return data; } else { int err = GetLastError(); CloseHandle(data->directoryChange.hEvent); CloseHandle(hDirectory); if(!suppressLogging) Log(TEXT("OSMonitorFileStart: Unable to monitor file '%s', error %d"), path.Array(), err); Free(data); return NULL; } } else { if(!suppressLogging) { int err = GetLastError(); Log(TEXT("OSMonitorFileStart: Unable to open directory '%s', error %d"), data->strDirectory, err); } Free(data); return NULL; } }
void LocalizeMenu(HMENU hMenu, LocaleStringLookup *lookup) { if(!lookup) lookup = locale; int itemCount = GetMenuItemCount(hMenu); if(itemCount == -1) return; bool bRTL = LocaleIsRTL(lookup); for(int i=0; i<itemCount; i++) { MENUITEMINFO mii; zero(&mii, sizeof(mii)); mii.cbSize = sizeof(mii); mii.fMask = MIIM_SUBMENU|MIIM_STRING|MIIM_FTYPE; GetMenuItemInfo(hMenu, i, TRUE, &mii); if(mii.fType & MFT_SEPARATOR || mii.cch < 2) continue; HMENU hSubMenu = mii.hSubMenu; String strLookup; strLookup.SetLength(mii.cch); mii.fMask = MIIM_STRING; mii.dwTypeData = strLookup.Array(); mii.cch = strLookup.Length()+1; GetMenuItemInfo(hMenu, i, TRUE, &mii); String strName; if(strLookup[0] == '.') strName = strLookup.Array()+1; else if(!lookup->HasLookup(strLookup)) strName = strLookup; else strName = lookup->LookupString(strLookup); mii.fMask = MIIM_STRING|MIIM_FTYPE; mii.dwTypeData = strName.Array(); SetMenuItemInfo(hMenu, i, TRUE, &mii); if(hSubMenu) LocalizeMenu(hSubMenu); } }
void STDCALL TraceCrashEnd() { String strStackTrace = TEXT("\r\nException Fault - Stack Trace:"); for(unsigned int i=0; i<TraceFuncList.Num(); i++) { if(i) strStackTrace << TEXT(" -> "); if(!(i%10)) strStackTrace << TEXT("\r\n "); strStackTrace << TraceFuncList[i]; } if(TraceFuncList.Num() == MAX_STACK_TRACE) strStackTrace << TEXT(" -> ..."); String strOut = FormattedString(TEXT("%s\r\n"), strStackTrace.Array()); OpenLogFile(); LogFile.WriteAsUTF8(strOut, strOut.Length()); LogFile.WriteAsUTF8(TEXT("\r\n")); CloseLogFile(); OSMessageBox(TEXT("Error: Exception fault - More info in the log file.\r\n\r\nMake sure you're using the latest verison, otherwise send your log to [email protected]")); TraceFuncList.Clear(); CriticalExit(); }
void get_x264_log(void *param, int i_level, const char *psz, va_list argptr) { String chi; chi << TEXT("x264: ") << String(psz); chi.FindReplace(TEXT("%s"), TEXT("%S")); OSDebugOutva(chi, argptr); chi.FindReplace(TEXT("\r"), TEXT("")); chi.FindReplace(TEXT("\n"), TEXT("")); if (chi == TEXT("x264: OpenCL: fatal error, aborting encode") || chi == TEXT("x264: OpenCL: Invalid value.")) { if (App->IsRunning()) { // FIXME: currently due to the way OBS handles the stream report, if reconnect is enabled and this error happens // outside of the 30 second "no reconnect" window, no error dialog is shown to the user. usually x264 opencl errors // will happen immediately though. Log(TEXT("Aborting stream due to x264 opencl error")); App->SetStreamReport(TEXT("x264 OpenCL Error\r\n\r\nx264 encountered an error attempting to use OpenCL. This may be due to unsupported hardware or outdated drivers.\r\n\r\nIt is recommended that you remove opencl=true from your x264 advanced settings.")); PostMessage(hwndMain, OBS_REQUESTSTOP, 1, 0); } } Logva(chi.Array(), argptr); }
BOOL GraphicsCaptureSource::CheckFileIntegrity(LPCTSTR strDLL) { HANDLE hFileTest = CreateFile(strDLL, GENERIC_READ | GENERIC_EXECUTE, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, NULL); if (hFileTest == INVALID_HANDLE_VALUE) { String strWarning; DWORD err = GetLastError(); if (err == ERROR_FILE_NOT_FOUND) strWarning = TEXT("Important game capture files have been deleted. This is likely due to anti-virus software. Please make sure the OBS folder is excluded or ignored from any anti-virus / security software and re-install OBS."); else if (err == ERROR_ACCESS_DENIED) strWarning = TEXT("Important game capture files can not be loaded. This is likely due to anti-virus or security software. Please make sure the OBS folder is excluded / ignored from any anti-virus / security software."); else strWarning = FormattedString(TEXT("Important game capture files can not be loaded (error %d). This is likely due to anti-virus or security software. Please make sure the OBS folder is excluded / ignored from any anti-virus / security software."), err); Log(TEXT("GraphicsCaptureSource::CheckFileIntegrity: Error %d while accessing %s"), err, strDLL); //not sure if we should be using messagebox here, but probably better than "help why do i have black screen" OBSMessageBox(API->GetMainWindow(), strWarning.Array(), NULL, MB_ICONERROR | MB_OK); return FALSE; } else { CloseHandle(hFileTest); return TRUE; } }
void dumpData(int rootCallCount, int indent=0) { if(indent == 0) calculateProfileData(rootCallCount); String indentStr; for(int i=0; i<indent; i++) indentStr << TEXT("| "); CTSTR lpIndent = indent == 0 ? TEXT("") : indentStr.Array(); int perFrameCalls = numCalls/rootCallCount; float fTimeTaken = (float)MicroToMS(avgTimeElapsed); if(avgPercentage >= minPercentage && fTimeTaken >= minTime) { if(Children.Num()) Log(TEXT("%s%s - [%.3g%%] [avg time: %g ms] [avg calls per frame: %d] [children: %.3g%%] [unaccounted: %.3g%%]"), lpIndent, lpName, avgPercentage, fTimeTaken, perFrameCalls, childPercentage, unaccountedPercentage); else Log(TEXT("%s%s - [%.3g%%] [avg time: %g ms] [avg calls per frame: %d]"), lpIndent, lpName, avgPercentage, fTimeTaken, perFrameCalls); } for(unsigned int i=0; i<Children.Num(); i++) Children[i]->dumpData(rootCallCount, indent+1); }
void dumpData(int rootCallCount, int indent=0) { if(indent == 0) { rootCallCount = (int)floor(rootCallCount/(double)numParallelCalls+0.5); calculateProfileData(rootCallCount); } String indentStr; for(int i=0; i<indent; i++) indentStr << TEXT("| "); CTSTR lpIndent = indent == 0 ? TEXT("") : indentStr.Array(); int perFrameCalls = (int)floor(numCalls/(double)rootCallCount+0.5); float fTimeTaken = (float)MicroToMS(avgTimeElapsed); float cpuTime = (float)MicroToMS(avgCpuTime); float totalCpuTime = (float)cpuTimeElapsed*0.001f; if(avgPercentage >= minPercentage && fTimeTaken >= minTime) { if(Children.Num()) Log(TEXT("%s%s - [%.3g%%] [avg time: %g ms] [children: %.3g%%] [unaccounted: %.3g%%]"), lpIndent, lpName, avgPercentage, fTimeTaken, childPercentage, unaccountedPercentage); else Log(TEXT("%s%s - [%.3g%%] [avg time: %g ms]"), lpIndent, lpName, avgPercentage, fTimeTaken); } for(unsigned int i=0; i<Children.Num(); i++) Children[i].dumpData(rootCallCount, indent+1); }
String GetLVText(HWND hwndList, UINT id) { String strText; strText.SetLength(256); ListView_GetItemText(hwndList, id, 0, (LPWSTR)strText.Array(), 256); return strText; }
static DWORD STDCALL SaveReplayBufferThread(void *arg) { unique_ptr<ReplayBuffer::thread_param_t> param((ReplayBuffer::thread_param_t*)arg); String name = GetOutputFilename(!get<3>(*param)); unique_ptr<VideoFileStream> out(CreateFileStream(name)); if (!out) { Log(L"ReplayBuffer: Failed to create file stream for file name '%s'", name.Array()); return 1; } auto &packets = get<2>(*param); DWORD target_ts = get<0>(*param); DWORD stop_ts = -1; for (auto it = rbegin(packets); it != rend(packets); it++) { if (get<0>(**it) == PacketType_Audio) continue; DWORD ts = get<2>(**it); if (ts <= target_ts) break; stop_ts = ts; } bool signalled = false; auto signal = [&]() { if (signalled) return; SetEvent(get<1>(*param).get()); signalled = true; }; while (packets.size()) { auto &packet = packets.front(); if (get<2>(*packet) == stop_ts) break; auto &buf = get<3>(*packet); out->AddPacket(buf, get<1>(*packet), get<2>(*packet), get<0>(*packet)); if (buf->front() == 0x17) signal(); packets.pop_front(); } signal(); ReplayBuffer::SetLastFilename(name); return 0; }
String GetEditText(HWND hwndEdit) { String strText; strText.SetLength((UINT)SendMessage(hwndEdit, WM_GETTEXTLENGTH, 0, 0)); if(strText.Length()) SendMessage(hwndEdit, WM_GETTEXT, strText.Length()+1, (LPARAM)strText.Array()); return strText; }
VOID GenerateGUID(String &strGUID) { BYTE junk[20]; if (!CryptGenRandom(hProvider, sizeof(junk), junk)) return; strGUID.SetLength(41); HashToString(junk, strGUID.Array()); }
static void RefreshAspect(HWND hwnd, int cx, int cy) { int divisor = gcd(cx, cy); String aspect = Str("Settings.Video.AspectRatioFormat"); aspect.FindReplace(L"$1", UIntString(cx / divisor)); aspect.FindReplace(L"$2", UIntString(cy / divisor)); SetWindowText(GetDlgItem(hwnd, IDC_ASPECT), aspect.Array()); }
FuturePixelShader GraphicsSystem::CreatePixelShaderFromFileAsync(CTSTR fileName) { using namespace std; using Context = FutureShaderContainer::FutureShaderContext; wstring const fn = fileName; auto &cs = futureShaders.contexts; ScopedLock m(futureShaders.lock); bool initialized = cs.find(fn) != end(cs); Context &c = cs[fn]; if (!initialized) { c.readyEvent.reset(CreateEvent(nullptr, true, false, nullptr)); c.fileName = fn; c.thread.reset(OSCreateThread(static_cast<XTHREAD>([](void *arg) -> DWORD { Context &c = *(Context*)arg; XFile ShaderFile; if (!ShaderFile.Open(c.fileName.c_str(), XFILE_READ | XFILE_SHARED, XFILE_OPENEXISTING)) return 1; String strShader; ShaderFile.ReadFileToString(strShader); c.fileData = strShader.Array(); GS->CreatePixelShaderBlob(c.shaderData, strShader.Array(), c.fileName.c_str()); SetEvent(c.readyEvent.get()); return 0; }), &c)); } if (c.thread && WaitForSingleObject(c.readyEvent.get(), 0) == WAIT_OBJECT_0) c.thread.reset(); return FuturePixelShader(c.readyEvent.get(), c.shaderData, c.fileData, c.fileName); }
// Game Capture log is always appended, as requested by Jim (yes, this can result in two game capture logs in one upload) static void AppendGameCaptureLog(String &data) { String path = FormattedString(L"%s\\captureHookLog.txt", OBSGetPluginDataPath().Array()); XFile f(path.Array(), XFILE_READ | XFILE_SHARED, XFILE_OPENEXISTING); if (!f.IsOpen()) return; String append; f.ReadFileToString(append); data << L"\r\n\r\nLast Game Capture Log:\r\n" << append; }
bool UploadLog(String filename, LogUploadResult &result) { String path = FormattedString(L"%s\\logs\\%s", OBSGetAppDataPath(), filename.Array()); XFile f(path.Array(), XFILE_READ, XFILE_OPENEXISTING); if (!f.IsOpen()) { result.errors << FormattedString(Str("LogUpload.CannotOpenFile"), path.Array()); return false; } String data; f.ReadFileToString(data); if (data.IsEmpty()) { result.errors << Str("LogUpload.EmptyLog"); return false; } AppendGameCaptureLog(data); return UploadLogGitHub(filename.Array(), data, result); }
json_t* OBSAPIMessageHandler::HandleSetCurrentScene(OBSAPIMessageHandler* handler, json_t* message) { json_t* newScene = json_object_get(message, "scene-name"); if(newScene != NULL && json_typeof(newScene) == JSON_STRING) { String name = json_string_value(newScene); OBSSetScene(name.Array(), true); } return GetOkResponse(); }
String GetCBText(HWND hwndCombo, UINT id) { UINT curSel = (id != CB_ERR) ? id : (UINT)SendMessage(hwndCombo, CB_GETCURSEL, 0, 0); if(curSel == CB_ERR) return String(); String strText; strText.SetLength((UINT)SendMessage(hwndCombo, CB_GETLBTEXTLEN, curSel, 0)); if(strText.Length()) SendMessage(hwndCombo, CB_GETLBTEXT, curSel, (LPARAM)strText.Array()); return strText; }
void get_x264_log(void *param, int i_level, const char *psz, va_list argptr) { String chi; chi << TEXT("x264: ") << String(psz); chi.FindReplace(TEXT("%s"), TEXT("%S")); OSDebugOutva(chi, argptr); chi.FindReplace(TEXT("\r"), TEXT("")); chi.FindReplace(TEXT("\n"), TEXT("")); Logva(chi.Array(), argptr); }
String LoadSettingTextComboString(HWND hwnd, CTSTR lpConfigSection, CTSTR lpConfigName, CTSTR lpDefault) { String strVal = AppConfig->GetString(lpConfigSection, lpConfigName, lpDefault); int id = (int)SendMessage(hwnd, CB_FINDSTRINGEXACT, -1, (LPARAM)strVal.Array()); if(!AppConfig->HasKey(lpConfigSection, lpConfigName)) { if(lpDefault) AppConfig->SetString(lpConfigSection, lpConfigName, lpDefault); } SendMessage(hwnd, CB_SETCURSEL, (WPARAM)id, 0); return strVal; }
Texture *ResourceManager::GetTexture(CTSTR lpName, BOOL bGenMipMaps) { traceInFast(ResourceManager::GetTexture); assert(lpName); for(DWORD i=0; i<TextureList.Num(); i++) { TextureResource &res = TextureList[i]; if(res.name.CompareI(lpName)) { if(res.texture->IsOf(GetClass(Texture))) { ++res.refs; return (Texture*)res.texture; } else return NULL; } } //---------------------------------------- String path; if(!Engine::ConvertResourceName(lpName, TEXT("textures"), path)) return NULL; //---------------------------------------- Texture *texOut = GS->CreateTextureFromFile(path, bGenMipMaps); if(!texOut) { AppWarning(TEXT("Could not create texture '%s'"), path.Array()); return NULL; } TextureResource &res = *TextureList.CreateNew(); res.texture = texOut; res.name = lpName; res.refs = 1; if(texOut) texOut->bGenMipMaps = bGenMipMaps; return texOut; traceOutFast; }
String CreateHTTPURL(String host, String path, String extra, bool secure) { URL_COMPONENTS components = { sizeof URL_COMPONENTS, secure ? L"https" : L"http", secure ? 5 : 4, secure ? INTERNET_SCHEME_HTTPS : INTERNET_SCHEME_HTTP, host.Array(), host.Length(), secure ? INTERNET_DEFAULT_HTTPS_PORT : INTERNET_DEFAULT_HTTP_PORT, nullptr, 0, nullptr, 0, path.Array(), path.Length(), extra.Array(), extra.Length() }; String url; url.SetLength(MAX_PATH); DWORD length = MAX_PATH; if (!WinHttpCreateUrl(&components, ICU_ESCAPE, url.Array(), &length)) return String(); url.SetLength(length); return url; }
void dumpLastData(int callNum, int indent=0) { if(lastCall != callNum) return; String indentStr; for(int i=0; i<indent; i++) indentStr << TEXT("| "); CTSTR lpIndent = indent == 0 ? TEXT("") : indentStr.Array(); Log(TEXT("%s%s - [time: %g ms (cpu time: %g ms)]"), lpIndent, lpName, MicroToMS((DWORD)lastTimeElapsed), MicroToMS((DWORD)lastCpuTimeElapsed)); for(unsigned int i=0; i<Children.Num(); i++) Children[i].dumpLastData(callNum, indent+1); }
void SettingsVideo::RefreshDownscales(HWND hwnd, int cx, int cy) { int lastID = (int)SendMessage(hwnd, CB_GETCURSEL, 0, 0); SendMessage(hwnd, CB_RESETCONTENT, 0, 0); float downscale = AppConfig->GetFloat(TEXT("Video"), TEXT("Downscale")); bool bFoundVal = false; for(int i=0; i<multiplierCount; i++) { float multiplier = downscaleMultipliers[i]; int scaleCX = int(float(cx)/multiplier) & 0xFFFFFFFE; int scaleCY = int(float(cy)/multiplier) & 0xFFFFFFFE; String strText; if(i == 0) strText << Str("None") << TEXT(" (") << IntString(scaleCX) << TEXT("x") << IntString(scaleCY) << TEXT(")"); else strText << FormattedString(TEXT("%0.2f"), multiplier) << TEXT(" (") << IntString(scaleCX) << TEXT("x") << IntString(scaleCY) << TEXT(")"); int id = (int)SendMessage(hwnd, CB_ADDSTRING, 0, (LPARAM)strText.Array()); SendMessage(hwnd, CB_SETITEMDATA, id, (LPARAM)*(DWORD*)&multiplier); if(CloseFloat(downscale, multiplier)) { if(lastID == CB_ERR) SendMessage(hwnd, CB_SETCURSEL, id, 0); downscale = multiplier; bFoundVal = true; } } if(!bFoundVal) { AppConfig->SetFloat(TEXT("Video"), TEXT("Downscale"), 1.0f); if(lastID == CB_ERR) SendMessage(hwnd, CB_SETCURSEL, 0, 0); SetChangedSettings(true); } if(lastID != CB_ERR) SendMessage(hwnd, CB_SETCURSEL, lastID, 0); }
String LoadSettingEditString(HWND hwnd, CTSTR lpConfigSection, CTSTR lpConfigName, CTSTR lpDefault) { String strLoadVal; if(!AppConfig->HasKey(lpConfigSection, lpConfigName)) { if(lpDefault) AppConfig->SetString(lpConfigSection, lpConfigName, lpDefault); strLoadVal = lpDefault; } else strLoadVal = AppConfig->GetString(lpConfigSection, lpConfigName, lpDefault); SendMessage(hwnd, WM_SETTEXT, 0, (LPARAM)strLoadVal.Array()); return strLoadVal; }
void LogInterfaceType (RTMP *rtmp) { MIB_IPFORWARDROW route; DWORD destAddr; CHAR hostname[256]; if (rtmp->Link.hostname.av_len >= sizeof(hostname)-1) return; strncpy (hostname, rtmp->Link.hostname.av_val, sizeof(hostname)-1); hostname[rtmp->Link.hostname.av_len] = 0; HOSTENT *h = gethostbyname(hostname); if (!h) return; destAddr = *(DWORD *)h->h_addr_list[0]; if (!GetBestRoute (destAddr, rtmp->m_bindIP.addr.sin_addr.S_un.S_addr, &route)) { MIB_IFROW row; zero (&row, sizeof(row)); row.dwIndex = route.dwForwardIfIndex; if (!GetIfEntry (&row)) { DWORD speed = row.dwSpeed / 1000000; TCHAR *type; String otherType; if (row.dwType == IF_TYPE_ETHERNET_CSMACD) type = TEXT("ethernet"); else if (row.dwType == IF_TYPE_IEEE80211) type = TEXT("802.11"); else { otherType = FormattedString (TEXT("type %d"), row.dwType); type = otherType.Array(); } Log (TEXT(" Interface: %S (%s, %d mbps)"), row.bDescr, type, speed); } } }
void AgentSource::UpdateSettings(Value &data) { this->data = data; IBaseVideo *OldSource = globalSource; String strName; if (!data["SecName"].isNull()) { strName = Asic2WChar(data["SecName"].asString().c_str()).c_str(); } String strNameDisable = L"空区域"; if (strName.IsValid() && (strNameDisable != strName)) { Value NameList; if (GetNameList(NameList)) { Json::Value &ArryList = NameList["Namelist"]; for (int i = 0; i < ArryList.size(); ++i) { Value &OneVaule = ArryList[i]; if (0 == strcmp(WcharToAnsi(strName.Array()).c_str(), OneVaule["Name"].asString().c_str())) { std::stringstream SourceId; uint64_t VideoId = 0; if (!OneVaule["SourceID"].isNull()) { if (!OneVaule["DeviceSourceID"].isNull()) { SourceId << OneVaule["DeviceSourceID"].asString().c_str(); SourceId >> VideoId; } else { SourceId << OneVaule["SourceID"].asString().c_str(); SourceId >> VideoId; } } globalSource = (IBaseVideo *)VideoId; break; }
QWORD STDCALL OSGetFileModificationTime(String path) { HANDLE hFile; if((hFile = CreateFile(path.Array(), GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, NULL)) == INVALID_HANDLE_VALUE) return -1; FILETIME create, write; BOOL res = GetFileTime(hFile, &create, nullptr, &write); CloseHandle(hFile); if(!res) return -1; ULARGE_INTEGER create_, write_; create_.HighPart = create.dwHighDateTime; create_.LowPart = create.dwLowDateTime; write_.HighPart = write.dwHighDateTime; write_.LowPart = write.dwLowDateTime; if(write_.QuadPart > create_.QuadPart) return write_.QuadPart; return create_.QuadPart; }
// Basically the same as Open (and in fact Open could/should call ParseString to do its thing) // But ParseString allows chunks of JSON type strings to be parse into the XConfig structure. bool XConfig::ParseString(const String& config) { String safe_copy = config; TSTR lpTemp = safe_copy; RootElement = new XElement(this, NULL, TEXT("Root")); if(!ReadFileData2(RootElement, 0, lpTemp, true)) { for(DWORD i=0; i<RootElement->SubItems.Num(); i++) delete RootElement->SubItems[i]; CrashError(TEXT("Error parsing X string '%s'"), config.Array()); Close(false); } return true; }
static DWORD STDCALL SaveReplayBufferThread(void *arg) { unique_ptr<ReplayBuffer::thread_param_t> param((ReplayBuffer::thread_param_t*)arg); String name = GetOutputFilename(); unique_ptr<VideoFileStream> out(CreateFileStream(name)); if (!out) { Log(L"ReplayBuffer: Failed to create file stream for file name '%s'", name.Array()); return 1; } auto &packets = get<1>(*param); DWORD target_ts = get<0>(*param); DWORD stop_ts = -1; for (auto it = rbegin(packets); it != rend(packets); it++) { if (get<0>(**it) == PacketType_Audio) continue; DWORD ts = get<2>(**it); if (ts <= target_ts) break; stop_ts = ts; } for (auto packet : packets) { if (get<2>(*packet) == stop_ts) break; auto &buf = get<3>(*packet); out->AddPacket(&buf.front(), (UINT)buf.size(), get<1>(*packet), get<2>(*packet), get<0>(*packet)); } ReplayBuffer::SetLastFilename(name); return 0; }
static inline void LoadUserServices(vector<ServiceIdentifier> &services) { OSFindData findData; String servicesDir = FormattedString(L"%s/services/", API->GetAppDataPath()); if (HANDLE find = OSFindFirstFile(FormattedString(L"%s/*.xconfig", servicesDir.Array()), findData)) { do { if (findData.bDirectory) continue; XConfig service(servicesDir + findData.fileName); if (!service.IsOpen()) continue; services.emplace_back(0, findData.fileName); } while (OSFindNextFile(find, findData)); OSFindClose(find); } }