00001
00002
00003
00004
00005
00006
00007
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>
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') { }
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
00089
00090
00091
00092
00093
00094
00095
00096
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);
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
00135
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) {
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
00153 d = NULL;
00154 errno = ENOENT;
00155 }
00156
00157 SetErrorMode(sem);
00158 return d;
00159 }
00160
00161 struct dirent *readdir(DIR *d)
00162 {
00163 DWORD prev_err = GetLastError();
00164
00165 if (d->at_first_entry) {
00166
00167 if (d->hFind == INVALID_HANDLE_VALUE) return NULL;
00168 d->at_first_entry = false;
00169 } else if (!FindNextFile(d->hFind, &d->fd)) {
00170 if (GetLastError() == ERROR_NO_MORE_FILES) SetLastError(prev_err);
00171 return NULL;
00172 }
00173
00174
00175
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';
00190 }
00191
00192 void FiosGetDrives()
00193 {
00194 #if defined(WINCE)
00195
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') { }
00213 }
00214 #endif
00215 }
00216
00217 bool FiosIsValidFile(const char *path, const struct dirent *ent, struct stat *sb)
00218 {
00219
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
00225
00226
00227
00228
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);
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);
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
00263 while (*line == ' ' || *line == '\t') line++;
00264
00265
00266 if (*line == '\0') break;
00267
00268
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
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
00307 #if !defined(__CYGWIN__)
00308
00309
00310 int fd = _open_osfhandle((intptr_t)hand, _O_TEXT);
00311 if (fd == -1) {
00312
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
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
00362
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
00391
00392
00393 _help_msg = str;
00394 DialogBox(GetModuleHandle(NULL), MAKEINTRESOURCE(101), NULL, HelpDialogFunc);
00395 } else {
00396 #if defined(UNICODE)
00397
00398
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];
00415 char *cmdline;
00416
00417 #if !defined(UNICODE)
00418 _codepage = GetACP();
00419 #endif
00420
00421 CrashLog::InitialiseCrashLog();
00422
00423 #if defined(UNICODE)
00424
00425 #if !defined(WINCE)
00426
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
00431
00432
00433 char cmdlinebuf[MAX_PATH];
00434 #endif
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);
00444 #endif
00445
00446
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
00459 GetModuleFileName(NULL, path, length);
00460
00461
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
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
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
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
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
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
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
00726
00727
00728
00729
00730
00731
00732 {
00733 DWORD ret;
00734 switch (csidl) {
00735 case CSIDL_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
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
00756 return NULL;
00757 }
00758
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 }