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

Generated on Fri May 27 04:19:46 2011 for OpenTTD by  doxygen 1.6.1