# win32.cpp

Go to the documentation of this file.

    00001 /* $Id$ */
    00002
    00003 /*
    00004  * This file is part of OpenTTD.
    00005  * 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.
    00006  * 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.
    00007  * 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/>.
    00008  */
    00009
    00012 #include "../../stdafx.h"
    00013 #include "../../debug.h"
    00014 #include "../../gfx_func.h"
    00015 #include "../../textbuf_gui.h"
    00016 #include "../../fileio_func.h"
    00017 #include "../../fios.h"
    00018 #include <windows.h>
    00019 #include <fcntl.h>
    00020 #include <shlobj.h> /* SHGetFolderPath */
    00021 #include <Shellapi.h>
    00022 #include "win32.h"
    00023 #include "../../core/alloc_func.hpp"
    00024 #include "../../openttd.h"
    00025 #include "../../core/random_func.hpp"
    00026 #include "../../string_func.h"
    00027 #include "../../crashlog.h"
    00028 #include <errno.h>
    00029 #include <sys/stat.h>
    00030
    00031 static bool _has_console;
    00032 static bool _cursor_disable = true;
    00033 static bool _cursor_visible = true;
    00034
    00035 bool MyShowCursor(bool show, bool toggle)
    00036 {
    00037   if (toggle) _cursor_disable = !_cursor_disable;
    00038   if (_cursor_disable) return show;
    00039   if (_cursor_visible == show) return show;
    00040
    00041   _cursor_visible = show;
    00042   ShowCursor(show);
    00043
    00044   return !show;
    00045 }
    00046
    00052 bool LoadLibraryList(Function proc[], const char *dll)
    00053 {
    00054   while (*dll != '\0') {
    00055     HMODULE lib;
    00056     lib = LoadLibrary(MB_TO_WIDE(dll));
    00057
    00058     if (lib == NULL) return false;
    00059     for (;;) {
    00060       FARPROC p;
    00061
    00062       while (*dll++ != '\0') { /* Nothing */ }
    00063       if (*dll == '\0') break;
    00064 #if defined(WINCE)
    00065       p = GetProcAddress(lib, MB_TO_WIDE(dll));
    00066 #else
    00067       p = GetProcAddress(lib, dll);
    00068 #endif
    00069       if (p == NULL) return false;
    00070       *proc++ = (Function)p;
    00071     }
    00072     dll++;
    00073   }
    00074   return true;
    00075 }
    00076
    00077 void ShowOSErrorBox(const char *buf, bool system)
    00078 {
    00079   MyShowCursor(true);
    00080   MessageBox(GetActiveWindow(), MB_TO_WIDE(buf), _T("Error!"), MB_ICONSTOP);
    00081 }
    00082
    00083 void OSOpenBrowser(const char *url)
    00084 {
    00085   ShellExecute(GetActiveWindow(), _T("open"), MB_TO_WIDE(url), NULL, NULL, SW_SHOWNORMAL);
    00086 }
    00087
    00088 /* Code below for windows version of opendir/readdir/closedir copied and
    00089  * modified from Jan Wassenberg's GPL implementation posted over at
    00090  * http://www.gamedev.net/community/forums/topic.asp?topic_id=364584&whichpage=1&#2398903 */
    00091
    00092 /* suballocator - satisfies most requests with a reusable static instance.
    00093  * this avoids hundreds of alloc/free which would fragment the heap.
    00094  * To guarantee concurrency, we fall back to malloc if the instance is
    00095  * already in use (it's important to avoid surprises since this is such a
    00096  * low-level routine). */
    00097 static DIR _global_dir;
    00098 static LONG _global_dir_is_in_use = false;
    00099
    00100 static inline DIR *dir_calloc()
    00101 {
    00102   DIR *d;
    00103
    00104   if (InterlockedExchange(&_global_dir_is_in_use, true) == (LONG)true) {
    00105     d = CallocT<DIR>(1);
    00106   } else {
    00107     d = &_global_dir;
    00108     memset(d, 0, sizeof(*d));
    00109   }
    00110   return d;
    00111 }
    00112
    00113 static inline void dir_free(DIR *d)
    00114 {
    00115   if (d == &_global_dir) {
    00116     _global_dir_is_in_use = (LONG)false;
    00117   } else {
    00118     free(d);
    00119   }
    00120 }
    00121
    00122 DIR *opendir(const TCHAR *path)
    00123 {
    00124   DIR *d;
    00125   UINT sem = SetErrorMode(SEM_FAILCRITICALERRORS); // disable 'no-disk' message box
    00126   DWORD fa = GetFileAttributes(path);
    00127
    00128   if ((fa != INVALID_FILE_ATTRIBUTES) && (fa & FILE_ATTRIBUTE_DIRECTORY)) {
    00129     d = dir_calloc();
    00130     if (d != NULL) {
    00131       TCHAR search_path[MAX_PATH];
    00132       bool slash = path[_tcslen(path) - 1] == '\\';
    00133
    00134       /* build search path for FindFirstFile, try not to append additional slashes
    00135        * as it throws Win9x off its groove for root directories */
    00136       _sntprintf(search_path, lengthof(search_path), _T("%s%s*"), path, slash ? _T("") : _T("\\"));
    00137       *lastof(search_path) = '\0';
    00138       d->hFind = FindFirstFile(search_path, &d->fd);
    00139
    00140       if (d->hFind != INVALID_HANDLE_VALUE ||
    00141           GetLastError() == ERROR_NO_MORE_FILES) { // the directory is empty
    00142         d->ent.dir = d;
    00143         d->at_first_entry = true;
    00144       } else {
    00145         dir_free(d);
    00146         d = NULL;
    00147       }
    00148     } else {
    00149       errno = ENOMEM;
    00150     }
    00151   } else {
    00152     /* path not found or not a directory */
    00153     d = NULL;
    00154     errno = ENOENT;
    00155   }
    00156
    00157   SetErrorMode(sem); // restore previous setting
    00158   return d;
    00159 }
    00160
    00161 struct dirent *readdir(DIR *d)
    00162 {
    00163   DWORD prev_err = GetLastError(); // avoid polluting last error
    00164
    00165   if (d->at_first_entry) {
    00166     /* the directory was empty when opened */
    00167     if (d->hFind == INVALID_HANDLE_VALUE) return NULL;
    00168     d->at_first_entry = false;
    00169   } else if (!FindNextFile(d->hFind, &d->fd)) { // determine cause and bail
    00170     if (GetLastError() == ERROR_NO_MORE_FILES) SetLastError(prev_err);
    00171     return NULL;
    00172   }
    00173
    00174   /* This entry has passed all checks; return information about it.
    00175    * (note: d_name is a pointer; see struct dirent definition) */
    00176   d->ent.d_name = d->fd.cFileName;
    00177   return &d->ent;
    00178 }
    00179
    00180 int closedir(DIR *d)
    00181 {
    00182   FindClose(d->hFind);
    00183   dir_free(d);
    00184   return 0;
    00185 }
    00186
    00187 bool FiosIsRoot(const char *file)
    00188 {
    00189   return file[3] == '\0'; // C:\...
    00190 }
    00191
    00192 void FiosGetDrives()
    00193 {
    00194 #if defined(WINCE)
    00195   /* WinCE only knows one drive: / */
    00196   FiosItem *fios = _fios_items.Append();
    00197   fios->type = FIOS_TYPE_DRIVE;
    00198   fios->mtime = 0;
    00199   snprintf(fios->name, lengthof(fios->name), PATHSEP "");
    00200   strecpy(fios->title, fios->name, lastof(fios->title));
    00201 #else
    00202   TCHAR drives[256];
    00203   const TCHAR *s;
    00204
    00205   GetLogicalDriveStrings(lengthof(drives), drives);
    00206   for (s = drives; *s != '\0';) {
    00207     FiosItem *fios = _fios_items.Append();
    00208     fios->type = FIOS_TYPE_DRIVE;
    00209     fios->mtime = 0;
    00210     snprintf(fios->name, lengthof(fios->name),  "%c:", s[0] & 0xFF);
    00211     strecpy(fios->title, fios->name, lastof(fios->title));
    00212     while (*s++ != '\0') { /* Nothing */ }
    00213   }
    00214 #endif
    00215 }
    00216
    00217 bool FiosIsValidFile(const char *path, const struct dirent *ent, struct stat *sb)
    00218 {
    00219   /* hectonanoseconds between Windows and POSIX epoch */
    00220   static const int64 posix_epoch_hns = 0x019DB1DED53E8000LL;
    00221   const WIN32_FIND_DATA *fd = &ent->dir->fd;
    00222
    00223   sb->st_size  = ((uint64) fd->nFileSizeHigh << 32) + fd->nFileSizeLow;
    00224   /* UTC FILETIME to seconds-since-1970 UTC
    00225    * we just have to subtract POSIX epoch and scale down to units of seconds.
    00226    * http://www.gamedev.net/community/forums/topic.asp?topic_id=294070&whichpage=1&#1860504
    00227    * XXX - not entirely correct, since filetimes on FAT aren't UTC but local,
    00228    * this won't entirely be correct, but we use the time only for comparsion. */
    00229   sb->st_mtime = (time_t)((*(uint64*)&fd->ftLastWriteTime - posix_epoch_hns) / 1E7);
    00230   sb->st_mode  = (fd->dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)? S_IFDIR : S_IFREG;
    00231
    00232   return true;
    00233 }
    00234
    00235 bool FiosIsHiddenFile(const struct dirent *ent)
    00236 {
    00237   return (ent->dir->fd.dwFileAttributes & (FILE_ATTRIBUTE_HIDDEN | FILE_ATTRIBUTE_SYSTEM)) != 0;
    00238 }
    00239
    00240 bool FiosGetDiskFreeSpace(const char *path, uint64 *tot)
    00241 {
    00242   UINT sem = SetErrorMode(SEM_FAILCRITICALERRORS);  // disable 'no-disk' message box
    00243   bool retval = false;
    00244   TCHAR root[4];
    00245   DWORD spc, bps, nfc, tnc;
    00246
    00247   _sntprintf(root, lengthof(root), _T("%c:") _T(PATHSEP), path[0]);
    00248   if (tot != NULL && GetDiskFreeSpace(root, &spc, &bps, &nfc, &tnc)) {
    00249     *tot = ((spc * bps) * (uint64)nfc);
    00250     retval = true;
    00251   }
    00252
    00253   SetErrorMode(sem); // reset previous setting
    00254   return retval;
    00255 }
    00256
    00257 static int ParseCommandLine(char *line, char **argv, int max_argc)
    00258 {
    00259   int n = 0;
    00260
    00261   do {
    00262     /* skip whitespace */
    00263     while (*line == ' ' || *line == '\t') line++;
    00264
    00265     /* end? */
    00266     if (*line == '\0') break;
    00267
    00268     /* special handling when quoted */
    00269     if (*line == '"') {
    00270       argv[n++] = ++line;
    00271       while (*line != '"') {
    00272         if (*line == '\0') return n;
    00273         line++;
    00274       }
    00275     } else {
    00276       argv[n++] = line;
    00277       while (*line != ' ' && *line != '\t') {
    00278         if (*line == '\0') return n;
    00279         line++;
    00280       }
    00281     }
    00282     *line++ = '\0';
    00283   } while (n != max_argc);
    00284
    00285   return n;
    00286 }
    00287
    00288 void CreateConsole()
    00289 {
    00290 #if defined(WINCE)
    00291   /* WinCE doesn't support console stuff */
    00292 #else
    00293   HANDLE hand;
    00294   CONSOLE_SCREEN_BUFFER_INFO coninfo;
    00295
    00296   if (_has_console) return;
    00297   _has_console = true;
    00298
    00299   AllocConsole();
    00300
    00301   hand = GetStdHandle(STD_OUTPUT_HANDLE);
    00302   GetConsoleScreenBufferInfo(hand, &coninfo);
    00303   coninfo.dwSize.Y = 500;
    00304   SetConsoleScreenBufferSize(hand, coninfo.dwSize);
    00305
    00306   /* redirect unbuffered STDIN, STDOUT, STDERR to the console */
    00307 #if !defined(__CYGWIN__)
    00308
    00309   /* Check if we can open a handle to STDOUT. */
    00310   int fd = _open_osfhandle((intptr_t)hand, _O_TEXT);
    00311   if (fd == -1) {
    00312     /* Free everything related to the console. */
    00313     FreeConsole();
    00314     _has_console = false;
    00315     _close(fd);
    00316     CloseHandle(hand);
    00317
    00318     ShowInfo("Unable to open an output handle to the console. Check known-bugs.txt for details.");
    00319     return;
    00320   }
    00321
    00322   *stdout = *_fdopen(fd, "w");
    00323   *stdin = *_fdopen(_open_osfhandle((intptr_t)GetStdHandle(STD_INPUT_HANDLE), _O_TEXT), "r" );
    00324   *stderr = *_fdopen(_open_osfhandle((intptr_t)GetStdHandle(STD_ERROR_HANDLE), _O_TEXT), "w" );
    00325 #else
    00326   /* open_osfhandle is not in cygwin */
    00327   *stdout = *fdopen(1, "w" );
    00328   *stdin = *fdopen(0, "r" );
    00329   *stderr = *fdopen(2, "w" );
    00330 #endif
    00331
    00332   setvbuf(stdin, NULL, _IONBF, 0);
    00333   setvbuf(stdout, NULL, _IONBF, 0);
    00334   setvbuf(stderr, NULL, _IONBF, 0);
    00335 #endif
    00336 }
    00337
    00339 static const char *_help_msg;
    00340
    00342 static INT_PTR CALLBACK HelpDialogFunc(HWND wnd, UINT msg, WPARAM wParam, LPARAM lParam)
    00343 {
    00344   switch (msg) {
    00345     case WM_INITDIALOG: {
    00346       char help_msg[8192];
    00347       const char *p = _help_msg;
    00348       char *q = help_msg;
    00349       while (q != lastof(help_msg) && *p != '\0') {
    00350         if (*p == '\n') {
    00351           *q++ = '\r';
    00352           if (q == lastof(help_msg)) {
    00353             q[-1] = '\0';
    00354             break;
    00355           }
    00356         }
    00357         *q++ = *p++;
    00358       }
    00359       *q = '\0';
    00360 #if defined(UNICODE)
    00361       /* We need to put the text in a seperate buffer because the default
    00362        * buffer in MB_TO_WIDE might not be large enough (512 chars) */
    00363       wchar_t help_msgW[8192];
    00364 #endif
    00365       SetDlgItemText(wnd, 11, MB_TO_WIDE_BUFFER(help_msg, help_msgW, lengthof(help_msgW)));
    00366       SendDlgItemMessage(wnd, 11, WM_SETFONT, (WPARAM)GetStockObject(ANSI_FIXED_FONT), FALSE);
    00367     } return TRUE;
    00368
    00369     case WM_COMMAND:
    00370       if (wParam == 12) ExitProcess(0);
    00371       return TRUE;
    00372     case WM_CLOSE:
    00373       ExitProcess(0);
    00374   }
    00375
    00376   return FALSE;
    00377 }
    00378
    00379 void ShowInfo(const char *str)
    00380 {
    00381   if (_has_console) {
    00382     fprintf(stderr, "%s\n", str);
    00383   } else {
    00384     bool old;
    00385     ReleaseCapture();
    00386     _left_button_clicked = _left_button_down = false;
    00387
    00388     old = MyShowCursor(true);
    00389     if (strlen(str) > 2048) {
    00390       /* The minimum length of the help message is 2048. Other messages sent via
    00391        * ShowInfo are much shorter, or so long they need this way of displaying
    00392        * them anyway. */
    00393       _help_msg = str;
    00394       DialogBox(GetModuleHandle(NULL), MAKEINTRESOURCE(101), NULL, HelpDialogFunc);
    00395     } else {
    00396 #if defined(UNICODE)
    00397       /* We need to put the text in a seperate buffer because the default
    00398        * buffer in MB_TO_WIDE might not be large enough (512 chars) */
    00399       wchar_t help_msgW[8192];
    00400 #endif
    00401       MessageBox(GetActiveWindow(), MB_TO_WIDE_BUFFER(str, help_msgW, lengthof(help_msgW)), _T("OpenTTD"), MB_ICONINFORMATION | MB_OK);
    00402     }
    00403     MyShowCursor(old);
    00404   }
    00405 }
    00406
    00407 #if defined(WINCE)
    00408 int APIENTRY WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPTSTR lpCmdLine, int nCmdShow)
    00409 #else
    00410 int APIENTRY WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow)
    00411 #endif
    00412 {
    00413   int argc;
    00414   char *argv[64]; // max 64 command line arguments
    00415   char *cmdline;
    00416
    00417 #if !defined(UNICODE)
    00418   _codepage = GetACP(); // get system codepage as some kind of a default
    00419 #endif /* UNICODE */
    00420
    00421   CrashLog::InitialiseCrashLog();
    00422
    00423 #if defined(UNICODE)
    00424
    00425 #if !defined(WINCE)
    00426   /* Check if a win9x user started the win32 version */
    00427   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.");
    00428 #endif
    00429
    00430   /* For UNICODE we need to convert the commandline to char* _AND_
    00431    * save it because argv[] points into this buffer and thus needs to
    00432    * be available between subsequent calls to FS2OTTD() */
    00433   char cmdlinebuf[MAX_PATH];
    00434 #endif /* UNICODE */
    00435
    00436   cmdline = WIDE_TO_MB_BUFFER(GetCommandLine(), cmdlinebuf, lengthof(cmdlinebuf));
    00437
    00438 #if defined(_DEBUG)
    00439   CreateConsole();
    00440 #endif
    00441
    00442 #if !defined(WINCE)
    00443   _set_error_mode(_OUT_TO_MSGBOX); // force assertion output to messagebox
    00444 #endif
    00445
    00446   /* setup random seed to something quite random */
    00447   SetRandomSeed(GetTickCount());
    00448
    00449   argc = ParseCommandLine(cmdline, argv, lengthof(argv));
    00450
    00451   ttd_main(argc, argv);
    00452   return 0;
    00453 }
    00454
    00455 #if defined(WINCE)
    00456 void GetCurrentDirectoryW(int length, wchar_t *path)
    00457 {
    00458   /* Get the name of this module */
    00459   GetModuleFileName(NULL, path, length);
    00460
    00461   /* Remove the executable name, this we call CurrentDir */
    00462   wchar_t *pDest = wcsrchr(path, '\\');
    00463   if (pDest != NULL) {
    00464     int result = pDest - path + 1;
    00465     path[result] = '\0';
    00466   }
    00467 }
    00468 #endif
    00469
    00470 char *getcwd(char *buf, size_t size)
    00471 {
    00472 #if defined(WINCE)
    00473   TCHAR path[MAX_PATH];
    00474   GetModuleFileName(NULL, path, MAX_PATH);
    00475   convert_from_fs(path, buf, size);
    00476   /* GetModuleFileName returns dir with file, so remove everything behind latest '\\' */
    00477   char *p = strrchr(buf, '\\');
    00478   if (p != NULL) *p = '\0';
    00479 #elif defined(UNICODE)
    00480   TCHAR path[MAX_PATH];
    00481   GetCurrentDirectory(MAX_PATH - 1, path);
    00482   convert_from_fs(path, buf, size);
    00483 #else
    00484   GetCurrentDirectory(size, buf);
    00485 #endif
    00486   return buf;
    00487 }
    00488
    00489
    00490 void DetermineBasePaths(const char *exe)
    00491 {
    00492   char tmp[MAX_PATH];
    00493   TCHAR path[MAX_PATH];
    00494 #ifdef WITH_PERSONAL_DIR
    00495   SHGetFolderPath(NULL, CSIDL_PERSONAL, NULL, SHGFP_TYPE_CURRENT, path);
    00496   strecpy(tmp, WIDE_TO_MB_BUFFER(path, tmp, lengthof(tmp)), lastof(tmp));
    00497   AppendPathSeparator(tmp, MAX_PATH);
    00498   ttd_strlcat(tmp, PERSONAL_DIR, MAX_PATH);
    00499   AppendPathSeparator(tmp, MAX_PATH);
    00500   _searchpaths[SP_PERSONAL_DIR] = strdup(tmp);
    00501
    00502   SHGetFolderPath(NULL, CSIDL_COMMON_DOCUMENTS, NULL, SHGFP_TYPE_CURRENT, path);
    00503   strecpy(tmp, WIDE_TO_MB_BUFFER(path, tmp, lengthof(tmp)), lastof(tmp));
    00504   AppendPathSeparator(tmp, MAX_PATH);
    00505   ttd_strlcat(tmp, PERSONAL_DIR, MAX_PATH);
    00506   AppendPathSeparator(tmp, MAX_PATH);
    00507   _searchpaths[SP_SHARED_DIR] = strdup(tmp);
    00508 #else
    00509   _searchpaths[SP_PERSONAL_DIR] = NULL;
    00510   _searchpaths[SP_SHARED_DIR]   = NULL;
    00511 #endif
    00512
    00513   /* Get the path to working directory of OpenTTD */
    00514   getcwd(tmp, lengthof(tmp));
    00515   AppendPathSeparator(tmp, MAX_PATH);
    00516   _searchpaths[SP_WORKING_DIR] = strdup(tmp);
    00517
    00518   if (!GetModuleFileName(NULL, path, lengthof(path))) {
    00519     DEBUG(misc, 0, "GetModuleFileName failed (%lu)\n", GetLastError());
    00520     _searchpaths[SP_BINARY_DIR] = NULL;
    00521   } else {
    00522     TCHAR exec_dir[MAX_PATH];
    00523     _tcsncpy(path, MB_TO_WIDE_BUFFER(exe, path, lengthof(path)), lengthof(path));
    00524     if (!GetFullPathName(path, lengthof(exec_dir), exec_dir, NULL)) {
    00525       DEBUG(misc, 0, "GetFullPathName failed (%lu)\n", GetLastError());
    00526       _searchpaths[SP_BINARY_DIR] = NULL;
    00527     } else {
    00528       strecpy(tmp, WIDE_TO_MB_BUFFER(exec_dir, tmp, lengthof(tmp)), lastof(tmp));
    00529       char *s = strrchr(tmp, PATHSEPCHAR);
    00530       *(s + 1) = '\0';
    00531       _searchpaths[SP_BINARY_DIR] = strdup(tmp);
    00532     }
    00533   }
    00534
    00535   _searchpaths[SP_INSTALLATION_DIR]       = NULL;
    00536   _searchpaths[SP_APPLICATION_BUNDLE_DIR] = NULL;
    00537 }
    00538
    00539
    00540 bool GetClipboardContents(char *buffer, size_t buff_len)
    00541 {
    00542   HGLOBAL cbuf;
    00543   const char *ptr;
    00544
    00545   if (IsClipboardFormatAvailable(CF_UNICODETEXT)) {
    00546     OpenClipboard(NULL);
    00547     cbuf = GetClipboardData(CF_UNICODETEXT);
    00548
    00549     ptr = (const char*)GlobalLock(cbuf);
    00550     const char *ret = convert_from_fs((wchar_t*)ptr, buffer, buff_len);
    00551     GlobalUnlock(cbuf);
    00552     CloseClipboard();
    00553
    00554     if (*ret == '\0') return false;
    00555 #if !defined(UNICODE)
    00556   } else if (IsClipboardFormatAvailable(CF_TEXT)) {
    00557     OpenClipboard(NULL);
    00558     cbuf = GetClipboardData(CF_TEXT);
    00559
    00560     ptr = (const char*)GlobalLock(cbuf);
    00561     ttd_strlcpy(buffer, FS2OTTD(ptr), buff_len);
    00562
    00563     GlobalUnlock(cbuf);
    00564     CloseClipboard();
    00565 #endif /* UNICODE */
    00566   } else {
    00567     return false;
    00568   }
    00569
    00570   return true;
    00571 }
    00572
    00573
    00574 void CSleep(int milliseconds)
    00575 {
    00576   Sleep(milliseconds);
    00577 }
    00578
    00579
    00593 const char *FS2OTTD(const TCHAR *name)
    00594 {
    00595   static char utf8_buf[512];
    00596 #if defined(UNICODE)
    00597   return convert_from_fs(name, utf8_buf, lengthof(utf8_buf));
    00598 #else
    00599   char *s = utf8_buf;
    00600
    00601   for (; *name != '\0'; name++) {
    00602     wchar_t w;
    00603     int len = MultiByteToWideChar(_codepage, 0, name, 1, &w, 1);
    00604     if (len != 1) {
    00605       DEBUG(misc, 0, "[utf8] M2W error converting '%c'. Errno %lu", *name, GetLastError());
    00606       continue;
    00607     }
    00608
    00609     if (s + Utf8CharLen(w) >= lastof(utf8_buf)) break;
    00610     s += Utf8Encode(s, w);
    00611   }
    00612
    00613   *s = '\0';
    00614   return utf8_buf;
    00615 #endif /* UNICODE */
    00616 }
    00617
    00631 const TCHAR *OTTD2FS(const char *name)
    00632 {
    00633   static TCHAR system_buf[512];
    00634 #if defined(UNICODE)
    00635   return convert_to_fs(name, system_buf, lengthof(system_buf));
    00636 #else
    00637   char *s = system_buf;
    00638
    00639   for (WChar c; (c = Utf8Consume(&name)) != '\0';) {
    00640     if (s >= lastof(system_buf)) break;
    00641
    00642     char mb;
    00643     int len = WideCharToMultiByte(_codepage, 0, (wchar_t*)&c, 1, &mb, 1, NULL, NULL);
    00644     if (len != 1) {
    00645       DEBUG(misc, 0, "[utf8] W2M error converting '0x%X'. Errno %lu", c, GetLastError());
    00646       continue;
    00647     }
    00648
    00649     *s++ = mb;
    00650   }
    00651
    00652   *s = '\0';
    00653   return system_buf;
    00654 #endif /* UNICODE */
    00655 }
    00656
    00657
    00666 char *convert_from_fs(const wchar_t *name, char *utf8_buf, size_t buflen)
    00667 {
    00668   int len = WideCharToMultiByte(CP_UTF8, 0, name, -1, utf8_buf, (int)buflen, NULL, NULL);
    00669   if (len == 0) {
    00670     DEBUG(misc, 0, "[utf8] W2M error converting wide-string. Errno %lu", GetLastError());
    00671     utf8_buf[0] = '\0';
    00672   }
    00673
    00674   return utf8_buf;
    00675 }
    00676
    00677
    00687 wchar_t *convert_to_fs(const char *name, wchar_t *utf16_buf, size_t buflen)
    00688 {
    00689   int len = MultiByteToWideChar(CP_UTF8, 0, name, -1, utf16_buf, (int)buflen);
    00690   if (len == 0) {
    00691     DEBUG(misc, 0, "[utf8] M2W error converting '%s'. Errno %lu", name, GetLastError());
    00692     utf16_buf[0] = '\0';
    00693   }
    00694
    00695   return utf16_buf;
    00696 }
    00697
    00704 HRESULT OTTDSHGetFolderPath(HWND hwnd, int csidl, HANDLE hToken, DWORD dwFlags, LPTSTR pszPath)
    00705 {
    00706   static HRESULT (WINAPI *SHGetFolderPath)(HWND, int, HANDLE, DWORD, LPTSTR) = NULL;
    00707   static bool first_time = true;
    00708
    00709   /* We only try to load the library one time; if it fails, it fails */
    00710   if (first_time) {
    00711 #if defined(UNICODE)
    00712 # define W(x) x "W"
    00713 #else
    00714 # define W(x) x "A"
    00715 #endif
    00716     if (!LoadLibraryList((Function*)&SHGetFolderPath, "SHFolder.dll\0" W("SHGetFolderPath") "\0\0")) {
    00717       DEBUG(misc, 0, "Unable to load " W("SHGetFolderPath") "from SHFolder.dll");
    00718     }
    00719 #undef W
    00720     first_time = false;
    00721   }
    00722
    00723   if (SHGetFolderPath != NULL) return SHGetFolderPath(hwnd, csidl, hToken, dwFlags, pszPath);
    00724
    00725   /* SHGetFolderPath doesn't exist, try a more conservative approach,
    00726    * eg environment variables. This is only included for legacy modes
    00727    * MSDN says: that 'pszPath' is a "Pointer to a null-terminated string of
    00728    * length MAX_PATH which will receive the path" so let's assume that
    00729    * Windows 95 with Internet Explorer 5.0, Windows 98 with Internet Explorer 5.0,
    00730    * Windows 98 Second Edition (SE), Windows NT 4.0 with Internet Explorer 5.0,
    00731    * Windows NT 4.0 with Service Pack 4 (SP4) */
    00732   {
    00733     DWORD ret;
    00734     switch (csidl) {
    00735       case CSIDL_FONTS: // Get the system font path, eg %WINDIR%\Fonts
    00736         ret = GetEnvironmentVariable(_T("WINDIR"), pszPath, MAX_PATH);
    00737         if (ret == 0) break;
    00738         _tcsncat(pszPath, _T("\\Fonts"), MAX_PATH);
    00739
    00740         return (HRESULT)0;
    00741
    00742       /* XXX - other types to go here when needed... */
    00743     }
    00744   }
    00745
    00746   return E_INVALIDARG;
    00747 }
    00748
    00750 const char *GetCurrentLocale(const char *)
    00751 {
    00752   char lang[9], country[9];
    00753   if (GetLocaleInfoA(LOCALE_USER_DEFAULT, LOCALE_SISO639LANGNAME, lang, lengthof(lang)) == 0 ||
    00754       GetLocaleInfoA(LOCALE_USER_DEFAULT, LOCALE_SISO3166CTRYNAME, country, lengthof(country)) == 0) {
    00755     /* Unable to retrieve the locale. */
    00756     return NULL;
    00757   }
    00758   /* Format it as 'en_us'. */
    00759   static char retbuf[6] = {lang[0], lang[1], '_', country[0], country[1], 0};
    00760   return retbuf;
    00761 }
    00762
    00763 uint GetCPUCoreCount()
    00764 {
    00765   SYSTEM_INFO info;
    00766
    00767   GetSystemInfo(&info);
    00768   return info.dwNumberOfProcessors;
    00769 }