OSDN Git Service

upgrade to 3.6.2
[jnethack/source.git] / sys / winnt / winnt.c
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. */
4
5 /*
6  *  WIN32 system functions.
7  * 
8  *  Included in both console and window based clients on the windows platform.
9  *
10  *  Initial Creation: Michael Allison - January 31/93
11  *
12  */
13
14 #include "winos.h"
15
16 #define NEED_VARARGS
17 #include "hack.h"
18 #include <dos.h>
19 #ifndef __BORLANDC__
20 #include <direct.h>
21 #endif
22 #include <ctype.h>
23 #ifdef TTY_GRAPHICS
24 #include "wintty.h"
25 #endif
26 #ifdef WIN32
27
28 /*
29  * The following WIN32 API routines are used in this file.
30  *
31  * GetDiskFreeSpace
32  * GetVolumeInformation
33  * GetUserName
34  * FindFirstFile
35  * FindNextFile
36  * FindClose
37  *
38  */
39
40 /* runtime cursor display control switch */
41 boolean win32_cursorblink;
42
43 /* globals required within here */
44 HANDLE ffhandle = (HANDLE) 0;
45 WIN32_FIND_DATA ffd;
46 extern int GUILaunched;
47 boolean getreturn_enabled;
48 int redirect_stdout;
49
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);
55 #endif
56 int NDECL(windows_console_custom_nhgetch);
57
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.
63  */
64
65 int def_kbhit(void);
66 int (*nt_kbhit)() = def_kbhit;
67
68 char
69 switchar()
70 {
71     /* Could not locate a WIN32 API call for this- MJA */
72     return '-';
73 }
74
75 long
76 freediskspace(path)
77 char *path;
78 {
79     char tmppath[4];
80     DWORD SectorsPerCluster = 0;
81     DWORD BytesPerSector = 0;
82     DWORD FreeClusters = 0;
83     DWORD TotalClusters = 0;
84
85     tmppath[0] = *path;
86     tmppath[1] = ':';
87     tmppath[2] = '\\';
88     tmppath[3] = '\0';
89     GetDiskFreeSpace(tmppath, &SectorsPerCluster, &BytesPerSector,
90                      &FreeClusters, &TotalClusters);
91     return (long) (SectorsPerCluster * BytesPerSector * FreeClusters);
92 }
93
94 /*
95  * Functions to get filenames using wildcards
96  */
97 int
98 findfirst(path)
99 char *path;
100 {
101     if (ffhandle) {
102         FindClose(ffhandle);
103         ffhandle = (HANDLE) 0;
104     }
105     ffhandle = FindFirstFile(path, &ffd);
106     return (ffhandle == INVALID_HANDLE_VALUE) ? 0 : 1;
107 }
108
109 int
110 findnext()
111 {
112     return FindNextFile(ffhandle, &ffd) ? 1 : 0;
113 }
114
115 char *
116 foundfile_buffer()
117 {
118     return &ffd.cFileName[0];
119 }
120
121 long
122 filesize(file)
123 char *file;
124 {
125     if (findfirst(file)) {
126         return ((long) ffd.nFileSizeLow);
127     } else
128         return -1L;
129 }
130
131 /*
132  * Chdrive() changes the default drive.
133  */
134 void
135 chdrive(str)
136 char *str;
137 {
138     char *ptr;
139     char drive;
140     if ((ptr = index(str, ':')) != (char *) 0) {
141         drive = toupper((uchar) *(ptr - 1));
142         _chdrive((drive - 'A') + 1);
143     }
144 }
145
146 static int
147 max_filename()
148 {
149     DWORD maxflen;
150     int status = 0;
151
152     status = GetVolumeInformation((LPTSTR) 0, (LPTSTR) 0, 0, (LPDWORD) 0,
153                                   &maxflen, (LPDWORD) 0, (LPTSTR) 0, 0);
154     if (status)
155         return maxflen;
156     else
157         return 0;
158 }
159
160 int
161 def_kbhit()
162 {
163     return 0;
164 }
165
166 /*
167  * Strip out troublesome file system characters.
168  */
169
170 void nt_regularize(s) /* normalize file name */
171 register char *s;
172 {
173     register unsigned char *lp;
174
175     for (lp = s; *lp; lp++)
176         if (*lp == '?' || *lp == '"' || *lp == '\\' || *lp == '/'
177             || *lp == '>' || *lp == '<' || *lp == '*' || *lp == '|'
178 /*JP
179             || *lp == ':' || (*lp > 127))
180 */
181             || *lp == ':')
182             *lp = '_';
183 }
184
185 /*
186  * This is used in nhlan.c to implement some of the LAN_FEATURES.
187  */
188 char *
189 get_username(lan_username_size)
190 int *lan_username_size;
191 {
192     static TCHAR username_buffer[BUFSZ];
193     unsigned int status;
194     DWORD i = BUFSZ - 1;
195
196     /* i gets updated with actual size */
197     status = GetUserName(username_buffer, &i);
198     if (status)
199         username_buffer[i] = '\0';
200     else
201         Strcpy(username_buffer, "NetHack");
202     if (lan_username_size)
203         *lan_username_size = strlen(username_buffer);
204     return username_buffer;
205 }
206
207 #if 0
208 char *getxxx()
209 {
210 char     szFullPath[MAX_PATH] = "";
211 HMODULE  hInst = NULL;          /* NULL gets the filename of this module */
212
213 GetModuleFileName(hInst, szFullPath, sizeof(szFullPath));
214 return &szFullPath[0];
215 }
216 #endif
217
218 /* fatal error */
219 /*VARARGS1*/
220 void error
221 VA_DECL(const char *, s)
222 {
223     char buf[BUFSZ];
224     VA_START(s);
225     VA_INIT(s, const char *);
226     /* error() may get called before tty is initialized */
227     if (iflags.window_inited)
228         end_screen();
229     if (WINDOWPORT("tty")) {
230         buf[0] = '\n';
231         (void) vsprintf(&buf[1], s, VA_ARGS);
232         Strcat(buf, "\n");
233         msmsg(buf);
234     } else {
235         (void) vsprintf(buf, s, VA_ARGS);
236         Strcat(buf, "\n");
237         raw_printf(buf);
238     }
239     VA_END();
240     exit(EXIT_FAILURE);
241 }
242
243 void
244 Delay(int ms)
245 {
246     (void) Sleep(ms);
247 }
248
249 void
250 win32_abort()
251 {
252     boolean is_tty = FALSE;
253
254 #ifdef TTY_GRAPHICS
255     is_tty = WINDOWPORT("tty");
256 #endif
257     if (wizard) {
258         int c, ci, ct;
259
260         if (!iflags.window_inited)
261             c = 'n';
262         ct = 0;
263         msmsg("Execute debug breakpoint wizard?");
264         while ((ci = nhgetch()) != '\n') {
265             if (ct > 0) {
266                 if (is_tty)
267                     backsp(); /* \b is visible on NT console */
268                 (void) putchar(' ');
269                 if (is_tty)
270                     backsp();
271                 ct = 0;
272                 c = 'n';
273             }
274             if (ci == 'y' || ci == 'n' || ci == 'Y' || ci == 'N') {
275                 ct = 1;
276                 c = ci;
277                 msmsg("%c", c);
278             }
279         }
280         if (c == 'y')
281             DebugBreak();
282     }
283     abort();
284 }
285
286 static char interjection_buf[INTERJECTION_TYPES][1024];
287 static int interjection[INTERJECTION_TYPES];
288
289 void
290 interject_assistance(num, interjection_type, ptr1, ptr2)
291 int num;
292 int interjection_type;
293 genericptr_t ptr1;
294 genericptr_t ptr2;
295 {
296     switch (num) {
297     case 1: {
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;
303         /*
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.
313          */
314         if (panicmsg && datadir) {
315             if (!strncmpi(datadir, "C:\\WINDOWS\\TEMP", 15)
316                 || strstri(datadir, "TEMP")
317                 || (tempdir && strstri(datadir, tempdir))) {
318                 (void) strncpy(
319                     interjection_buf[INTERJECT_PANIC],
320                     "\nOne common cause of this error is attempting to "
321                     "execute\n"
322                     "the game by double-clicking on it while it is "
323                     "displayed\n"
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 "
327                     "\n"
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",
331                     1023);
332             }
333         }
334     } break;
335     }
336 }
337
338 void
339 interject(interjection_type)
340 int interjection_type;
341 {
342     if (interjection_type >= 0 && interjection_type < INTERJECTION_TYPES)
343         msmsg(interjection_buf[interjection_type]);
344 }
345
346 #ifdef RUNTIME_PASTEBUF_SUPPORT
347
348 void port_insert_pastebuf(buf)
349 char *buf;
350 {
351     /* This implementation will utilize the windows clipboard
352      * to accomplish this.
353      */
354
355     char *tmp = buf;
356     HGLOBAL hglbCopy; 
357     WCHAR *w, w2[2];
358     int cc, rc, abytes;
359     LPWSTR lpwstrCopy;
360     HANDLE hresult;
361
362     if (!buf)
363         return; 
364  
365     cc = strlen(buf);
366     /* last arg=0 means "tell me the size of the buffer that I need" */
367     rc = MultiByteToWideChar(GetConsoleOutputCP(), 0, buf, -1, w2, 0);
368     if (!rc) return;
369
370     abytes = rc * sizeof(WCHAR);
371     w = (WCHAR *)alloc(abytes);     
372     /* Housekeeping need: +free(w) */
373
374     rc = MultiByteToWideChar(GetConsoleOutputCP(), 0, buf, -1, w, rc);
375     if (!rc) {
376         free(w);
377         return;
378     }
379     if (!OpenClipboard(NULL)) {
380         free(w);
381         return;
382     }
383     /* Housekeeping need: +CloseClipboard(), free(w) */
384
385     EmptyClipboard(); 
386
387     /* allocate global mem obj to hold the text */
388  
389     hglbCopy = GlobalAlloc(GMEM_MOVEABLE, abytes);
390     if (hglbCopy == NULL) { 
391         CloseClipboard(); 
392         free(w);
393         return;
394     } 
395     /* Housekeeping need: +GlobalFree(hglbCopy), CloseClipboard(), free(w) */
396  
397     lpwstrCopy = (LPWSTR)GlobalLock(hglbCopy);
398     /* Housekeeping need: +GlobalUnlock(hglbCopy), GlobalFree(hglbCopy),
399                             CloseClipboard(), free(w) */
400
401     memcpy(lpwstrCopy, w, abytes);
402     GlobalUnlock(hglbCopy);
403     /* Housekeeping need: GlobalFree(hglbCopy), CloseClipboard(), free(w) */
404
405     /* put it on the clipboard */
406     hresult = SetClipboardData(CF_UNICODETEXT, hglbCopy);
407     if (!hresult) {
408         raw_printf("Error copying to clipboard.\n");
409         GlobalFree(hglbCopy); /* only needed if clipboard didn't accept data */
410     }
411     /* Housekeeping need: CloseClipboard(), free(w) */
412  
413     CloseClipboard(); 
414     free(w);
415     return;
416 }
417
418 static HWND
419 GetConsoleHandle(void)
420 {
421     HMODULE hMod = GetModuleHandle("kernel32.dll");
422     GETCONSOLEWINDOW pfnGetConsoleWindow =
423         (GETCONSOLEWINDOW) GetProcAddress(hMod, "GetConsoleWindow");
424     if (pfnGetConsoleWindow)
425         return pfnGetConsoleWindow();
426     else
427         return GetConsoleHwnd();
428 }
429
430 static HWND
431 GetConsoleHwnd(void)
432 {
433     int iterations = 0;
434     HWND hwndFound = 0;
435     char OldTitle[1024], NewTitle[1024], TestTitle[1024];
436
437     /* Get current window title */
438     GetConsoleTitle(OldTitle, sizeof OldTitle);
439
440     (void) sprintf(NewTitle, "NETHACK%d/%d", GetTickCount(),
441                    GetCurrentProcessId());
442     SetConsoleTitle(NewTitle);
443
444     GetConsoleTitle(TestTitle, sizeof TestTitle);
445     while (strcmp(TestTitle, NewTitle) != 0) {
446         iterations++;
447         /* sleep(0); */
448         GetConsoleTitle(TestTitle, sizeof TestTitle);
449     }
450     hwndFound = FindWindow(NULL, NewTitle);
451     SetConsoleTitle(OldTitle);
452     /*       printf("%d iterations\n", iterations); */
453     return hwndFound;
454 }
455
456 #endif
457
458 #ifdef RUNTIME_PORT_ID
459 /*
460  * _M_IX86 is Defined for x86 processors. This is not defined for x64
461  * processors.
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.
465  */
466 #ifndef _M_IX86
467 #ifdef _M_X64
468 #define TARGET_PORT "x64"
469 #endif
470 #ifdef _M_IA64
471 #define TARGET_PORT "IA64"
472 #endif
473 #endif
474
475 #ifndef TARGET_PORT
476 #define TARGET_PORT "x86"
477 #endif
478
479 char *
480 get_port_id(buf)
481 char *buf;
482 {
483     Strcpy(buf, TARGET_PORT);
484     return buf;
485 }
486 #endif /* RUNTIME_PORT_ID */
487
488 /* nhassert_failed is called when an nhassert's condition is false */
489 void nhassert_failed(const char * exp, const char * file, int line)
490 {
491     char message[128];
492     _snprintf(message, sizeof(message),
493                 "NHASSERT(%s) in '%s' at line %d\n", exp, file, line);
494
495     if (IsDebuggerPresent()) {
496         OutputDebugStringA(message);
497         DebugBreak();
498     }
499
500     // strip off the newline
501     message[strlen(message) - 1] = '\0';
502     error(message);
503 }
504
505 void
506 nethack_exit(code)
507 int code;
508 {
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.
513      */
514
515
516     if (!GUILaunched) {
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;
521     }
522     if (getreturn_enabled)
523         wait_synch();
524     exit(code);
525 }
526
527 #undef kbhit
528 #include <conio.h>
529
530 int
531 windows_console_custom_nhgetch(VOID_ARGS)
532 {
533     return _getch();
534 }
535
536
537 void
538 getreturn(str)
539 const char *str;
540 {
541     char buf[BUFSZ];
542
543     if (!getreturn_enabled)
544         return;
545     Sprintf(buf,"Hit <Enter> %s.", str);
546     raw_print(buf);
547     wait_synch();
548     return;
549 }
550
551 /* nethack_enter_winnt() is called from main immediately after
552    initializing the window port */
553 void nethack_enter_winnt()
554 {
555         if (WINDOWPORT("tty"))
556                 nethack_enter_nttty();
557 }
558
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
593 };
594
595 WCHAR *
596 winos_ascii_to_wide_str(const unsigned char * src, WCHAR * dst, size_t dstLength)
597 {
598     size_t i = 0;
599     while(i < dstLength - 1 && src[i] != 0)
600         dst[i++] = cp437[src[i]];
601     dst[i] = 0;
602     return dst;
603 }
604
605 WCHAR
606 winos_ascii_to_wide(const unsigned char c)
607 {
608     return cp437[c];
609 }
610
611 BOOL winos_font_support_cp437(HFONT hFont)
612 {
613     BOOL allFound = FALSE;
614     HDC hdc = GetDC(NULL);
615     HFONT oldFont = SelectObject(hdc, hFont);
616
617     DWORD size = GetFontUnicodeRanges(hdc, NULL);
618     GLYPHSET *glyphSet = (GLYPHSET *) malloc(size);
619
620     if (glyphSet != NULL) {
621         GetFontUnicodeRanges(hdc, glyphSet);
622
623         allFound = TRUE;
624         for (int i = 0; i < 256 && allFound; i++) {
625             WCHAR wc = cp437[i];
626             BOOL found = FALSE;
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;
630
631                 if (wc >= first && wc <= last)
632                     found = TRUE;
633             }
634             if (!found)
635                 allFound = FALSE;
636         }
637
638         free(glyphSet);
639     }
640
641     SelectObject(hdc, oldFont);
642     ReleaseDC(NULL, hdc);
643
644     return allFound;
645 }
646
647 int
648 windows_early_options(window_opt)
649 const char *window_opt;
650 {
651     /*
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.
655      */
656
657     if (match_optname(window_opt, "cursorblink", 5, FALSE)) {
658         win32_cursorblink = TRUE;
659         return 1;
660     } else {
661         raw_printf(
662             "-%swindows:cursorblink is the only supported option.\n");
663     }
664     return 0;
665 }
666
667 /*
668  * Add a backslash to any name not ending in /, \ or :   There must
669  * be room for the \
670  */
671 void
672 append_slash(name)
673 char *name;
674 {
675     char *ptr;
676
677     if (!*name)
678         return;
679     ptr = name + (strlen(name) - 1);
680     if (*ptr != '\\' && *ptr != '/' && *ptr != ':') {
681         *++ptr = '\\';
682         *++ptr = '\0';
683     }
684     return;
685 }
686
687 #include <bcrypt.h>     /* Windows Crypto Next Gen (CNG) */
688
689 #ifndef STATUS_SUCCESS
690 #define STATUS_SUCCESS 0
691 #endif
692 #ifndef STATUS_NOT_FOUND
693 #define STATUS_NOT_FOUND 0xC0000225
694 #endif
695 #ifndef STATUS_UNSUCCESSFUL
696 #define STATUS_UNSUCCESSFUL 0xC0000001
697 #endif
698
699 unsigned long
700 sys_random_seed(VOID_ARGS)
701 {
702     unsigned long ourseed = 0UL;
703     BCRYPT_ALG_HANDLE hRa = (BCRYPT_ALG_HANDLE) 0;
704     NTSTATUS status = STATUS_UNSUCCESSFUL;
705     boolean Plan_B = TRUE;
706
707     status = BCryptOpenAlgorithmProvider(&hRa, BCRYPT_RNG_ALGORITHM,
708                                          (LPCWSTR) 0, 0);
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;
715             Plan_B = FALSE;
716         }
717     }
718
719     if (Plan_B) {
720         time_t datetime = 0;
721         const char *emsg;
722
723         if (status == STATUS_NOT_FOUND)
724             emsg = "BCRYPT_RNG_ALGORITHM not avail, falling back";
725         else
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;
730     }
731     return ourseed;
732 }
733
734 #endif /* WIN32 */
735
736 /*winnt.c*/