From c883d9cf5673fe0af8d69120b048d642e122bdbb Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?John=20Ankarstr=C3=B6m?= <john@ankarstrom.se>
Date: Fri, 29 Jul 2022 15:31:26 +0200
Subject: Use swprintf_s instead of string streams.

I find it much simpler. It is very safe, as wszf only accepts
fixed-size arrays. There is, of course, the chance that swprintf_s
fails and writes nothing into the array. This can be handled by the
caller, if desired.
---
 c/common.h |  8 +++++++-
 c/main.cpp | 30 ++++++++++++++++--------------
 2 files changed, 23 insertions(+), 15 deletions(-)

(limited to 'c')

diff --git a/c/common.h b/c/common.h
index 3a2d598..8b88635 100644
--- a/c/common.h
+++ b/c/common.h
@@ -42,6 +42,12 @@ T* Library::GetProcAddress(const char* const szProc)
 	return (T*)(void*)::GetProcAddress(m_hModule, szProc);
 }
 
+template<size_t N, typename... T>
+inline auto wszf(wchar_t (&wsz)[N], const wchar_t* wszFmt, T... xs)
+{
+	return swprintf_s(wsz, N, wszFmt, xs...);
+}
+
 /* Create and return an object of type C. If construction fails,
  * return nothing. The returned value must be checked before being
  * used, as dereferencing is undefined if the value is empty. */
@@ -57,7 +63,7 @@ std::optional<T> maybe_make(U... xs)
 
 /* Variable template for caching values from GetSystemMetrics. */
 template <int I>
-const auto Metric = GetSystemMetrics(I);
+auto Metric = GetSystemMetrics(I);
 
 /* Check result of Windows API call, throwing error on NULL. */
 template <typename T>
diff --git a/c/main.cpp b/c/main.cpp
index 29a4d46..673affe 100644
--- a/c/main.cpp
+++ b/c/main.cpp
@@ -1,5 +1,4 @@
 #include <exception>
-#include <sstream>
 #include <windows.h>
 #include <commctrl.h>
 #include <uxtheme.h>
@@ -47,14 +46,12 @@ static void UpdateTheme();
 
 void TerminateMsg(const wchar_t* wsz1, const wchar_t* wsz2) noexcept
 {
-	std::wstringstream wss;
-	wss << L"Episode Browser was terminated due to ";
-	wss << wsz1;
+	wchar_t wsz[256] = {0};
 	if (wsz2)
-		wss << ": " << wsz2;
+		wszf(wsz, L"Episode Browser was terminated due to %s: %s.", wsz1, wsz2);
 	else
-		wss << ".";
-	MessageBox(g_hWnd, wss.str().c_str(), L"Fatal Error", MB_ICONERROR);
+		wszf(wsz, L"Episode Browser was terminated due to %s.", wsz1);
+	MessageBox(g_hWnd, wsz, L"Fatal Error", MB_ICONERROR);
 }
 
 void OnTerminate() noexcept
@@ -240,7 +237,11 @@ LRESULT CALLBACK WndProc(const HWND hWnd, const UINT uMsg, const WPARAM wParam,
 	case 0x02E0: /* WM_DPICHANGED */
 	    {
 		const RECT* const lpr = (RECT*)lParam;
+
+		/* Update DPI and cached metrics. */
 		g_iDPI = HIWORD(wParam);
+		Metric<SM_CXVSCROLL> = GetSystemMetrics(SM_CXVSCROLL);
+
 		prefer(SetWindowPos(hWnd, (HWND)NULL,
 		    lpr->left, lpr->top,
 		    lpr->right-lpr->left,
@@ -455,9 +456,9 @@ void WndProcContextMenu(const HWND, unsigned short wCommand)
 		EBMessageBox(L"Episode could not be opened locally.",
 		    L"Error", MB_ICONWARNING);
 	} else if (cNotFound) {
-		std::wstringstream wss;
-		wss << cNotFound << L" episodes could not be opened locally.";
-		EBMessageBox(wss.str().c_str(), L"Error", MB_ICONWARNING);
+		wchar_t wsz[64] = {0};
+		wszf(wsz, L"%d episodes could not be opened locally.", cNotFound);
+		EBMessageBox(wsz, L"Error", MB_ICONWARNING);
 	} else if (ID_SUBGROUP(wCommand) == IDG_CTX_RATE) {
 		g_pElv->Sort();
 		g_pElv->ShowFocus();
@@ -473,10 +474,11 @@ void WaitFor(const char* szMod, const char* szPred)
 	static std::wstring wsPred;
 
 	if (bActive) {
-		std::wstringstream wss;
-		wss << L"Another task (" << wsPred.c_str() << ") is active. "
-		    << "Do you want to cancel the existing task and start a new one?";
-		if (EBMessageBox(wss.str().c_str(), L"Error", MB_YESNO|MB_ICONWARNING) != IDYES)
+		wchar_t wsz[128] = {0};
+		wszf(wsz, L"Another task (%s) is active. "
+		    L"Do you want to cancel the existing task and start a new one?",
+		    wsPred.c_str());
+		if (EBMessageBox(wsz, L"Error", MB_YESNO|MB_ICONWARNING) != IDYES)
 			return;
 		KillTimer(NULL, iTimer);
 		bActive = 0;
-- 
cgit v1.2.3