From c6cd2f1f164baac1414f2cf658566de146b10552 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?John=20Ankarstr=C3=B6m?= Date: Sat, 23 Jul 2022 18:59:37 +0200 Subject: Fix display of Unicode text. Turns out that SWI-Prolog's wide string functions, which I started using in 03fe361, do not convert between narrow Prolog atoms and wide C strings, as I mistakenly thought. Instead, they work with wide Prolog atoms. In hindsight, it is not surprising. --- README | 9 +++++---- c/common.cpp | 18 ++++++++++++++++++ c/common.h | 1 + c/datalistview.cpp | 10 +++++----- c/episodelistview.cpp | 9 ++++----- c/pl.h | 25 +++++++++++++++++++------ 6 files changed, 52 insertions(+), 20 deletions(-) diff --git a/README b/README index ebe22ef..c8b3f5c 100644 --- a/README +++ b/README @@ -69,12 +69,13 @@ Following is a summary of some coding conventions used in the project. - w = WORD, WPARAM - dw = DWORD - lvi = LVITEM - - sz = unmangaged, zero-terminated string (char *) - - wsz = ... wide string (wchar_t *) - - tsz = ... tstring (TCHAR *) - - str = ... managed string (std::string) + - sz = unmanaged, zero-terminated narrow string (char*) + - wsz = ... wide string (wchar_t*) + - tsz = ... tstring (TCHAR*) + - str = managed narrow string (std::string) - wstr = ... (std::wstring) - tstr = ... (std::basic_string) + - bstr = ... (std::basic_string of any type T) The list above is non-exhaustive. Variables whose type is unknown (in templates) do not need prefixes. Some very common self-explanatory diff --git a/c/common.cpp b/c/common.cpp index 4ce95a0..155c099 100644 --- a/c/common.cpp +++ b/c/common.cpp @@ -57,6 +57,24 @@ Library::~Library() FreeLibrary(m_hModule); } +/* Convert narrow unmanaged string to narrow/wide basic string. */ +template <> +std::basic_string BstrFromSz(const char* sz, int) +{ + return std::string(sz); +} + +template <> +std::basic_string BstrFromSz(const char* sz, int iCp) +{ + int cbMultiByte = strlen(sz)+1; + int cchWideChar = MultiByteToWideChar(iCp, 0, sz, cbMultiByte, NULL, 0); + std::wstring wstr(cchWideChar, 0); + if (!MultiByteToWideChar(iCp, 0, sz, cbMultiByte, wstr.data(), cchWideChar)) + throw Win32Error(GetLastError()); + return wstr; +} + /* Move message box to center of main window. */ static LRESULT CALLBACK CBTProc(const int nCode, const WPARAM wParam, const LPARAM lParam) noexcept { diff --git a/c/common.h b/c/common.h index 5fe6d62..fb21e6f 100644 --- a/c/common.h +++ b/c/common.h @@ -11,6 +11,7 @@ #define WA "A" #endif +template std::basic_string BstrFromSz(const char* sz, int iCp = CP_UTF8); int EBMessageBox(const TCHAR* tszText, const TCHAR* tszCaption, unsigned uType); struct Win32Error : public std::exception diff --git a/c/datalistview.cpp b/c/datalistview.cpp index b728fa8..1ceeb3b 100644 --- a/c/datalistview.cpp +++ b/c/datalistview.cpp @@ -57,21 +57,21 @@ void DataListView::ShowEpisode(const int iEpisode) PL_predicate("episode_datum", 3, "episode_data"), t); for (int i = 0; PL_next_solution(q); i++) { - TCHAR* tszKey; - TCHAR* tszValue; + std::basic_string tstrKey; + std::basic_string tstrValue; - if (!(PlGet(t+1, &tszKey) && PlGet(t+2, &tszValue))) + if (!(PlGet(t+1, &tstrKey) && PlGet(t+2, &tstrValue))) continue; lviKey.mask = LVIF_TEXT; lviKey.iItem = i; lviKey.iSubItem = 0; - lviKey.pszText = tszKey; + lviKey.pszText = tstrKey.data(); ListView_InsertItem(hWnd, &lviKey); lviValue.iItem = i; lviValue.iSubItem = 1; - lviValue.pszText = tszValue; + lviValue.pszText = tstrValue.data(); ListView_SetItem(hWnd, &lviValue); } diff --git a/c/episodelistview.cpp b/c/episodelistview.cpp index cdb3dc7..bc01ce9 100644 --- a/c/episodelistview.cpp +++ b/c/episodelistview.cpp @@ -414,17 +414,16 @@ void EpisodeListView::Update() /* Update episode name and rating. */ void EpisodeListView::UpdateItem(const LVITEM* const pLvi) { - Mark m; - TCHAR* tszName; + std::basic_string tstrName; int iRating; static TCHAR tszRating[3]; - if (!Pl("episode_data","episode_title",pLvi->lParam,&tszName)) { + if (!Pl("episode_data","episode_title",pLvi->lParam,&tstrName)) { if (!Pl("episode_data","update_episode_data")) goto r; - if (!Pl("episode_data","episode_title",pLvi->lParam,&tszName)) + if (!Pl("episode_data","episode_title",pLvi->lParam,&tstrName)) goto r; } - ListView_SetItemText(hWnd, pLvi->iItem, ELVSITITLE, tszName); + ListView_SetItemText(hWnd, pLvi->iItem, ELVSITITLE, tstrName.data()); r: if (!Pl("episode_data","episode_rating",pLvi->lParam,&iRating)) { ListView_SetItemText(hWnd, pLvi->iItem, ELVSIRATING, (TCHAR*)TEXT("")); diff --git a/c/pl.h b/c/pl.h index 8325c86..44b8a5e 100644 --- a/c/pl.h +++ b/c/pl.h @@ -1,9 +1,12 @@ #ifndef PL_H #define PL_H +#include #include #include +#include "common.h" + int PL_get_tchars(term_t t, TCHAR** pTsz, int iFlags); struct Frame @@ -43,14 +46,13 @@ inline int PlPut(term_t t, long long x) { return PL_put_int64(t, x); } inline int PlPut(term_t t, atom_t x) { return PL_put_atom(t, x); } inline int PlPut(term_t t, char* x) { return PL_put_atom_chars(t, x); } inline int PlPut(term_t t, const char* x) { return PL_put_atom_chars(t, x); } -inline int PlPut(term_t t, wchar_t* x) { return PL_unify_wchars(t, PL_ATOM, -1, x); } -inline int PlPut(term_t t, const wchar_t* x) { return PL_unify_wchars(t, PL_ATOM, -1, x); } inline int PlPut(term_t, int*) { return -1; } inline int PlPut(term_t, long*) { return -1; } inline int PlPut(term_t, long long*) { return -1; } inline int PlPut(term_t, atom_t*) { return -1; } inline int PlPut(term_t, char**) { return -1; } -inline int PlPut(term_t, wchar_t**) { return -1; } +inline int PlPut(term_t, std::string*) { return -1; } +inline int PlPut(term_t, std::wstring*) { return -1; } inline int PlGet(term_t, int) { return -1; } inline int PlGet(term_t, long) { return -1; } @@ -58,14 +60,25 @@ inline int PlGet(term_t, long long) { return -1; } inline int PlGet(term_t, atom_t) { return -1; } inline int PlGet(term_t, char*) { return -1; } inline int PlGet(term_t, const char*) { return -1; } -inline int PlGet(term_t, wchar_t*) { return -1; } -inline int PlGet(term_t, const wchar_t*) { return -1; } inline int PlGet(term_t t, int* x) { return PL_get_integer(t, x); } inline int PlGet(term_t t, long* x) { return PL_get_long(t, x); } inline int PlGet(term_t t, long long* x) { return PL_get_int64(t, x); } inline int PlGet(term_t t, atom_t* x) { return PL_get_atom(t, x); } inline int PlGet(term_t t, char** x) { return PL_get_atom_chars(t, x); } -inline int PlGet(term_t t, wchar_t** x) { size_t len; return PL_get_wchars(t, &len, x, CVT_ATOM); } +inline int PlGet(term_t t, std::string* x) { + Mark m; + char* sz; + if (!PlGet(t, &sz)) return 0; + *x = sz; + return 1; +} +inline int PlGet(term_t t, std::wstring* x) { + Mark m; + char* sz; + if (!PlGet(t, &sz)) return 0; + *x = BstrFromSz(sz); + return 1; /* or catch potential exception from BstrFromSz? */ +} /* Put in or get from a term reference an arbitrary number of values, * returning false if any value could not be put/got. */ -- cgit v1.2.3