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