1 /* NetHack 3.6 winnt.c $NHDT-Date: 1524321419 2018/04/21 14:36:59 $ $NHDT-Branch: NetHack-3.6.0 $:$NHDT-Revision: 1.30 $ */
2 /* Copyright (c) NetHack PC Development Team 1993, 1994 */
3 /* NetHack may be freely redistributed. See license for details. */
6 * WIN32 system functions.
8 * Included in both console and window based clients on the windows platform.
10 * Initial Creation: Michael Allison - January 31/93
29 * The following WIN32 API routines are used in this file.
32 * GetVolumeInformation
40 /* runtime cursor display control switch */
41 boolean win32_cursorblink;
43 /* globals required within here */
44 HANDLE ffhandle = (HANDLE) 0;
46 extern int GUILaunched;
47 boolean getreturn_enabled;
50 typedef HWND(WINAPI *GETCONSOLEWINDOW)();
51 static HWND GetConsoleHandle(void);
52 static HWND GetConsoleHwnd(void);
53 #if !defined(TTY_GRAPHICS)
54 extern void NDECL(backsp);
56 int NDECL(windows_console_custom_nhgetch);
58 /* The function pointer nt_kbhit contains a kbhit() equivalent
59 * which varies depending on which window port is active.
60 * For the tty port it is tty_kbhit() [from nttty.c]
61 * For the win32 port it is win32_kbhit() [from winmain.c]
62 * It is initialized to point to def_kbhit [in here] for safety.
66 int (*nt_kbhit)() = def_kbhit;
71 /* Could not locate a WIN32 API call for this- MJA */
80 DWORD SectorsPerCluster = 0;
81 DWORD BytesPerSector = 0;
82 DWORD FreeClusters = 0;
83 DWORD TotalClusters = 0;
89 GetDiskFreeSpace(tmppath, &SectorsPerCluster, &BytesPerSector,
90 &FreeClusters, &TotalClusters);
91 return (long) (SectorsPerCluster * BytesPerSector * FreeClusters);
95 * Functions to get filenames using wildcards
103 ffhandle = (HANDLE) 0;
105 ffhandle = FindFirstFile(path, &ffd);
106 return (ffhandle == INVALID_HANDLE_VALUE) ? 0 : 1;
112 return FindNextFile(ffhandle, &ffd) ? 1 : 0;
118 return &ffd.cFileName[0];
125 if (findfirst(file)) {
126 return ((long) ffd.nFileSizeLow);
132 * Chdrive() changes the default drive.
140 if ((ptr = index(str, ':')) != (char *) 0) {
141 drive = toupper((uchar) *(ptr - 1));
142 _chdrive((drive - 'A') + 1);
152 status = GetVolumeInformation((LPTSTR) 0, (LPTSTR) 0, 0, (LPDWORD) 0,
153 &maxflen, (LPDWORD) 0, (LPTSTR) 0, 0);
167 * Strip out troublesome file system characters.
170 void nt_regularize(s) /* normalize file name */
173 register unsigned char *lp;
175 for (lp = s; *lp; lp++)
176 if (*lp == '?' || *lp == '"' || *lp == '\\' || *lp == '/'
177 || *lp == '>' || *lp == '<' || *lp == '*' || *lp == '|'
179 || *lp == ':' || (*lp > 127))
186 * This is used in nhlan.c to implement some of the LAN_FEATURES.
189 get_username(lan_username_size)
190 int *lan_username_size;
192 static TCHAR username_buffer[BUFSZ];
196 /* i gets updated with actual size */
197 status = GetUserName(username_buffer, &i);
199 username_buffer[i] = '\0';
201 Strcpy(username_buffer, "NetHack");
202 if (lan_username_size)
203 *lan_username_size = strlen(username_buffer);
204 return username_buffer;
210 char szFullPath[MAX_PATH] = "";
211 HMODULE hInst = NULL; /* NULL gets the filename of this module */
213 GetModuleFileName(hInst, szFullPath, sizeof(szFullPath));
214 return &szFullPath[0];
221 VA_DECL(const char *, s)
225 VA_INIT(s, const char *);
226 /* error() may get called before tty is initialized */
227 if (iflags.window_inited)
229 if (WINDOWPORT("tty")) {
231 (void) vsprintf(&buf[1], s, VA_ARGS);
235 (void) vsprintf(buf, s, VA_ARGS);
252 boolean is_tty = FALSE;
255 is_tty = WINDOWPORT("tty");
260 if (!iflags.window_inited)
263 msmsg("Execute debug breakpoint wizard?");
264 while ((ci = nhgetch()) != '\n') {
267 backsp(); /* \b is visible on NT console */
274 if (ci == 'y' || ci == 'n' || ci == 'Y' || ci == 'N') {
286 static char interjection_buf[INTERJECTION_TYPES][1024];
287 static int interjection[INTERJECTION_TYPES];
290 interject_assistance(num, interjection_type, ptr1, ptr2)
292 int interjection_type;
298 char *panicmsg = (char *) ptr1;
299 char *datadir = (char *) ptr2;
300 char *tempdir = nh_getenv("TEMP");
301 interjection_type = INTERJECT_PANIC;
302 interjection[INTERJECT_PANIC] = 1;
304 * ptr1 = the panic message about to be delivered.
305 * ptr2 = the directory prefix of the dungeon file
306 * that failed to open.
307 * Check to see if datadir matches tempdir or a
308 * common windows temp location. If it does, inform
309 * the user that they are probably trying to run the
310 * game from within their unzip utility, so the required
311 * files really don't exist at the location. Instruct
312 * them to unpack them first.
314 if (panicmsg && datadir) {
315 if (!strncmpi(datadir, "C:\\WINDOWS\\TEMP", 15)
316 || strstri(datadir, "TEMP")
317 || (tempdir && strstri(datadir, tempdir))) {
319 interjection_buf[INTERJECT_PANIC],
320 "\nOne common cause of this error is attempting to "
322 "the game by double-clicking on it while it is "
324 "inside an unzip utility.\n\n"
325 "You have to unzip the contents of the zip file into a\n"
326 "folder on your system, and then run \"NetHack.exe\" or "
328 "\"NetHackW.exe\" from there.\n\n"
329 "If that is not the situation, you are encouraged to\n"
330 "report the error as shown above.\n\n",
339 interject(interjection_type)
340 int interjection_type;
342 if (interjection_type >= 0 && interjection_type < INTERJECTION_TYPES)
343 msmsg(interjection_buf[interjection_type]);
346 #ifdef RUNTIME_PASTEBUF_SUPPORT
348 void port_insert_pastebuf(buf)
351 /* This implementation will utilize the windows clipboard
352 * to accomplish this.
366 /* last arg=0 means "tell me the size of the buffer that I need" */
367 rc = MultiByteToWideChar(GetConsoleOutputCP(), 0, buf, -1, w2, 0);
370 abytes = rc * sizeof(WCHAR);
371 w = (WCHAR *)alloc(abytes);
372 /* Housekeeping need: +free(w) */
374 rc = MultiByteToWideChar(GetConsoleOutputCP(), 0, buf, -1, w, rc);
379 if (!OpenClipboard(NULL)) {
383 /* Housekeeping need: +CloseClipboard(), free(w) */
387 /* allocate global mem obj to hold the text */
389 hglbCopy = GlobalAlloc(GMEM_MOVEABLE, abytes);
390 if (hglbCopy == NULL) {
395 /* Housekeeping need: +GlobalFree(hglbCopy), CloseClipboard(), free(w) */
397 lpwstrCopy = (LPWSTR)GlobalLock(hglbCopy);
398 /* Housekeeping need: +GlobalUnlock(hglbCopy), GlobalFree(hglbCopy),
399 CloseClipboard(), free(w) */
401 memcpy(lpwstrCopy, w, abytes);
402 GlobalUnlock(hglbCopy);
403 /* Housekeeping need: GlobalFree(hglbCopy), CloseClipboard(), free(w) */
405 /* put it on the clipboard */
406 hresult = SetClipboardData(CF_UNICODETEXT, hglbCopy);
408 raw_printf("Error copying to clipboard.\n");
409 GlobalFree(hglbCopy); /* only needed if clipboard didn't accept data */
411 /* Housekeeping need: CloseClipboard(), free(w) */
419 GetConsoleHandle(void)
421 HMODULE hMod = GetModuleHandle("kernel32.dll");
422 GETCONSOLEWINDOW pfnGetConsoleWindow =
423 (GETCONSOLEWINDOW) GetProcAddress(hMod, "GetConsoleWindow");
424 if (pfnGetConsoleWindow)
425 return pfnGetConsoleWindow();
427 return GetConsoleHwnd();
435 char OldTitle[1024], NewTitle[1024], TestTitle[1024];
437 /* Get current window title */
438 GetConsoleTitle(OldTitle, sizeof OldTitle);
440 (void) sprintf(NewTitle, "NETHACK%d/%d", GetTickCount(),
441 GetCurrentProcessId());
442 SetConsoleTitle(NewTitle);
444 GetConsoleTitle(TestTitle, sizeof TestTitle);
445 while (strcmp(TestTitle, NewTitle) != 0) {
448 GetConsoleTitle(TestTitle, sizeof TestTitle);
450 hwndFound = FindWindow(NULL, NewTitle);
451 SetConsoleTitle(OldTitle);
452 /* printf("%d iterations\n", iterations); */
458 #ifdef RUNTIME_PORT_ID
460 * _M_IX86 is Defined for x86 processors. This is not defined for x64
462 * _M_X64 is Defined for x64 processors.
463 * _M_IA64 is Defined for Itanium Processor Family 64-bit processors.
464 * _WIN64 is Defined for applications for Win64.
468 #define TARGET_PORT "x64"
471 #define TARGET_PORT "IA64"
476 #define TARGET_PORT "x86"
483 Strcpy(buf, TARGET_PORT);
486 #endif /* RUNTIME_PORT_ID */
488 /* nhassert_failed is called when an nhassert's condition is false */
489 void nhassert_failed(const char * exp, const char * file, int line)
492 _snprintf(message, sizeof(message),
493 "NHASSERT(%s) in '%s' at line %d\n", exp, file, line);
495 if (IsDebuggerPresent()) {
496 OutputDebugStringA(message);
500 // strip off the newline
501 message[strlen(message) - 1] = '\0';
509 /* Only if we started from the GUI, not the command prompt,
510 * we need to get one last return, so the score board does
511 * not vanish instantly after being created.
512 * GUILaunched is defined and set in nttty.c.
517 windowprocs = *get_safe_procs(1);
518 /* use our custom version which works
519 a little cleaner than the stdio one */
520 windowprocs.win_nhgetch = windows_console_custom_nhgetch;
522 if (getreturn_enabled)
531 windows_console_custom_nhgetch(VOID_ARGS)
543 if (!getreturn_enabled)
545 Sprintf(buf,"Hit <Enter> %s.", str);
551 /* nethack_enter_winnt() is called from main immediately after
552 initializing the window port */
553 void nethack_enter_winnt()
555 if (WINDOWPORT("tty"))
556 nethack_enter_nttty();
559 /* CP437 to Unicode mapping according to the Unicode Consortium */
560 const WCHAR cp437[256] = {
561 0x0020, 0x263A, 0x263B, 0x2665, 0x2666, 0x2663, 0x2660, 0x2022,
562 0x25D8, 0x25CB, 0x25D9, 0x2642, 0x2640, 0x266A, 0x266B, 0x263C,
563 0x25BA, 0x25C4, 0x2195, 0x203C, 0x00B6, 0x00A7, 0x25AC, 0x21A8,
564 0x2191, 0x2193, 0x2192, 0x2190, 0x221F, 0x2194, 0x25B2, 0x25BC,
565 0x0020, 0x0021, 0x0022, 0x0023, 0x0024, 0x0025, 0x0026, 0x0027,
566 0x0028, 0x0029, 0x002a, 0x002b, 0x002c, 0x002d, 0x002e, 0x002f,
567 0x0030, 0x0031, 0x0032, 0x0033, 0x0034, 0x0035, 0x0036, 0x0037,
568 0x0038, 0x0039, 0x003a, 0x003b, 0x003c, 0x003d, 0x003e, 0x003f,
569 0x0040, 0x0041, 0x0042, 0x0043, 0x0044, 0x0045, 0x0046, 0x0047,
570 0x0048, 0x0049, 0x004a, 0x004b, 0x004c, 0x004d, 0x004e, 0x004f,
571 0x0050, 0x0051, 0x0052, 0x0053, 0x0054, 0x0055, 0x0056, 0x0057,
572 0x0058, 0x0059, 0x005a, 0x005b, 0x005c, 0x005d, 0x005e, 0x005f,
573 0x0060, 0x0061, 0x0062, 0x0063, 0x0064, 0x0065, 0x0066, 0x0067,
574 0x0068, 0x0069, 0x006a, 0x006b, 0x006c, 0x006d, 0x006e, 0x006f,
575 0x0070, 0x0071, 0x0072, 0x0073, 0x0074, 0x0075, 0x0076, 0x0077,
576 0x0078, 0x0079, 0x007a, 0x007b, 0x007c, 0x007d, 0x007e, 0x2302,
577 0x00c7, 0x00fc, 0x00e9, 0x00e2, 0x00e4, 0x00e0, 0x00e5, 0x00e7,
578 0x00ea, 0x00eb, 0x00e8, 0x00ef, 0x00ee, 0x00ec, 0x00c4, 0x00c5,
579 0x00c9, 0x00e6, 0x00c6, 0x00f4, 0x00f6, 0x00f2, 0x00fb, 0x00f9,
580 0x00ff, 0x00d6, 0x00dc, 0x00a2, 0x00a3, 0x00a5, 0x20a7, 0x0192,
581 0x00e1, 0x00ed, 0x00f3, 0x00fa, 0x00f1, 0x00d1, 0x00aa, 0x00ba,
582 0x00bf, 0x2310, 0x00ac, 0x00bd, 0x00bc, 0x00a1, 0x00ab, 0x00bb,
583 0x2591, 0x2592, 0x2593, 0x2502, 0x2524, 0x2561, 0x2562, 0x2556,
584 0x2555, 0x2563, 0x2551, 0x2557, 0x255d, 0x255c, 0x255b, 0x2510,
585 0x2514, 0x2534, 0x252c, 0x251c, 0x2500, 0x253c, 0x255e, 0x255f,
586 0x255a, 0x2554, 0x2569, 0x2566, 0x2560, 0x2550, 0x256c, 0x2567,
587 0x2568, 0x2564, 0x2565, 0x2559, 0x2558, 0x2552, 0x2553, 0x256b,
588 0x256a, 0x2518, 0x250c, 0x2588, 0x2584, 0x258c, 0x2590, 0x2580,
589 0x03b1, 0x00df, 0x0393, 0x03c0, 0x03a3, 0x03c3, 0x00b5, 0x03c4,
590 0x03a6, 0x0398, 0x03a9, 0x03b4, 0x221e, 0x03c6, 0x03b5, 0x2229,
591 0x2261, 0x00b1, 0x2265, 0x2264, 0x2320, 0x2321, 0x00f7, 0x2248,
592 0x00b0, 0x2219, 0x00b7, 0x221a, 0x207f, 0x00b2, 0x25a0, 0x00a0
596 winos_ascii_to_wide_str(const unsigned char * src, WCHAR * dst, size_t dstLength)
599 while(i < dstLength - 1 && src[i] != 0)
600 dst[i++] = cp437[src[i]];
606 winos_ascii_to_wide(const unsigned char c)
611 BOOL winos_font_support_cp437(HFONT hFont)
613 BOOL allFound = FALSE;
614 HDC hdc = GetDC(NULL);
615 HFONT oldFont = SelectObject(hdc, hFont);
617 DWORD size = GetFontUnicodeRanges(hdc, NULL);
618 GLYPHSET *glyphSet = (GLYPHSET *) malloc(size);
620 if (glyphSet != NULL) {
621 GetFontUnicodeRanges(hdc, glyphSet);
624 for (int i = 0; i < 256 && allFound; i++) {
627 for (DWORD j = 0; j < glyphSet->cRanges && !found; j++) {
628 WCHAR first = glyphSet->ranges[j].wcLow;
629 WCHAR last = first + glyphSet->ranges[j].cGlyphs - 1;
631 if (wc >= first && wc <= last)
641 SelectObject(hdc, oldFont);
642 ReleaseDC(NULL, hdc);
648 windows_early_options(window_opt)
649 const char *window_opt;
652 * If you return 2, the game will exit before it begins.
653 * Return 1, to say the option parsed okay.
654 * Return 0, to say the option was bad.
657 if (match_optname(window_opt, "cursorblink", 5, FALSE)) {
658 win32_cursorblink = TRUE;
662 "-%swindows:cursorblink is the only supported option.\n");
668 * Add a backslash to any name not ending in /, \ or : There must
679 ptr = name + (strlen(name) - 1);
680 if (*ptr != '\\' && *ptr != '/' && *ptr != ':') {
687 #include <bcrypt.h> /* Windows Crypto Next Gen (CNG) */
689 #ifndef STATUS_SUCCESS
690 #define STATUS_SUCCESS 0
692 #ifndef STATUS_NOT_FOUND
693 #define STATUS_NOT_FOUND 0xC0000225
695 #ifndef STATUS_UNSUCCESSFUL
696 #define STATUS_UNSUCCESSFUL 0xC0000001
700 sys_random_seed(VOID_ARGS)
702 unsigned long ourseed = 0UL;
703 BCRYPT_ALG_HANDLE hRa = (BCRYPT_ALG_HANDLE) 0;
704 NTSTATUS status = STATUS_UNSUCCESSFUL;
705 boolean Plan_B = TRUE;
707 status = BCryptOpenAlgorithmProvider(&hRa, BCRYPT_RNG_ALGORITHM,
709 if (hRa && status == STATUS_SUCCESS) {
710 status = BCryptGenRandom(hRa, (PUCHAR) &ourseed,
711 (ULONG) sizeof ourseed, 0);
712 if (status == STATUS_SUCCESS) {
713 BCryptCloseAlgorithmProvider(hRa,0);
714 has_strong_rngseed = TRUE;
723 if (status == STATUS_NOT_FOUND)
724 emsg = "BCRYPT_RNG_ALGORITHM not avail, falling back";
726 emsg = "Other failure than algorithm not avail";
727 paniclog("sys_random_seed", emsg); /* leaves clue, doesn't exit */
728 (void) time(&datetime);
729 ourseed = (unsigned long) datetime;