OpenTTD Source: src/os/windows/win32.cpp Source File

OpenTTD Source 14.1

win32.cpp
Go to the documentation of this file.
1 /*
2 * This file is part of OpenTTD.
3 * OpenTTD is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, version 2.
4 * OpenTTD is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
5 * See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with OpenTTD. If not, see <http://www.gnu.org/licenses/>.
6 */
7
10 #include "../../stdafx.h"
11 #include "../../debug.h"
12 #include "../../gfx_func.h"
13 #include "../../textbuf_gui.h"
14 #include "../../fileio_func.h"
15 #include <windows.h>
16 #include <fcntl.h>
17 #include <mmsystem.h>
18 #include <regstr.h>
19 #define NO_SHOBJIDL_SORTDIRECTION // Avoid multiple definition of SORT_ASCENDING
20 #include <shlobj.h> /* SHGetFolderPath */
21 #include <shellapi.h>
22 #include <WinNls.h>
23 #include "win32.h"
24 #include "../../fios.h"
25 #include "../../core/alloc_func.hpp"
26 #include "../../string_func.h"
27 #include <sys/stat.h>
28 #include "../../language.h"
29 #include "../../thread.h"
30 #include "../../library_loader.h"
31
32 #include "../../safeguards.h"
33
34 static bool _has_console;
35 static bool _cursor_disable = true;
36 static bool _cursor_visible = true;
37
38 bool MyShowCursor(bool show, bool toggle)
39 {
40 if (toggle) _cursor_disable = !_cursor_disable;
41 if (_cursor_disable) return show;
42 if (_cursor_visible == show) return show;
43
44 _cursor_visible = show;
45 ShowCursor(show);
46
47 return !show;
48 }
49
50 void ShowOSErrorBox(const char *buf, bool)
51 {
52 MyShowCursor(true);
53 MessageBox(GetActiveWindow(), OTTD2FS(buf).c_str(), L"Error!", MB_ICONSTOP | MB_TASKMODAL);
54 }
55
56 void OSOpenBrowser(const std::string &url)
57 {
58 ShellExecute(GetActiveWindow(), L"open", OTTD2FS(url).c_str(), nullptr, nullptr, SW_SHOWNORMAL);
59 }
60
61 /* Code below for windows version of opendir/readdir/closedir copied and
62 * modified from Jan Wassenberg's GPL implementation posted over at
63 * http://www.gamedev.net/community/forums/topic.asp?topic_id=364584&whichpage=1&#2398903 */
64
65 struct DIR {
66 HANDLE hFind;
67 /* the dirent returned by readdir.
68 * note: having only one global instance is not possible because
69 * multiple independent opendir/readdir sequences must be supported. */
70 dirent ent;
71 WIN32_FIND_DATA fd;
72 /* since opendir calls FindFirstFile, we need a means of telling the
73 * first call to readdir that we already have a file.
74 * that's the case iff this is true */
75 bool at_first_entry;
76 };
77
78 /* suballocator - satisfies most requests with a reusable static instance.
79 * this avoids hundreds of alloc/free which would fragment the heap.
80 * To guarantee concurrency, we fall back to malloc if the instance is
81 * already in use (it's important to avoid surprises since this is such a
82 * low-level routine). */
83 static DIR _global_dir;
84 static LONG _global_dir_is_in_use = false;
85
86 static inline DIR *dir_calloc()
87 {
88 DIR *d;
89
90 if (InterlockedExchange(&_global_dir_is_in_use, true) == (LONG)true) {
91 d = CallocT<DIR>(1);
92 } else {
93 d = &_global_dir;
94 memset(d, 0, sizeof(*d));
95 }
96 return d;
97 }
98
99 static inline void dir_free(DIR *d)
100 {
101 if (d == &_global_dir) {
102 _global_dir_is_in_use = (LONG)false;
103 } else {
104 free(d);
105 }
106 }
107
108 DIR *opendir(const wchar_t *path)
109 {
110 DIR *d;
111 UINT sem = SetErrorMode(SEM_FAILCRITICALERRORS); // disable 'no-disk' message box
112 DWORD fa = GetFileAttributes(path);
113
114 if ((fa != INVALID_FILE_ATTRIBUTES) && (fa & FILE_ATTRIBUTE_DIRECTORY)) {
115 d = dir_calloc();
116 if (d != nullptr) {
117 std::wstring search_path = path;
118 bool slash = path[wcslen(path) - 1] == '\\';
119
120 /* build search path for FindFirstFile, try not to append additional slashes
121 * as it throws Win9x off its groove for root directories */
122 if (!slash) search_path += L"\\";
123 search_path += L"*";
124 d->hFind = FindFirstFile(search_path.c_str(), &d->fd);
125
126 if (d->hFind != INVALID_HANDLE_VALUE ||
127 GetLastError() == ERROR_NO_MORE_FILES) { // the directory is empty
128 d->ent.dir = d;
129 d->at_first_entry = true;
130 } else {
131 dir_free(d);
132 d = nullptr;
133 }
134 } else {
135 errno = ENOMEM;
136 }
137 } else {
138 /* path not found or not a directory */
139 d = nullptr;
140 errno = ENOENT;
141 }
142
143 SetErrorMode(sem); // restore previous setting
144 return d;
145 }
146
147 struct dirent *readdir(DIR *d)
148 {
149 DWORD prev_err = GetLastError(); // avoid polluting last error
150
151 if (d->at_first_entry) {
152 /* the directory was empty when opened */
153 if (d->hFind == INVALID_HANDLE_VALUE) return nullptr;
154 d->at_first_entry = false;
155 } else if (!FindNextFile(d->hFind, &d->fd)) { // determine cause and bail
156 if (GetLastError() == ERROR_NO_MORE_FILES) SetLastError(prev_err);
157 return nullptr;
158 }
159
160 /* This entry has passed all checks; return information about it.
161 * (note: d_name is a pointer; see struct dirent definition) */
162 d->ent.d_name = d->fd.cFileName;
163 return &d->ent;
164 }
165
166 int closedir(DIR *d)
167 {
168 FindClose(d->hFind);
169 dir_free(d);
170 return 0;
171 }
172
173 bool FiosIsRoot(const std::string &file)
174 {
175 return file.size() == 3; // C:\...
176 }
177
178 void FiosGetDrives(FileList &file_list)
179 {
180 wchar_t drives[256];
181 const wchar_t *s;
182
183 GetLogicalDriveStrings(lengthof(drives), drives);
184 for (s = drives; *s != '\0';) {
185 FiosItem *fios = &file_list.emplace_back();
186 fios->type = FIOS_TYPE_DRIVE;
187 fios->mtime = 0;
188 fios->name += (char)(s[0] & 0xFF);
189 fios->name += ':';
190 fios->title = fios->name;
191 while (*s++ != '\0') { /* Nothing */ }
192 }
193 }
194
195 bool FiosIsValidFile(const std::string &, const struct dirent *ent, struct stat *sb)
196 {
197 /* hectonanoseconds between Windows and POSIX epoch */
198 static const int64_t posix_epoch_hns = 0x019DB1DED53E8000LL;
199 const WIN32_FIND_DATA *fd = &ent->dir->fd;
200
201 sb->st_size = ((uint64_t) fd->nFileSizeHigh << 32) + fd->nFileSizeLow;
202 /* UTC FILETIME to seconds-since-1970 UTC
203 * we just have to subtract POSIX epoch and scale down to units of seconds.
204 * http://www.gamedev.net/community/forums/topic.asp?topic_id=294070&whichpage=1&#1860504
205 * XXX - not entirely correct, since filetimes on FAT aren't UTC but local,
206 * this won't entirely be correct, but we use the time only for comparison. */
207 sb->st_mtime = (time_t)((*(const uint64_t*)&fd->ftLastWriteTime - posix_epoch_hns) / 1E7);
208 sb->st_mode = (fd->dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)? S_IFDIR : S_IFREG;
209
210 return true;
211 }
212
213 bool FiosIsHiddenFile(const struct dirent *ent)
214 {
215 return (ent->dir->fd.dwFileAttributes & (FILE_ATTRIBUTE_HIDDEN | FILE_ATTRIBUTE_SYSTEM)) != 0;
216 }
217
218 std::optional<uint64_t> FiosGetDiskFreeSpace(const std::string &path)
219 {
220 UINT sem = SetErrorMode(SEM_FAILCRITICALERRORS); // disable 'no-disk' message box
221
222 ULARGE_INTEGER bytes_free;
223 bool retval = GetDiskFreeSpaceEx(OTTD2FS(path).c_str(), &bytes_free, nullptr, nullptr);
224
225 SetErrorMode(sem); // reset previous setting
226
227 if (retval) return bytes_free.QuadPart;
228 return std::nullopt;
229 }
230
231 void CreateConsole()
232 {
233 HANDLE hand;
234 CONSOLE_SCREEN_BUFFER_INFO coninfo;
235
236 if (_has_console) return;
237 _has_console = true;
238
239 if (!AllocConsole()) return;
240
241 hand = GetStdHandle(STD_OUTPUT_HANDLE);
242 GetConsoleScreenBufferInfo(hand, &coninfo);
243 coninfo.dwSize.Y = 500;
244 SetConsoleScreenBufferSize(hand, coninfo.dwSize);
245
246 /* redirect unbuffered STDIN, STDOUT, STDERR to the console */
247 #if !defined(__CYGWIN__)
248
249 /* Check if we can open a handle to STDOUT. */
250 int fd = _open_osfhandle((intptr_t)hand, _O_TEXT);
251 if (fd == -1) {
252 /* Free everything related to the console. */
253 FreeConsole();
254 _has_console = false;
255 _close(fd);
256 CloseHandle(hand);
257
258 ShowInfo("Unable to open an output handle to the console. Check known-bugs.txt for details.");
259 return;
260 }
261
262 #if defined(_MSC_VER) && _MSC_VER >= 1900
263 freopen("CONOUT$", "a", stdout);
264 freopen("CONIN$", "r", stdin);
265 freopen("CONOUT$", "a", stderr);
266 #else
267 *stdout = *_fdopen(fd, "w");
268 *stdin = *_fdopen(_open_osfhandle((intptr_t)GetStdHandle(STD_INPUT_HANDLE), _O_TEXT), "r" );
269 *stderr = *_fdopen(_open_osfhandle((intptr_t)GetStdHandle(STD_ERROR_HANDLE), _O_TEXT), "w" );
270 #endif
271
272 #else
273 /* open_osfhandle is not in cygwin */
274 *stdout = *fdopen(1, "w" );
275 *stdin = *fdopen(0, "r" );
276 *stderr = *fdopen(2, "w" );
277 #endif
278
279 setvbuf(stdin, nullptr, _IONBF, 0);
280 setvbuf(stdout, nullptr, _IONBF, 0);
281 setvbuf(stderr, nullptr, _IONBF, 0);
282 }
283
285 static const char *_help_msg;
286
288 static INT_PTR CALLBACK HelpDialogFunc(HWND wnd, UINT msg, WPARAM wParam, LPARAM)
289 {
290 switch (msg) {
291 case WM_INITDIALOG: {
292 char help_msg[8192];
293 const char *p = _help_msg;
294 char *q = help_msg;
295 while (q != lastof(help_msg) && *p != '\0') {
296 if (*p == '\n') {
297 *q++ = '\r';
298 if (q == lastof(help_msg)) {
299 q[-1] = '\0';
300 break;
301 }
302 }
303 *q++ = *p++;
304 }
305 *q = '\0';
306 /* We need to put the text in a separate buffer because the default
307 * buffer in OTTD2FS might not be large enough (512 chars). */
308 wchar_t help_msg_buf[8192];
309 SetDlgItemText(wnd, 11, convert_to_fs(help_msg, help_msg_buf, lengthof(help_msg_buf)));
310 SendDlgItemMessage(wnd, 11, WM_SETFONT, (WPARAM)GetStockObject(ANSI_FIXED_FONT), FALSE);
311 } return TRUE;
312
313 case WM_COMMAND:
314 if (wParam == 12) ExitProcess(0);
315 return TRUE;
316 case WM_CLOSE:
317 ExitProcess(0);
318 }
319
320 return FALSE;
321 }
322
323 void ShowInfoI(const std::string &str)
324 {
325 if (_has_console) {
326 fmt::print(stderr, "{}\n", str);
327 } else {
328 bool old;
329 ReleaseCapture();
330 _left_button_clicked = _left_button_down = false;
331
332 old = MyShowCursor(true);
333 if (str.size() > 2048) {
334 /* The minimum length of the help message is 2048. Other messages sent via
335 * ShowInfo are much shorter, or so long they need this way of displaying
336 * them anyway. */
337 _help_msg = str.c_str();
338 DialogBox(GetModuleHandle(nullptr), MAKEINTRESOURCE(101), nullptr, HelpDialogFunc);
339 } else {
340 /* We need to put the text in a separate buffer because the default
341 * buffer in OTTD2FS might not be large enough (512 chars). */
342 wchar_t help_msg_buf[8192];
343 MessageBox(GetActiveWindow(), convert_to_fs(str, help_msg_buf, lengthof(help_msg_buf)), L"OpenTTD", MB_ICONINFORMATION | MB_OK);
344 }
345 MyShowCursor(old);
346 }
347 }
348
349 char *getcwd(char *buf, size_t size)
350 {
351 wchar_t path[MAX_PATH];
352 GetCurrentDirectory(MAX_PATH - 1, path);
353 convert_from_fs(path, buf, size);
354 return buf;
355 }
356
357 extern std::string _config_file;
358
359 void DetermineBasePaths(const char *exe)
360 {
361 extern std::array<std::string, NUM_SEARCHPATHS> _searchpaths;
362
363 wchar_t path[MAX_PATH];
364 #ifdef WITH_PERSONAL_DIR
365 if (SUCCEEDED(SHGetFolderPath(nullptr, CSIDL_PERSONAL, nullptr, SHGFP_TYPE_CURRENT, path))) {
366 std::string tmp(FS2OTTD(path));
367 AppendPathSeparator(tmp);
368 tmp += PERSONAL_DIR;
369 AppendPathSeparator(tmp);
370 _searchpaths[SP_PERSONAL_DIR] = tmp;
371
372 tmp += "content_download";
373 AppendPathSeparator(tmp);
374 _searchpaths[SP_AUTODOWNLOAD_PERSONAL_DIR] = tmp;
375 } else {
376 _searchpaths[SP_PERSONAL_DIR].clear();
377 }
378
379 if (SUCCEEDED(SHGetFolderPath(nullptr, CSIDL_COMMON_DOCUMENTS, nullptr, SHGFP_TYPE_CURRENT, path))) {
380 std::string tmp(FS2OTTD(path));
381 AppendPathSeparator(tmp);
382 tmp += PERSONAL_DIR;
383 AppendPathSeparator(tmp);
384 _searchpaths[SP_SHARED_DIR] = tmp;
385 } else {
386 _searchpaths[SP_SHARED_DIR].clear();
387 }
388 #else
389 _searchpaths[SP_PERSONAL_DIR].clear();
390 _searchpaths[SP_SHARED_DIR].clear();
391 #endif
392
393 if (_config_file.empty()) {
394 char cwd[MAX_PATH];
395 getcwd(cwd, lengthof(cwd));
396 std::string cwd_s(cwd);
397 AppendPathSeparator(cwd_s);
398 _searchpaths[SP_WORKING_DIR] = cwd_s;
399 } else {
400 /* Use the folder of the config file as working directory. */
401 wchar_t config_dir[MAX_PATH];
402 wcsncpy(path, convert_to_fs(_config_file, path, lengthof(path)), lengthof(path));
403 if (!GetFullPathName(path, lengthof(config_dir), config_dir, nullptr)) {
404 Debug(misc, 0, "GetFullPathName failed ({})", GetLastError());
405 _searchpaths[SP_WORKING_DIR].clear();
406 } else {
407 std::string tmp(FS2OTTD(config_dir));
408 auto pos = tmp.find_last_of(PATHSEPCHAR);
409 if (pos != std::string::npos) tmp.erase(pos + 1);
410
411 _searchpaths[SP_WORKING_DIR] = tmp;
412 }
413 }
414
415 if (!GetModuleFileName(nullptr, path, lengthof(path))) {
416 Debug(misc, 0, "GetModuleFileName failed ({})", GetLastError());
417 _searchpaths[SP_BINARY_DIR].clear();
418 } else {
419 wchar_t exec_dir[MAX_PATH];
420 wcsncpy(path, convert_to_fs(exe, path, lengthof(path)), lengthof(path));
421 if (!GetFullPathName(path, lengthof(exec_dir), exec_dir, nullptr)) {
422 Debug(misc, 0, "GetFullPathName failed ({})", GetLastError());
423 _searchpaths[SP_BINARY_DIR].clear();
424 } else {
425 std::string tmp(FS2OTTD(exec_dir));
426 auto pos = tmp.find_last_of(PATHSEPCHAR);
427 if (pos != std::string::npos) tmp.erase(pos + 1);
428
429 _searchpaths[SP_BINARY_DIR] = tmp;
430 }
431 }
432
433 _searchpaths[SP_INSTALLATION_DIR].clear();
434 _searchpaths[SP_APPLICATION_BUNDLE_DIR].clear();
435 }
436
437
438 std::optional<std::string> GetClipboardContents()
439 {
440 if (!IsClipboardFormatAvailable(CF_UNICODETEXT)) return std::nullopt;
441
442 OpenClipboard(nullptr);
443 HGLOBAL cbuf = GetClipboardData(CF_UNICODETEXT);
444
445 std::string result = FS2OTTD(static_cast<LPCWSTR>(GlobalLock(cbuf)));
446 GlobalUnlock(cbuf);
447 CloseClipboard();
448
449 if (result.empty()) return std::nullopt;
450 return result;
451 }
452
453
462 std::string FS2OTTD(const std::wstring &name)
463 {
464 int name_len = (name.length() >= INT_MAX) ? INT_MAX : (int)name.length();
465 int len = WideCharToMultiByte(CP_UTF8, 0, name.c_str(), name_len, nullptr, 0, nullptr, nullptr);
466 if (len <= 0) return std::string();
467 std::string utf8_buf(len, '\0'); // len includes terminating null
468 WideCharToMultiByte(CP_UTF8, 0, name.c_str(), name_len, utf8_buf.data(), len, nullptr, nullptr);
469 return utf8_buf;
470 }
471
479 std::wstring OTTD2FS(const std::string &name)
480 {
481 int name_len = (name.length() >= INT_MAX) ? INT_MAX : (int)name.length();
482 int len = MultiByteToWideChar(CP_UTF8, 0, name.c_str(), name_len, nullptr, 0);
483 if (len <= 0) return std::wstring();
484 std::wstring system_buf(len, L'\0'); // len includes terminating null
485 MultiByteToWideChar(CP_UTF8, 0, name.c_str(), name_len, system_buf.data(), len);
486 return system_buf;
487 }
488
489
498 char *convert_from_fs(const wchar_t *name, char *utf8_buf, size_t buflen)
499 {
500 /* Convert UTF-16 string to UTF-8. */
501 int len = WideCharToMultiByte(CP_UTF8, 0, name, -1, utf8_buf, (int)buflen, nullptr, nullptr);
502 if (len == 0) utf8_buf[0] = '\0';
503
504 return utf8_buf;
505 }
506
507
518 wchar_t *convert_to_fs(const std::string_view name, wchar_t *system_buf, size_t buflen)
519 {
520 int len = MultiByteToWideChar(CP_UTF8, 0, name.data(), (int)name.size(), system_buf, (int)buflen);
521 system_buf[len] = '\0';
522
523 return system_buf;
524 }
525
527 const char *GetCurrentLocale(const char *)
528 {
529 const LANGID userUiLang = GetUserDefaultUILanguage();
530 const LCID userUiLocale = MAKELCID(userUiLang, SORT_DEFAULT);
531
532 char lang[9], country[9];
533 if (GetLocaleInfoA(userUiLocale, LOCALE_SISO639LANGNAME, lang, lengthof(lang)) == 0 ||
534 GetLocaleInfoA(userUiLocale, LOCALE_SISO3166CTRYNAME, country, lengthof(country)) == 0) {
535 /* Unable to retrieve the locale. */
536 return nullptr;
537 }
538 /* Format it as 'en_us'. */
539 static char retbuf[6] = {lang[0], lang[1], '_', country[0], country[1], 0};
540 return retbuf;
541 }
542
543
544 static WCHAR _cur_iso_locale[16] = L"";
545
546 void Win32SetCurrentLocaleName(std::string iso_code)
547 {
548 /* Convert the iso code into the format that windows expects. */
549 if (iso_code == "zh_TW") {
550 iso_code = "zh-Hant";
551 } else if (iso_code == "zh_CN") {
552 iso_code = "zh-Hans";
553 } else {
554 /* Windows expects a '-' between language and country code, but we use a '_'. */
555 for (char &c : iso_code) {
556 if (c == '_') c = '-';
557 }
558 }
559
560 MultiByteToWideChar(CP_UTF8, 0, iso_code.c_str(), -1, _cur_iso_locale, lengthof(_cur_iso_locale));
561 }
562
563 int OTTDStringCompare(std::string_view s1, std::string_view s2)
564 {
565 typedef int (WINAPI *PFNCOMPARESTRINGEX)(LPCWSTR, DWORD, LPCWCH, int, LPCWCH, int, LPVOID, LPVOID, LPARAM);
566 static PFNCOMPARESTRINGEX _CompareStringEx = nullptr;
567 static bool first_time = true;
568
569 #ifndef SORT_DIGITSASNUMBERS
570 # define SORT_DIGITSASNUMBERS 0x00000008 // use digits as numbers sort method
571 #endif
572 #ifndef LINGUISTIC_IGNORECASE
573 # define LINGUISTIC_IGNORECASE 0x00000010 // linguistically appropriate 'ignore case'
574 #endif
575
576 if (first_time) {
577 static LibraryLoader _kernel32("Kernel32.dll");
578 _CompareStringEx = _kernel32.GetFunction("CompareStringEx");
579 first_time = false;
580 }
581
582 if (_CompareStringEx != nullptr) {
583 /* CompareStringEx takes UTF-16 strings, even in ANSI-builds. */
584 int len_s1 = MultiByteToWideChar(CP_UTF8, 0, s1.data(), (int)s1.size(), nullptr, 0);
585 int len_s2 = MultiByteToWideChar(CP_UTF8, 0, s2.data(), (int)s2.size(), nullptr, 0);
586
587 if (len_s1 != 0 && len_s2 != 0) {
588 std::wstring str_s1(len_s1, L'\0'); // len includes terminating null
589 std::wstring str_s2(len_s2, L'\0');
590
591 MultiByteToWideChar(CP_UTF8, 0, s1.data(), (int)s1.size(), str_s1.data(), len_s1);
592 MultiByteToWideChar(CP_UTF8, 0, s2.data(), (int)s2.size(), str_s2.data(), len_s2);
593
594 int result = _CompareStringEx(_cur_iso_locale, LINGUISTIC_IGNORECASE | SORT_DIGITSASNUMBERS, str_s1.c_str(), -1, str_s2.c_str(), -1, nullptr, nullptr, 0);
595 if (result != 0) return result;
596 }
597 }
598
599 wchar_t s1_buf[512], s2_buf[512];
600 convert_to_fs(s1, s1_buf, lengthof(s1_buf));
601 convert_to_fs(s2, s2_buf, lengthof(s2_buf));
602
603 return CompareString(MAKELCID(_current_language->winlangid, SORT_DEFAULT), NORM_IGNORECASE, s1_buf, -1, s2_buf, -1);
604 }
605
614 int Win32StringContains(const std::string_view str, const std::string_view value, bool case_insensitive)
615 {
616 typedef int (WINAPI *PFNFINDNLSSTRINGEX)(LPCWSTR, DWORD, LPCWSTR, int, LPCWSTR, int, LPINT, LPNLSVERSIONINFO, LPVOID, LPARAM);
617 static PFNFINDNLSSTRINGEX _FindNLSStringEx = nullptr;
618 static bool first_time = true;
619
620 if (first_time) {
621 static LibraryLoader _kernel32("Kernel32.dll");
622 _FindNLSStringEx = _kernel32.GetFunction("FindNLSStringEx");
623 first_time = false;
624 }
625
626 if (_FindNLSStringEx != nullptr) {
627 int len_str = MultiByteToWideChar(CP_UTF8, 0, str.data(), (int)str.size(), nullptr, 0);
628 int len_value = MultiByteToWideChar(CP_UTF8, 0, value.data(), (int)value.size(), nullptr, 0);
629
630 if (len_str != 0 && len_value != 0) {
631 std::wstring str_str(len_str, L'\0'); // len includes terminating null
632 std::wstring str_value(len_value, L'\0');
633
634 MultiByteToWideChar(CP_UTF8, 0, str.data(), (int)str.size(), str_str.data(), len_str);
635 MultiByteToWideChar(CP_UTF8, 0, value.data(), (int)value.size(), str_value.data(), len_value);
636
637 return _FindNLSStringEx(_cur_iso_locale, FIND_FROMSTART | (case_insensitive ? LINGUISTIC_IGNORECASE : 0), str_str.data(), -1, str_value.data(), -1, nullptr, nullptr, nullptr, 0) >= 0 ? 1 : 0;
638 }
639 }
640
641 return -1; // Failure indication.
642 }
643
644 #ifdef _MSC_VER
645 /* Based on code from MSDN: https://msdn.microsoft.com/en-us/library/xcb2z8hs.aspx */
646 const DWORD MS_VC_EXCEPTION = 0x406D1388;
647
648 PACK_N(struct THREADNAME_INFO {
649 DWORD dwType;
650 LPCSTR szName;
651 DWORD dwThreadID;
652 DWORD dwFlags;
653 }, 8);
654
658 void SetCurrentThreadName(const char *threadName)
659 {
660 THREADNAME_INFO info;
661 info.dwType = 0x1000;
662 info.szName = threadName;
663 info.dwThreadID = -1;
664 info.dwFlags = 0;
665
666 #pragma warning(push)
667 #pragma warning(disable: 6320 6322)
668 __try {
669 RaiseException(MS_VC_EXCEPTION, 0, sizeof(info) / sizeof(ULONG_PTR), (ULONG_PTR*)&info);
670 } __except (EXCEPTION_EXECUTE_HANDLER) {
671 }
672 #pragma warning(pop)
673 }
674 #else
675 void SetCurrentThreadName(const char *) {}
676 #endif
_left_button_down
bool _left_button_down
Is left mouse button pressed?
Definition: gfx.cpp:40
win32.h
SP_PERSONAL_DIR
@ SP_PERSONAL_DIR
Search in the personal directory.
Definition: fileio_type.h:138
Win32StringContains
int Win32StringContains(const std::string_view str, const std::string_view value, bool case_insensitive)
Search if a string is contained in another string using the current locale.
Definition: win32.cpp:614
SP_AUTODOWNLOAD_PERSONAL_DIR
@ SP_AUTODOWNLOAD_PERSONAL_DIR
Search within the autodownload directory located in the personal directory.
Definition: fileio_type.h:144
SP_INSTALLATION_DIR
@ SP_INSTALLATION_DIR
Search in the installation directory.
Definition: fileio_type.h:141
FileList
List of file information.
Definition: fios.h:88
Debug
#define Debug(category, level, format_string,...)
Ouptut a line of debugging information.
Definition: debug.h:37
convert_from_fs
char * convert_from_fs(const wchar_t *name, char *utf8_buf, size_t buflen)
Convert to OpenTTD's encoding from that of the environment in UNICODE.
Definition: win32.cpp:498
_searchpaths
std::array< std::string, NUM_SEARCHPATHS > _searchpaths
The search paths OpenTTD could search through.
Definition: fileio.cpp:58
FS2OTTD
std::string FS2OTTD(const std::wstring &name)
Convert to OpenTTD's encoding from a wide string.
Definition: win32.cpp:462
free
void free(const void *ptr)
Version of the standard free that accepts const pointers.
Definition: stdafx.h:382
FiosItem
Deals with finding savegames.
Definition: fios.h:79
SP_APPLICATION_BUNDLE_DIR
@ SP_APPLICATION_BUNDLE_DIR
Search within the application bundle.
Definition: fileio_type.h:142
SetCurrentThreadName
void SetCurrentThreadName(const char *)
Name the thread this function is called on for the debugger.
Definition: win32.cpp:675
_current_language
const LanguageMetadata * _current_language
The currently loaded language.
Definition: strings.cpp:54
lengthof
#define lengthof(array)
Return the length of an fixed size array.
Definition: stdafx.h:303
SP_SHARED_DIR
@ SP_SHARED_DIR
Search in the shared directory, like 'Shared Files' under Windows.
Definition: fileio_type.h:139
LibraryLoader
Definition: library_loader.h:13
GetCurrentLocale
const char * GetCurrentLocale(const char *)
Determine the current user's locale.
Definition: win32.cpp:527
SP_WORKING_DIR
@ SP_WORKING_DIR
Search in the working directory.
Definition: fileio_type.h:134
GetClipboardContents
std::optional< std::string > GetClipboardContents()
Try to retrieve the current clipboard contents.
Definition: win32.cpp:438
AppendPathSeparator
void AppendPathSeparator(std::string &buf)
Appends, if necessary, the path separator character to the end of the string.
Definition: fileio.cpp:378
_help_msg
static const char * _help_msg
Temporary pointer to get the help message to the window.
Definition: win32.cpp:285
SP_BINARY_DIR
@ SP_BINARY_DIR
Search in the directory where the binary resides.
Definition: fileio_type.h:140
DIR
Definition: win32.cpp:65
DetermineBasePaths
void DetermineBasePaths(const char *exe)
Determine the base (personal dir and game data dir) paths.
Definition: fileio.cpp:847
_config_file
std::string _config_file
Configuration file of OpenTTD.
Definition: settings.cpp:58
convert_to_fs
wchar_t * convert_to_fs(const std::string_view name, wchar_t *system_buf, size_t buflen)
Convert from OpenTTD's encoding to that of the environment in UNICODE.
Definition: win32.cpp:518
LibraryLoader::GetFunction
Function GetFunction(const std::string &symbol_name)
Get a function from a loaded library.
Definition: library_loader.h:78
HelpDialogFunc
static INT_PTR CALLBACK HelpDialogFunc(HWND wnd, UINT msg, WPARAM wParam, LPARAM)
Callback function to handle the window.
Definition: win32.cpp:288
LanguagePackHeader::winlangid
uint16_t winlangid
Windows language ID: Windows cannot and will not convert isocodes to something it can use to determin...
Definition: language.h:51
lastof
#define lastof(x)
Get the last element of an fixed size array.
Definition: stdafx.h:319
_left_button_clicked
bool _left_button_clicked
Is left mouse button clicked?
Definition: gfx.cpp:41
OTTD2FS
std::wstring OTTD2FS(const std::string &name)
Convert from OpenTTD's encoding to a wide string.
Definition: win32.cpp:479