12 #include "../../stdafx.h"
13 #include "../../debug.h"
14 #include "../../gfx_func.h"
15 #include "../../textbuf_gui.h"
16 #include "../../fileio_func.h"
23 #include "../../fios.h"
24 #include "../../core/alloc_func.hpp"
25 #include "../../openttd.h"
26 #include "../../core/random_func.hpp"
27 #include "../../string_func.h"
28 #include "../../crashlog.h"
33 #include "../../safeguards.h"
37 static bool _has_console;
38 static bool _cursor_disable =
true;
39 static bool _cursor_visible =
true;
41 bool MyShowCursor(
bool show,
bool toggle)
43 if (toggle) _cursor_disable = !_cursor_disable;
44 if (_cursor_disable)
return show;
45 if (_cursor_visible == show)
return show;
47 _cursor_visible = show;
60 while (*dll !=
'\0') {
62 lib = LoadLibrary(MB_TO_WIDE(dll));
64 if (lib == NULL)
return false;
68 while (*dll++ !=
'\0') { }
69 if (*dll ==
'\0')
break;
71 p = GetProcAddress(lib, MB_TO_WIDE(dll));
73 p = GetProcAddress(lib, dll);
75 if (p == NULL)
return false;
76 *proc++ = (Function)p;
83 void ShowOSErrorBox(
const char *buf,
bool system)
86 MessageBox(GetActiveWindow(),
OTTD2FS(buf), _T(
"Error!"), MB_ICONSTOP);
89 void OSOpenBrowser(
const char *url)
91 ShellExecute(GetActiveWindow(), _T(
"open"),
OTTD2FS(url), NULL, NULL, SW_SHOWNORMAL);
116 static DIR _global_dir;
117 static LONG _global_dir_is_in_use =
false;
119 static inline DIR *dir_calloc()
123 if (InterlockedExchange(&_global_dir_is_in_use,
true) == (LONG)
true) {
127 memset(d, 0,
sizeof(*d));
132 static inline void dir_free(
DIR *d)
134 if (d == &_global_dir) {
135 _global_dir_is_in_use = (LONG)
false;
141 DIR *opendir(
const TCHAR *path)
144 UINT sem = SetErrorMode(SEM_FAILCRITICALERRORS);
145 DWORD fa = GetFileAttributes(path);
147 if ((fa != INVALID_FILE_ATTRIBUTES) && (fa & FILE_ATTRIBUTE_DIRECTORY)) {
150 TCHAR search_path[MAX_PATH];
151 bool slash = path[_tcslen(path) - 1] ==
'\\';
155 _sntprintf(search_path,
lengthof(search_path), _T(
"%s%s*"), path, slash ? _T(
"") : _T(
"\\"));
156 *
lastof(search_path) =
'\0';
157 d->hFind = FindFirstFile(search_path, &d->fd);
159 if (d->hFind != INVALID_HANDLE_VALUE ||
160 GetLastError() == ERROR_NO_MORE_FILES) {
162 d->at_first_entry =
true;
180 struct dirent *readdir(
DIR *d)
182 DWORD prev_err = GetLastError();
184 if (d->at_first_entry) {
186 if (d->hFind == INVALID_HANDLE_VALUE)
return NULL;
187 d->at_first_entry =
false;
188 }
else if (!FindNextFile(d->hFind, &d->fd)) {
189 if (GetLastError() == ERROR_NO_MORE_FILES) SetLastError(prev_err);
195 d->ent.d_name = d->fd.cFileName;
206 bool FiosIsRoot(
const char *file)
208 return file[3] ==
'\0';
211 void FiosGetDrives(
FileList &file_list)
216 fios->type = FIOS_TYPE_DRIVE;
224 GetLogicalDriveStrings(
lengthof(drives), drives);
225 for (s = drives; *s !=
'\0';) {
227 fios->type = FIOS_TYPE_DRIVE;
231 while (*s++ !=
'\0') { }
236 bool FiosIsValidFile(
const char *path,
const struct dirent *ent,
struct stat *sb)
239 static const int64 posix_epoch_hns = 0x019DB1DED53E8000LL;
240 const WIN32_FIND_DATA *fd = &ent->dir->fd;
242 sb->st_size = ((uint64) fd->nFileSizeHigh << 32) + fd->nFileSizeLow;
248 sb->st_mtime = (time_t)((*(
const uint64*)&fd->ftLastWriteTime - posix_epoch_hns) / 1E7);
249 sb->st_mode = (fd->dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)? S_IFDIR : S_IFREG;
254 bool FiosIsHiddenFile(
const struct dirent *ent)
256 return (ent->dir->fd.dwFileAttributes & (FILE_ATTRIBUTE_HIDDEN | FILE_ATTRIBUTE_SYSTEM)) != 0;
259 bool FiosGetDiskFreeSpace(
const char *path, uint64 *tot)
261 UINT sem = SetErrorMode(SEM_FAILCRITICALERRORS);
264 DWORD spc, bps, nfc, tnc;
266 _sntprintf(root,
lengthof(root), _T(
"%c:") _T(PATHSEP), path[0]);
267 if (tot != NULL && GetDiskFreeSpace(root, &spc, &bps, &nfc, &tnc)) {
268 *tot = ((spc * bps) * (uint64)nfc);
276 static int ParseCommandLine(
char *line,
char **argv,
int max_argc)
282 while (*line ==
' ' || *line ==
'\t') line++;
285 if (*line ==
'\0')
break;
290 while (*line !=
'"') {
291 if (*line ==
'\0')
return n;
296 while (*line !=
' ' && *line !=
'\t') {
297 if (*line ==
'\0')
return n;
302 }
while (n != max_argc);
313 CONSOLE_SCREEN_BUFFER_INFO coninfo;
315 if (_has_console)
return;
320 hand = GetStdHandle(STD_OUTPUT_HANDLE);
321 GetConsoleScreenBufferInfo(hand, &coninfo);
322 coninfo.dwSize.Y = 500;
323 SetConsoleScreenBufferSize(hand, coninfo.dwSize);
326 #if !defined(__CYGWIN__)
329 int fd = _open_osfhandle((intptr_t)hand, _O_TEXT);
333 _has_console =
false;
337 ShowInfo(
"Unable to open an output handle to the console. Check known-bugs.txt for details.");
341 #if defined(_MSC_VER) && _MSC_VER >= 1900
342 freopen(
"CONOUT$",
"a", stdout);
343 freopen(
"CONIN$",
"r", stdin);
344 freopen(
"CONOUT$",
"a", stderr);
346 *stdout = *_fdopen(fd,
"w");
347 *stdin = *_fdopen(_open_osfhandle((intptr_t)GetStdHandle(STD_INPUT_HANDLE), _O_TEXT),
"r" );
348 *stderr = *_fdopen(_open_osfhandle((intptr_t)GetStdHandle(STD_ERROR_HANDLE), _O_TEXT),
"w" );
353 *stdout = *fdopen(1,
"w" );
354 *stdin = *fdopen(0,
"r" );
355 *stderr = *fdopen(2,
"w" );
358 setvbuf(stdin, NULL, _IONBF, 0);
359 setvbuf(stdout, NULL, _IONBF, 0);
360 setvbuf(stderr, NULL, _IONBF, 0);
368 static INT_PTR CALLBACK
HelpDialogFunc(HWND wnd, UINT msg, WPARAM wParam, LPARAM lParam)
371 case WM_INITDIALOG: {
375 while (q !=
lastof(help_msg) && *p !=
'\0') {
378 if (q ==
lastof(help_msg)) {
388 TCHAR help_msg_buf[8192];
390 SendDlgItemMessage(wnd, 11, WM_SETFONT, (WPARAM)GetStockObject(ANSI_FIXED_FONT), FALSE);
394 if (wParam == 12) ExitProcess(0);
403 void ShowInfo(
const char *str)
406 fprintf(stderr,
"%s\n", str);
412 old = MyShowCursor(
true);
413 if (strlen(str) > 2048) {
418 DialogBox(GetModuleHandle(NULL), MAKEINTRESOURCE(101), NULL,
HelpDialogFunc);
422 TCHAR help_msg_buf[8192];
423 MessageBox(GetActiveWindow(),
convert_to_fs(str, help_msg_buf,
lengthof(help_msg_buf)), _T(
"OpenTTD"), MB_ICONINFORMATION | MB_OK);
430 int APIENTRY WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPTSTR lpCmdLine,
int nCmdShow)
432 int APIENTRY WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine,
int nCmdShow)
440 #if defined(UNICODE) && !defined(WINCE)
442 if (
HasBit(GetVersion(), 31))
usererror(
"This version of OpenTTD doesn't run on windows 95/98/ME.\nPlease download the win9x binary and try again.");
455 _set_error_mode(_OUT_TO_MSGBOX);
461 argc = ParseCommandLine(cmdline, argv,
lengthof(argv));
472 void GetCurrentDirectoryW(
int length,
wchar_t *path)
475 GetModuleFileName(NULL, path, length);
478 wchar_t *pDest = wcsrchr(path,
'\\');
480 int result = pDest - path + 1;
486 char *getcwd(
char *buf,
size_t size)
489 TCHAR path[MAX_PATH];
490 GetModuleFileName(NULL, path, MAX_PATH);
493 char *p = strrchr(buf,
'\\');
494 if (p != NULL) *p =
'\0';
496 TCHAR path[MAX_PATH];
497 GetCurrentDirectory(MAX_PATH - 1, path);
507 TCHAR path[MAX_PATH];
508 #ifdef WITH_PERSONAL_DIR
509 if (SUCCEEDED(
OTTDSHGetFolderPath(NULL, CSIDL_PERSONAL, NULL, SHGFP_TYPE_CURRENT, path))) {
519 if (SUCCEEDED(
OTTDSHGetFolderPath(NULL, CSIDL_COMMON_DOCUMENTS, NULL, SHGFP_TYPE_CURRENT, path))) {
538 if (!GetModuleFileName(NULL, path,
lengthof(path))) {
539 DEBUG(misc, 0,
"GetModuleFileName failed (%lu)\n", GetLastError());
542 TCHAR exec_dir[MAX_PATH];
544 if (!GetFullPathName(path,
lengthof(exec_dir), exec_dir, NULL)) {
545 DEBUG(misc, 0,
"GetFullPathName failed (%lu)\n", GetLastError());
549 char *s = strrchr(tmp, PATHSEPCHAR);
565 if (IsClipboardFormatAvailable(CF_UNICODETEXT)) {
567 cbuf = GetClipboardData(CF_UNICODETEXT);
569 ptr = (
const char*)GlobalLock(cbuf);
570 int out_len = WideCharToMultiByte(CP_UTF8, 0, (LPCWSTR)ptr, -1, buffer, (last - buffer) + 1, NULL, NULL);
574 if (out_len == 0)
return false;
575 #if !defined(UNICODE)
576 }
else if (IsClipboardFormatAvailable(CF_TEXT)) {
578 cbuf = GetClipboardData(CF_TEXT);
580 ptr = (
const char*)GlobalLock(cbuf);
594 void CSleep(
int milliseconds)
615 static char utf8_buf[512];
631 const TCHAR *
OTTD2FS(
const char *name,
bool console_cp)
633 static TCHAR system_buf[512];
649 const WCHAR *wide_buf = name;
652 int wide_len = MultiByteToWideChar(CP_ACP, 0, name, -1, NULL, 0);
658 WCHAR *wide_buf =
AllocaM(WCHAR, wide_len);
659 MultiByteToWideChar(CP_ACP, 0, name, -1, wide_buf, wide_len);
663 int len = WideCharToMultiByte(CP_UTF8, 0, wide_buf, -1, utf8_buf, (
int)buflen, NULL, NULL);
664 if (len == 0) utf8_buf[0] =
'\0';
680 TCHAR *
convert_to_fs(
const char *name, TCHAR *system_buf,
size_t buflen,
bool console_cp)
683 int len = MultiByteToWideChar(CP_UTF8, 0, name, -1, system_buf, (
int)buflen);
684 if (len == 0) system_buf[0] =
'\0';
686 int len = MultiByteToWideChar(CP_UTF8, 0, name, -1, NULL, 0);
688 system_buf[0] =
'\0';
692 WCHAR *wide_buf =
AllocaM(WCHAR, len);
693 MultiByteToWideChar(CP_UTF8, 0, name, -1, wide_buf, len);
695 len = WideCharToMultiByte(console_cp ? CP_OEMCP : CP_ACP, 0, wide_buf, len, system_buf, (
int)buflen, NULL, NULL);
696 if (len == 0) system_buf[0] =
'\0';
710 static HRESULT (WINAPI *SHGetFolderPath)(HWND, int, HANDLE, DWORD, LPTSTR) = NULL;
711 static bool first_time =
true;
721 if (!
LoadLibraryList((Function*)&SHGetFolderPath,
"shell32.dll\0" W(
"SHGetFolderPath")
"\0\0")) {
722 if (!
LoadLibraryList((Function*)&SHGetFolderPath,
"SHFolder.dll\0" W(
"SHGetFolderPath")
"\0\0")) {
723 DEBUG(misc, 0,
"Unable to load " W(
"SHGetFolderPath")
"from either shell32.dll or SHFolder.dll");
730 if (SHGetFolderPath != NULL)
return SHGetFolderPath(hwnd, csidl, hToken, dwFlags, pszPath);
743 ret = GetEnvironmentVariable(_T(
"WINDIR"), pszPath, MAX_PATH);
745 _tcsncat(pszPath, _T(
"\\Fonts"), MAX_PATH);
750 case CSIDL_COMMON_DOCUMENTS: {
752 if (RegOpenKeyEx(csidl == CSIDL_PERSONAL ? HKEY_CURRENT_USER : HKEY_LOCAL_MACHINE, REGSTR_PATH_SPECIAL_FOLDERS, 0, KEY_READ, &key) != ERROR_SUCCESS)
break;
753 DWORD len = MAX_PATH;
754 ret = RegQueryValueEx(key, csidl == CSIDL_PERSONAL ? _T(
"Personal") : _T(
"Common Documents"), NULL, NULL, (LPBYTE)pszPath, &len);
756 if (ret == ERROR_SUCCESS)
return (HRESULT)0;
770 char lang[9], country[9];
771 if (GetLocaleInfoA(LOCALE_USER_DEFAULT, LOCALE_SISO639LANGNAME, lang,
lengthof(lang)) == 0 ||
772 GetLocaleInfoA(LOCALE_USER_DEFAULT, LOCALE_SISO3166CTRYNAME, country,
lengthof(country)) == 0) {
777 static char retbuf[6] = {lang[0], lang[1],
'_', country[0], country[1], 0};
785 GetSystemInfo(&info);
786 return info.dwNumberOfProcessors;
791 const DWORD MS_VC_EXCEPTION = 0x406D1388;
804 void SetWin32ThreadName(DWORD dwThreadID,
const char* threadName)
806 THREADNAME_INFO info;
807 info.dwType = 0x1000;
808 info.szName = threadName;
809 info.dwThreadID = dwThreadID;
812 #pragma warning(push)
813 #pragma warning(disable: 6320 6322)
815 RaiseException(MS_VC_EXCEPTION, 0,
sizeof(info) /
sizeof(ULONG_PTR), (ULONG_PTR*)&info);
816 } __except (EXCEPTION_EXECUTE_HANDLER) {