xref: /vim-8.2.3635/src/os_mswin.c (revision ed37d9b3)
1 /* vi:set ts=8 sts=4 sw=4 noet:
2  *
3  * VIM - Vi IMproved	by Bram Moolenaar
4  *
5  * Do ":help uganda"  in Vim to read copying and usage conditions.
6  * Do ":help credits" in Vim to see a list of people who contributed.
7  * See README.txt for an overview of the Vim source code.
8  */
9 
10 /*
11  * os_mswin.c
12  *
13  * Routines for Win32.
14  */
15 
16 #include "vim.h"
17 
18 #include <sys/types.h>
19 #include <signal.h>
20 #include <limits.h>
21 #ifndef PROTO
22 # include <process.h>
23 #endif
24 
25 #undef chdir
26 #ifdef __GNUC__
27 # ifndef __MINGW32__
28 #  include <dirent.h>
29 # endif
30 #else
31 # include <direct.h>
32 #endif
33 
34 #ifndef PROTO
35 # if defined(FEAT_TITLE) && !defined(FEAT_GUI_MSWIN)
36 #  include <shellapi.h>
37 # endif
38 
39 # if defined(FEAT_PRINTER) && !defined(FEAT_POSTSCRIPT)
40 #  include <dlgs.h>
41 #  include <winspool.h>
42 #  include <commdlg.h>
43 # endif
44 
45 #endif // PROTO
46 
47 #ifdef __MINGW32__
48 # ifndef FROM_LEFT_1ST_BUTTON_PRESSED
49 #  define FROM_LEFT_1ST_BUTTON_PRESSED    0x0001
50 # endif
51 # ifndef RIGHTMOST_BUTTON_PRESSED
52 #  define RIGHTMOST_BUTTON_PRESSED	  0x0002
53 # endif
54 # ifndef FROM_LEFT_2ND_BUTTON_PRESSED
55 #  define FROM_LEFT_2ND_BUTTON_PRESSED    0x0004
56 # endif
57 # ifndef FROM_LEFT_3RD_BUTTON_PRESSED
58 #  define FROM_LEFT_3RD_BUTTON_PRESSED    0x0008
59 # endif
60 # ifndef FROM_LEFT_4TH_BUTTON_PRESSED
61 #  define FROM_LEFT_4TH_BUTTON_PRESSED    0x0010
62 # endif
63 
64 /*
65  * EventFlags
66  */
67 # ifndef MOUSE_MOVED
68 #  define MOUSE_MOVED   0x0001
69 # endif
70 # ifndef DOUBLE_CLICK
71 #  define DOUBLE_CLICK  0x0002
72 # endif
73 #endif
74 
75 /*
76  * When generating prototypes for Win32 on Unix, these lines make the syntax
77  * errors disappear.  They do not need to be correct.
78  */
79 #ifdef PROTO
80 # define WINAPI
81 # define WINBASEAPI
82 typedef int BOOL;
83 typedef int CALLBACK;
84 typedef int COLORREF;
85 typedef int CONSOLE_CURSOR_INFO;
86 typedef int COORD;
87 typedef int DWORD;
88 typedef int ENUMLOGFONTW;
89 typedef int HANDLE;
90 typedef int HDC;
91 typedef int HFONT;
92 typedef int HICON;
93 typedef int HWND;
94 typedef int INPUT_RECORD;
95 typedef int KEY_EVENT_RECORD;
96 typedef int LOGFONTW;
97 typedef int LPARAM;
98 typedef int LPBOOL;
99 typedef int LPCSTR;
100 typedef int LPCWSTR;
101 typedef int LPDWORD;
102 typedef int LPSTR;
103 typedef int LPTSTR;
104 typedef int LPVOID;
105 typedef int LPWSTR;
106 typedef int LRESULT;
107 typedef int MOUSE_EVENT_RECORD;
108 typedef int NEWTEXTMETRICW;
109 typedef int PACL;
110 typedef int PRINTDLGW;
111 typedef int PSECURITY_DESCRIPTOR;
112 typedef int PSID;
113 typedef int SECURITY_INFORMATION;
114 typedef int SHORT;
115 typedef int SMALL_RECT;
116 typedef int TEXTMETRIC;
117 typedef int UINT;
118 typedef int WCHAR;
119 typedef int WNDENUMPROC;
120 typedef int WORD;
121 typedef int WPARAM;
122 typedef void VOID;
123 #endif
124 
125 // Record all output and all keyboard & mouse input
126 // #define MCH_WRITE_DUMP
127 
128 #ifdef MCH_WRITE_DUMP
129 FILE* fdDump = NULL;
130 #endif
131 
132 #if !defined(FEAT_GUI_MSWIN) || defined(VIMDLL)
133 extern char g_szOrigTitle[];
134 #endif
135 
136 #ifdef FEAT_GUI
137 extern HWND s_hwnd;
138 #else
139 static HWND s_hwnd = 0;	    // console window handle, set by GetConsoleHwnd()
140 #endif
141 
142 #ifdef FEAT_JOB_CHANNEL
143 int WSInitialized = FALSE; // WinSock is initialized
144 #endif
145 
146 // Don't generate prototypes here, because some systems do have these
147 // functions.
148 #if defined(__GNUC__) && !defined(PROTO)
149 # ifndef __MINGW32__
150 int _stricoll(char *a, char *b)
151 {
152     // the ANSI-ish correct way is to use strxfrm():
153     char a_buff[512], b_buff[512];  // file names, so this is enough on Win32
154     strxfrm(a_buff, a, 512);
155     strxfrm(b_buff, b, 512);
156     return strcoll(a_buff, b_buff);
157 }
158 
159 char * _fullpath(char *buf, char *fname, int len)
160 {
161     LPTSTR toss;
162 
163     return (char *)GetFullPathName(fname, len, buf, &toss);
164 }
165 # endif
166 
167 # if !defined(__MINGW32__) || (__GNUC__ < 4)
168 int _chdrive(int drive)
169 {
170     char temp [3] = "-:";
171     temp[0] = drive + 'A' - 1;
172     return !SetCurrentDirectory(temp);
173 }
174 # endif
175 #endif
176 
177 
178 #ifndef PROTO
179 /*
180  * Save the instance handle of the exe/dll.
181  */
182     void
183 SaveInst(HINSTANCE hInst)
184 {
185     g_hinst = hInst;
186 }
187 #endif
188 
189 #if defined(FEAT_GUI_MSWIN) || defined(PROTO)
190 /*
191  * GUI version of mch_exit().
192  * Shut down and exit with status `r'
193  * Careful: mch_exit() may be called before mch_init()!
194  */
195     void
196 mch_exit_g(int r)
197 {
198     exiting = TRUE;
199 
200     display_errors();
201 
202     ml_close_all(TRUE);		// remove all memfiles
203 
204 # ifdef FEAT_OLE
205     UninitOLE();
206 # endif
207 # ifdef FEAT_JOB_CHANNEL
208     if (WSInitialized)
209     {
210 	WSInitialized = FALSE;
211 	WSACleanup();
212     }
213 # endif
214 # ifdef DYNAMIC_GETTEXT
215     dyn_libintl_end();
216 # endif
217 
218     if (gui.in_use)
219 	gui_exit(r);
220 
221 # ifdef EXITFREE
222     free_all_mem();
223 # endif
224 
225     exit(r);
226 }
227 
228 #endif // FEAT_GUI_MSWIN
229 
230 
231 /*
232  * Init the tables for toupper() and tolower().
233  */
234     void
235 mch_early_init(void)
236 {
237     int		i;
238 
239     PlatformId();
240 
241     // Init the tables for toupper() and tolower()
242     for (i = 0; i < 256; ++i)
243 	toupper_tab[i] = tolower_tab[i] = i;
244     CharUpperBuff((LPSTR)toupper_tab, 256);
245     CharLowerBuff((LPSTR)tolower_tab, 256);
246 }
247 
248 
249 /*
250  * Return TRUE if the input comes from a terminal, FALSE otherwise.
251  */
252     int
253 mch_input_isatty(void)
254 {
255 #ifdef FEAT_GUI_MSWIN
256 # ifdef VIMDLL
257     if (gui.in_use)
258 # endif
259 	return TRUE;	    // GUI always has a tty
260 #endif
261 #if !defined(FEAT_GUI_MSWIN) || defined(VIMDLL)
262     if (isatty(read_cmd_fd))
263 	return TRUE;
264     return FALSE;
265 #endif
266 }
267 
268 #ifdef FEAT_TITLE
269 /*
270  * mch_settitle(): set titlebar of our window
271  */
272     void
273 mch_settitle(
274     char_u *title,
275     char_u *icon UNUSED)
276 {
277 # ifdef FEAT_GUI_MSWIN
278 #  ifdef VIMDLL
279     if (gui.in_use)
280 #  endif
281     {
282 	gui_mch_settitle(title, icon);
283 	return;
284     }
285 # endif
286 # if !defined(FEAT_GUI_MSWIN) || defined(VIMDLL)
287     if (title != NULL)
288     {
289 	WCHAR	*wp = enc_to_utf16(title, NULL);
290 
291 	if (wp == NULL)
292 	    return;
293 
294 	SetConsoleTitleW(wp);
295 	vim_free(wp);
296 	return;
297     }
298 # endif
299 }
300 
301 
302 /*
303  * Restore the window/icon title.
304  * which is one of:
305  *  SAVE_RESTORE_TITLE: Just restore title
306  *  SAVE_RESTORE_ICON:  Just restore icon (which we don't have)
307  *  SAVE_RESTORE_BOTH:  Restore title and icon (which we don't have)
308  */
309     void
310 mch_restore_title(int which UNUSED)
311 {
312 # if !defined(FEAT_GUI_MSWIN) || defined(VIMDLL)
313 #  ifdef VIMDLL
314     if (!gui.in_use)
315 #  endif
316 	SetConsoleTitle(g_szOrigTitle);
317 # endif
318 }
319 
320 
321 /*
322  * Return TRUE if we can restore the title (we can)
323  */
324     int
325 mch_can_restore_title(void)
326 {
327     return TRUE;
328 }
329 
330 
331 /*
332  * Return TRUE if we can restore the icon title (we can't)
333  */
334     int
335 mch_can_restore_icon(void)
336 {
337     return FALSE;
338 }
339 #endif // FEAT_TITLE
340 
341 
342 /*
343  * Get absolute file name into buffer "buf" of length "len" bytes,
344  * turning all '/'s into '\\'s and getting the correct case of each component
345  * of the file name.  Append a (back)slash to a directory name.
346  * When 'shellslash' set do it the other way around.
347  * Return OK or FAIL.
348  */
349     int
350 mch_FullName(
351     char_u	*fname,
352     char_u	*buf,
353     int		len,
354     int		force UNUSED)
355 {
356     int		nResult = FAIL;
357     WCHAR	*wname;
358     WCHAR	wbuf[MAX_PATH];
359     char_u	*cname = NULL;
360 
361     wname = enc_to_utf16(fname, NULL);
362     if (wname != NULL && _wfullpath(wbuf, wname, MAX_PATH) != NULL)
363     {
364 	cname = utf16_to_enc((short_u *)wbuf, NULL);
365 	if (cname != NULL)
366 	{
367 	    vim_strncpy(buf, cname, len - 1);
368 	    nResult = OK;
369 	}
370     }
371     vim_free(wname);
372     vim_free(cname);
373 
374 #ifdef USE_FNAME_CASE
375     fname_case(buf, len);
376 #else
377     slash_adjust(buf);
378 #endif
379 
380     return nResult;
381 }
382 
383 
384 /*
385  * Return TRUE if "fname" does not depend on the current directory.
386  */
387     int
388 mch_isFullName(char_u *fname)
389 {
390     // WinNT and later can use _MAX_PATH wide characters for a pathname, which
391     // means that the maximum pathname is _MAX_PATH * 3 bytes when 'enc' is
392     // UTF-8.
393     char szName[_MAX_PATH * 3 + 1];
394 
395     // A name like "d:/foo" and "//server/share" is absolute
396     if ((fname[0] && fname[1] == ':' && (fname[2] == '/' || fname[2] == '\\'))
397 	    || (fname[0] == fname[1] && (fname[0] == '/' || fname[0] == '\\')))
398 	return TRUE;
399 
400     // A name that can't be made absolute probably isn't absolute.
401     if (mch_FullName(fname, (char_u *)szName, sizeof(szName) - 1, FALSE) == FAIL)
402 	return FALSE;
403 
404     return pathcmp((const char *)fname, (const char *)szName, -1) == 0;
405 }
406 
407 /*
408  * Replace all slashes by backslashes.
409  * This used to be the other way around, but MS-DOS sometimes has problems
410  * with slashes (e.g. in a command name).  We can't have mixed slashes and
411  * backslashes, because comparing file names will not work correctly.  The
412  * commands that use a file name should try to avoid the need to type a
413  * backslash twice.
414  * When 'shellslash' set do it the other way around.
415  * When the path looks like a URL leave it unmodified.
416  */
417     void
418 slash_adjust(char_u *p)
419 {
420     if (path_with_url(p))
421 	return;
422 
423     if (*p == '`')
424     {
425 	size_t len = STRLEN(p);
426 
427 	// don't replace backslash in backtick quoted strings
428 	if (len > 2 && *(p + len - 1) == '`')
429 	    return;
430     }
431 
432     while (*p)
433     {
434 	if (*p == psepcN)
435 	    *p = psepc;
436 	MB_PTR_ADV(p);
437     }
438 }
439 
440 // Use 64-bit stat functions if available.
441 #ifdef HAVE_STAT64
442 # undef stat
443 # undef _stat
444 # undef _wstat
445 # undef _fstat
446 # define stat _stat64
447 # define _stat _stat64
448 # define _wstat _wstat64
449 # define _fstat _fstat64
450 #endif
451 
452 #if (defined(_MSC_VER) && (_MSC_VER >= 1300)) || defined(__MINGW32__)
453 # define OPEN_OH_ARGTYPE intptr_t
454 #else
455 # define OPEN_OH_ARGTYPE long
456 #endif
457 
458     static int
459 wstat_symlink_aware(const WCHAR *name, stat_T *stp)
460 {
461 #if (defined(_MSC_VER) && (_MSC_VER < 1900)) || defined(__MINGW32__)
462     // Work around for VC12 or earlier (and MinGW). _wstat() can't handle
463     // symlinks properly.
464     // VC9 or earlier: _wstat() doesn't support a symlink at all. It retrieves
465     // status of a symlink itself.
466     // VC10: _wstat() supports a symlink to a normal file, but it doesn't
467     // support a symlink to a directory (always returns an error).
468     // VC11 and VC12: _wstat() doesn't return an error for a symlink to a
469     // directory, but it doesn't set S_IFDIR flag.
470     // MinGW: Same as VC9.
471     int			n;
472     BOOL		is_symlink = FALSE;
473     HANDLE		hFind, h;
474     DWORD		attr = 0;
475     WIN32_FIND_DATAW	findDataW;
476 
477     hFind = FindFirstFileW(name, &findDataW);
478     if (hFind != INVALID_HANDLE_VALUE)
479     {
480 	attr = findDataW.dwFileAttributes;
481 	if ((attr & FILE_ATTRIBUTE_REPARSE_POINT)
482 		&& (findDataW.dwReserved0 == IO_REPARSE_TAG_SYMLINK))
483 	    is_symlink = TRUE;
484 	FindClose(hFind);
485     }
486     if (is_symlink)
487     {
488 	h = CreateFileW(name, FILE_READ_ATTRIBUTES,
489 		FILE_SHARE_READ | FILE_SHARE_WRITE, NULL,
490 		OPEN_EXISTING,
491 		(attr & FILE_ATTRIBUTE_DIRECTORY)
492 					    ? FILE_FLAG_BACKUP_SEMANTICS : 0,
493 		NULL);
494 	if (h != INVALID_HANDLE_VALUE)
495 	{
496 	    int	    fd;
497 
498 	    fd = _open_osfhandle((OPEN_OH_ARGTYPE)h, _O_RDONLY);
499 	    n = _fstat(fd, (struct _stat *)stp);
500 	    if ((n == 0) && (attr & FILE_ATTRIBUTE_DIRECTORY))
501 		stp->st_mode = (stp->st_mode & ~S_IFREG) | S_IFDIR;
502 	    _close(fd);
503 	    return n;
504 	}
505     }
506 #endif
507     return _wstat(name, (struct _stat *)stp);
508 }
509 
510 /*
511  * stat() can't handle a trailing '/' or '\', remove it first.
512  */
513     int
514 vim_stat(const char *name, stat_T *stp)
515 {
516     // WinNT and later can use _MAX_PATH wide characters for a pathname, which
517     // means that the maximum pathname is _MAX_PATH * 3 bytes when 'enc' is
518     // UTF-8.
519     char_u	buf[_MAX_PATH * 3 + 1];
520     char_u	*p;
521     WCHAR	*wp;
522     int		n;
523 
524     vim_strncpy((char_u *)buf, (char_u *)name, sizeof(buf) - 1);
525     p = buf + STRLEN(buf);
526     if (p > buf)
527 	MB_PTR_BACK(buf, p);
528 
529     // Remove trailing '\\' except root path.
530     if (p > buf && (*p == '\\' || *p == '/') && p[-1] != ':')
531 	*p = NUL;
532 
533     if ((buf[0] == '\\' && buf[1] == '\\') || (buf[0] == '/' && buf[1] == '/'))
534     {
535 	// UNC root path must be followed by '\\'.
536 	p = vim_strpbrk(buf + 2, (char_u *)"\\/");
537 	if (p != NULL)
538 	{
539 	    p = vim_strpbrk(p + 1, (char_u *)"\\/");
540 	    if (p == NULL)
541 		STRCAT(buf, "\\");
542 	}
543     }
544 
545     wp = enc_to_utf16(buf, NULL);
546     if (wp == NULL)
547 	return -1;
548 
549     n = wstat_symlink_aware(wp, stp);
550     vim_free(wp);
551     return n;
552 }
553 
554 #if (defined(FEAT_GUI_MSWIN) && !defined(VIMDLL)) || defined(PROTO)
555     void
556 mch_settmode(tmode_T tmode UNUSED)
557 {
558     // nothing to do
559 }
560 
561     int
562 mch_get_shellsize(void)
563 {
564     // never used
565     return OK;
566 }
567 
568     void
569 mch_set_shellsize(void)
570 {
571     // never used
572 }
573 
574 /*
575  * Rows and/or Columns has changed.
576  */
577     void
578 mch_new_shellsize(void)
579 {
580     // never used
581 }
582 
583 #endif
584 
585 /*
586  * We have no job control, so fake it by starting a new shell.
587  */
588     void
589 mch_suspend(void)
590 {
591     suspend_shell();
592 }
593 
594 #if defined(USE_MCH_ERRMSG) || defined(PROTO)
595 
596 # ifdef display_errors
597 #  undef display_errors
598 # endif
599 
600 /*
601  * Display the saved error message(s).
602  */
603     void
604 display_errors(void)
605 {
606 # ifdef FEAT_GUI
607     char *p;
608 
609 #  ifdef VIMDLL
610     if (gui.in_use || gui.starting)
611 #  endif
612     {
613 	if (error_ga.ga_data != NULL)
614 	{
615 	    // avoid putting up a message box with blanks only
616 	    for (p = (char *)error_ga.ga_data; *p; ++p)
617 		if (!isspace(*p))
618 		{
619 		    (void)gui_mch_dialog(
620 				     gui.starting ? VIM_INFO :
621 					     VIM_ERROR,
622 				     gui.starting ? (char_u *)_("Message") :
623 					     (char_u *)_("Error"),
624 				     (char_u *)p, (char_u *)_("&Ok"),
625 					1, NULL, FALSE);
626 		    break;
627 		}
628 	    ga_clear(&error_ga);
629 	}
630 	return;
631     }
632 # endif
633 # if !defined(FEAT_GUI) || defined(VIMDLL)
634     FlushFileBuffers(GetStdHandle(STD_ERROR_HANDLE));
635 # endif
636 }
637 #endif
638 
639 
640 /*
641  * Return TRUE if "p" contain a wildcard that can be expanded by
642  * dos_expandpath().
643  */
644     int
645 mch_has_exp_wildcard(char_u *p)
646 {
647     for ( ; *p; MB_PTR_ADV(p))
648     {
649 	if (vim_strchr((char_u *)"?*[", *p) != NULL
650 		|| (*p == '~' && p[1] != NUL))
651 	    return TRUE;
652     }
653     return FALSE;
654 }
655 
656 /*
657  * Return TRUE if "p" contain a wildcard or a "~1" kind of thing (could be a
658  * shortened file name).
659  */
660     int
661 mch_has_wildcard(char_u *p)
662 {
663     for ( ; *p; MB_PTR_ADV(p))
664     {
665 	if (vim_strchr((char_u *)
666 #ifdef VIM_BACKTICK
667 				    "?*$[`"
668 #else
669 				    "?*$["
670 #endif
671 						, *p) != NULL
672 		|| (*p == '~' && p[1] != NUL))
673 	    return TRUE;
674     }
675     return FALSE;
676 }
677 
678 
679 /*
680  * The normal _chdir() does not change the default drive.  This one does.
681  * Returning 0 implies success; -1 implies failure.
682  */
683     int
684 mch_chdir(char *path)
685 {
686     WCHAR   *p;
687     int	    n;
688 
689     if (path[0] == NUL)		// just checking...
690 	return -1;
691 
692     if (p_verbose >= 5)
693     {
694 	verbose_enter();
695 	smsg("chdir(%s)", path);
696 	verbose_leave();
697     }
698     if (isalpha(path[0]) && path[1] == ':')	// has a drive name
699     {
700 	// If we can change to the drive, skip that part of the path.  If we
701 	// can't then the current directory may be invalid, try using chdir()
702 	// with the whole path.
703 	if (_chdrive(TOLOWER_ASC(path[0]) - 'a' + 1) == 0)
704 	    path += 2;
705     }
706 
707     if (*path == NUL)		// drive name only
708 	return 0;
709 
710     p = enc_to_utf16((char_u *)path, NULL);
711     if (p == NULL)
712 	return -1;
713 
714     n = _wchdir(p);
715     vim_free(p);
716     return n;
717 }
718 
719 
720 #if defined(FEAT_GUI_MSWIN) && !defined(VIMDLL)
721 /*
722  * return non-zero if a character is available
723  */
724     int
725 mch_char_avail(void)
726 {
727     // never used
728     return TRUE;
729 }
730 
731 # if defined(FEAT_TERMINAL) || defined(PROTO)
732 /*
733  * Check for any pending input or messages.
734  */
735     int
736 mch_check_messages(void)
737 {
738     // TODO: check for messages
739     return TRUE;
740 }
741 # endif
742 #endif
743 
744 
745 #if defined(FEAT_LIBCALL) || defined(PROTO)
746 /*
747  * Call a DLL routine which takes either a string or int param
748  * and returns an allocated string.
749  * Return OK if it worked, FAIL if not.
750  */
751 typedef LPTSTR (*MYSTRPROCSTR)(LPTSTR);
752 typedef LPTSTR (*MYINTPROCSTR)(int);
753 typedef int (*MYSTRPROCINT)(LPTSTR);
754 typedef int (*MYINTPROCINT)(int);
755 
756 /*
757  * Check if a pointer points to a valid NUL terminated string.
758  * Return the length of the string, including terminating NUL.
759  * Returns 0 for an invalid pointer, 1 for an empty string.
760  */
761     static size_t
762 check_str_len(char_u *str)
763 {
764     SYSTEM_INFO			si;
765     MEMORY_BASIC_INFORMATION	mbi;
766     size_t			length = 0;
767     size_t			i;
768     const char_u		*p;
769 
770     // get page size
771     GetSystemInfo(&si);
772 
773     // get memory information
774     if (VirtualQuery(str, &mbi, sizeof(mbi)))
775     {
776 	// pre cast these (typing savers)
777 	long_u dwStr = (long_u)str;
778 	long_u dwBaseAddress = (long_u)mbi.BaseAddress;
779 
780 	// get start address of page that str is on
781 	long_u strPage = dwStr - (dwStr - dwBaseAddress) % si.dwPageSize;
782 
783 	// get length from str to end of page
784 	long_u pageLength = si.dwPageSize - (dwStr - strPage);
785 
786 	for (p = str; !IsBadReadPtr(p, (UINT)pageLength);
787 				  p += pageLength, pageLength = si.dwPageSize)
788 	    for (i = 0; i < pageLength; ++i, ++length)
789 		if (p[i] == NUL)
790 		    return length + 1;
791     }
792 
793     return 0;
794 }
795 
796 /*
797  * Passed to do_in_runtimepath() to load a vim.ico file.
798  */
799     static void
800 mch_icon_load_cb(char_u *fname, void *cookie)
801 {
802     HANDLE *h = (HANDLE *)cookie;
803 
804     *h = LoadImage(NULL,
805 		   (LPSTR)fname,
806 		   IMAGE_ICON,
807 		   64,
808 		   64,
809 		   LR_LOADFROMFILE | LR_LOADMAP3DCOLORS);
810 }
811 
812 /*
813  * Try loading an icon file from 'runtimepath'.
814  */
815     int
816 mch_icon_load(HANDLE *iconp)
817 {
818     return do_in_runtimepath((char_u *)"bitmaps/vim.ico",
819 						  0, mch_icon_load_cb, iconp);
820 }
821 
822     int
823 mch_libcall(
824     char_u	*libname,
825     char_u	*funcname,
826     char_u	*argstring,	// NULL when using a argint
827     int		argint,
828     char_u	**string_result,// NULL when using number_result
829     int		*number_result)
830 {
831     HINSTANCE		hinstLib;
832     MYSTRPROCSTR	ProcAdd;
833     MYINTPROCSTR	ProcAddI;
834     char_u		*retval_str = NULL;
835     int			retval_int = 0;
836     size_t		len;
837 
838     BOOL fRunTimeLinkSuccess = FALSE;
839 
840     // Get a handle to the DLL module.
841     hinstLib = vimLoadLib((char *)libname);
842 
843     // If the handle is valid, try to get the function address.
844     if (hinstLib != NULL)
845     {
846 # ifdef HAVE_TRY_EXCEPT
847 	__try
848 	{
849 # endif
850 	if (argstring != NULL)
851 	{
852 	    // Call with string argument
853 	    ProcAdd = (MYSTRPROCSTR)GetProcAddress(hinstLib, (LPCSTR)funcname);
854 	    if ((fRunTimeLinkSuccess = (ProcAdd != NULL)) != 0)
855 	    {
856 		if (string_result == NULL)
857 		    retval_int = ((MYSTRPROCINT)ProcAdd)((LPSTR)argstring);
858 		else
859 		    retval_str = (char_u *)(ProcAdd)((LPSTR)argstring);
860 	    }
861 	}
862 	else
863 	{
864 	    // Call with number argument
865 	    ProcAddI = (MYINTPROCSTR) GetProcAddress(hinstLib, (LPCSTR)funcname);
866 	    if ((fRunTimeLinkSuccess = (ProcAddI != NULL)) != 0)
867 	    {
868 		if (string_result == NULL)
869 		    retval_int = ((MYINTPROCINT)ProcAddI)(argint);
870 		else
871 		    retval_str = (char_u *)(ProcAddI)(argint);
872 	    }
873 	}
874 
875 	// Save the string before we free the library.
876 	// Assume that a "1" result is an illegal pointer.
877 	if (string_result == NULL)
878 	    *number_result = retval_int;
879 	else if (retval_str != NULL
880 		&& (len = check_str_len(retval_str)) > 0)
881 	{
882 	    *string_result = alloc(len);
883 	    if (*string_result != NULL)
884 		mch_memmove(*string_result, retval_str, len);
885 	}
886 
887 # ifdef HAVE_TRY_EXCEPT
888 	}
889 	__except(EXCEPTION_EXECUTE_HANDLER)
890 	{
891 	    if (GetExceptionCode() == EXCEPTION_STACK_OVERFLOW)
892 		RESETSTKOFLW();
893 	    fRunTimeLinkSuccess = 0;
894 	}
895 # endif
896 
897 	// Free the DLL module.
898 	(void)FreeLibrary(hinstLib);
899     }
900 
901     if (!fRunTimeLinkSuccess)
902     {
903 	semsg(_(e_libcall), funcname);
904 	return FAIL;
905     }
906 
907     return OK;
908 }
909 #endif
910 
911 /*
912  * Debugging helper: expose the MCH_WRITE_DUMP stuff to other modules
913  */
914     void
915 DumpPutS(const char *psz UNUSED)
916 {
917 #ifdef MCH_WRITE_DUMP
918     if (fdDump)
919     {
920 	fputs(psz, fdDump);
921 	if (psz[strlen(psz) - 1] != '\n')
922 	    fputc('\n', fdDump);
923 	fflush(fdDump);
924     }
925 #endif
926 }
927 
928 #ifdef _DEBUG
929 
930 void __cdecl
931 Trace(
932     char *pszFormat,
933     ...)
934 {
935     CHAR szBuff[2048];
936     va_list args;
937 
938     va_start(args, pszFormat);
939     vsprintf(szBuff, pszFormat, args);
940     va_end(args);
941 
942     OutputDebugString(szBuff);
943 }
944 
945 #endif //_DEBUG
946 
947 #if !defined(FEAT_GUI) || defined(VIMDLL) || defined(PROTO)
948 # ifdef FEAT_TITLE
949 extern HWND g_hWnd;	// This is in os_win32.c.
950 # endif
951 
952 /*
953  * Showing the printer dialog is tricky since we have no GUI
954  * window to parent it. The following routines are needed to
955  * get the window parenting and Z-order to work properly.
956  */
957     static void
958 GetConsoleHwnd(void)
959 {
960     // Skip if it's already set.
961     if (s_hwnd != 0)
962 	return;
963 
964 # ifdef FEAT_TITLE
965     // Window handle may have been found by init code (Windows NT only)
966     if (g_hWnd != 0)
967     {
968 	s_hwnd = g_hWnd;
969 	return;
970     }
971 # endif
972 
973     s_hwnd = GetConsoleWindow();
974 }
975 
976 /*
977  * Console implementation of ":winpos".
978  */
979     int
980 mch_get_winpos(int *x, int *y)
981 {
982     RECT  rect;
983 
984     GetConsoleHwnd();
985     GetWindowRect(s_hwnd, &rect);
986     *x = rect.left;
987     *y = rect.top;
988     return OK;
989 }
990 
991 /*
992  * Console implementation of ":winpos x y".
993  */
994     void
995 mch_set_winpos(int x, int y)
996 {
997     GetConsoleHwnd();
998     SetWindowPos(s_hwnd, NULL, x, y, 0, 0,
999 		 SWP_NOZORDER | SWP_NOSIZE | SWP_NOACTIVATE);
1000 }
1001 #endif
1002 
1003 #if (defined(FEAT_PRINTER) && !defined(FEAT_POSTSCRIPT)) || defined(PROTO)
1004 
1005 //=================================================================
1006 // Win32 printer stuff
1007 
1008 static HFONT		prt_font_handles[2][2][2];
1009 static PRINTDLGW	prt_dlg;
1010 static const int	boldface[2] = {FW_REGULAR, FW_BOLD};
1011 static TEXTMETRIC	prt_tm;
1012 static int		prt_line_height;
1013 static int		prt_number_width;
1014 static int		prt_left_margin;
1015 static int		prt_right_margin;
1016 static int		prt_top_margin;
1017 static char_u		szAppName[] = TEXT("VIM");
1018 static HWND		hDlgPrint;
1019 static int		*bUserAbort = NULL;
1020 static char_u		*prt_name = NULL;
1021 
1022 // Defines which are also in vim.rc.
1023 # define IDC_BOX1		400
1024 # define IDC_PRINTTEXT1		401
1025 # define IDC_PRINTTEXT2		402
1026 # define IDC_PROGRESS		403
1027 
1028     static BOOL
1029 vimSetDlgItemText(HWND hDlg, int nIDDlgItem, char_u *s)
1030 {
1031     WCHAR   *wp;
1032     BOOL    ret;
1033 
1034     wp = enc_to_utf16(s, NULL);
1035     if (wp == NULL)
1036 	return FALSE;
1037 
1038     ret = SetDlgItemTextW(hDlg, nIDDlgItem, wp);
1039     vim_free(wp);
1040     return ret;
1041 }
1042 
1043 /*
1044  * Convert BGR to RGB for Windows GDI calls
1045  */
1046     static COLORREF
1047 swap_me(COLORREF colorref)
1048 {
1049     int  temp;
1050     char *ptr = (char *)&colorref;
1051 
1052     temp = *(ptr);
1053     *(ptr ) = *(ptr + 2);
1054     *(ptr + 2) = temp;
1055     return colorref;
1056 }
1057 
1058 // Attempt to make this work for old and new compilers
1059 # if !defined(_WIN64) && (!defined(_MSC_VER) || _MSC_VER < 1300)
1060 #  define PDP_RETVAL BOOL
1061 # else
1062 #  define PDP_RETVAL INT_PTR
1063 # endif
1064 
1065     static PDP_RETVAL CALLBACK
1066 PrintDlgProc(
1067 	HWND hDlg,
1068 	UINT message,
1069 	WPARAM wParam UNUSED,
1070 	LPARAM lParam UNUSED)
1071 {
1072 # ifdef FEAT_GETTEXT
1073     NONCLIENTMETRICS nm;
1074     static HFONT hfont;
1075 # endif
1076 
1077     switch (message)
1078     {
1079 	case WM_INITDIALOG:
1080 # ifdef FEAT_GETTEXT
1081 	    nm.cbSize = sizeof(NONCLIENTMETRICS);
1082 	    if (SystemParametersInfo(
1083 			SPI_GETNONCLIENTMETRICS,
1084 			sizeof(NONCLIENTMETRICS),
1085 			&nm,
1086 			0))
1087 	    {
1088 		char buff[MAX_PATH];
1089 		int i;
1090 
1091 		// Translate the dialog texts
1092 		hfont = CreateFontIndirect(&nm.lfMessageFont);
1093 		for (i = IDC_PRINTTEXT1; i <= IDC_PROGRESS; i++)
1094 		{
1095 		    SendDlgItemMessage(hDlg, i, WM_SETFONT, (WPARAM)hfont, 1);
1096 		    if (GetDlgItemText(hDlg,i, buff, sizeof(buff)))
1097 			vimSetDlgItemText(hDlg,i, (char_u *)_(buff));
1098 		}
1099 		SendDlgItemMessage(hDlg, IDCANCEL,
1100 						WM_SETFONT, (WPARAM)hfont, 1);
1101 		if (GetDlgItemText(hDlg,IDCANCEL, buff, sizeof(buff)))
1102 		    vimSetDlgItemText(hDlg,IDCANCEL, (char_u *)_(buff));
1103 	    }
1104 # endif
1105 	    SetWindowText(hDlg, (LPCSTR)szAppName);
1106 	    if (prt_name != NULL)
1107 	    {
1108 		vimSetDlgItemText(hDlg, IDC_PRINTTEXT2, (char_u *)prt_name);
1109 		VIM_CLEAR(prt_name);
1110 	    }
1111 	    EnableMenuItem(GetSystemMenu(hDlg, FALSE), SC_CLOSE, MF_GRAYED);
1112 # if !defined(FEAT_GUI) || defined(VIMDLL)
1113 #  ifdef VIMDLL
1114 	    if (!gui.in_use)
1115 #  endif
1116 		BringWindowToTop(s_hwnd);
1117 # endif
1118 	    return TRUE;
1119 
1120 	case WM_COMMAND:
1121 	    *bUserAbort = TRUE;
1122 	    EnableWindow(GetParent(hDlg), TRUE);
1123 	    DestroyWindow(hDlg);
1124 	    hDlgPrint = NULL;
1125 # ifdef FEAT_GETTEXT
1126 	    DeleteObject(hfont);
1127 # endif
1128 	    return TRUE;
1129     }
1130     return FALSE;
1131 }
1132 
1133     static BOOL CALLBACK
1134 AbortProc(HDC hdcPrn UNUSED, int iCode UNUSED)
1135 {
1136     MSG msg;
1137 
1138     while (!*bUserAbort && pPeekMessage(&msg, NULL, 0, 0, PM_REMOVE))
1139     {
1140 	if (!hDlgPrint || !pIsDialogMessage(hDlgPrint, &msg))
1141 	{
1142 	    TranslateMessage(&msg);
1143 	    pDispatchMessage(&msg);
1144 	}
1145     }
1146     return !*bUserAbort;
1147 }
1148 
1149 # if !defined(FEAT_GUI) || defined(VIMDLL)
1150 
1151     static UINT_PTR CALLBACK
1152 PrintHookProc(
1153 	HWND hDlg,	// handle to dialog box
1154 	UINT uiMsg,	// message identifier
1155 	WPARAM wParam UNUSED,	// message parameter
1156 	LPARAM lParam	// message parameter
1157 	)
1158 {
1159     HWND	hwndOwner;
1160     RECT	rc, rcDlg, rcOwner;
1161     PRINTDLGW	*pPD;
1162 
1163     if (uiMsg == WM_INITDIALOG)
1164     {
1165 	// Get the owner window and dialog box rectangles.
1166 	if ((hwndOwner = GetParent(hDlg)) == NULL)
1167 	    hwndOwner = GetDesktopWindow();
1168 
1169 	GetWindowRect(hwndOwner, &rcOwner);
1170 	GetWindowRect(hDlg, &rcDlg);
1171 	CopyRect(&rc, &rcOwner);
1172 
1173 	// Offset the owner and dialog box rectangles so that
1174 	// right and bottom values represent the width and
1175 	// height, and then offset the owner again to discard
1176 	// space taken up by the dialog box.
1177 
1178 	OffsetRect(&rcDlg, -rcDlg.left, -rcDlg.top);
1179 	OffsetRect(&rc, -rc.left, -rc.top);
1180 	OffsetRect(&rc, -rcDlg.right, -rcDlg.bottom);
1181 
1182 	// The new position is the sum of half the remaining
1183 	// space and the owner's original position.
1184 
1185 	SetWindowPos(hDlg,
1186 		HWND_TOP,
1187 		rcOwner.left + (rc.right / 2),
1188 		rcOwner.top + (rc.bottom / 2),
1189 		0, 0,		// ignores size arguments
1190 		SWP_NOSIZE);
1191 
1192 	//  tackle the printdlg copiesctrl problem
1193 	pPD = (PRINTDLGW *)lParam;
1194 	pPD->nCopies = (WORD)pPD->lCustData;
1195 	SetDlgItemInt( hDlg, edt3, pPD->nCopies, FALSE );
1196 	//  Bring the window to top
1197 	BringWindowToTop(GetParent(hDlg));
1198 	SetForegroundWindow(hDlg);
1199     }
1200 
1201     return FALSE;
1202 }
1203 # endif
1204 
1205     void
1206 mch_print_cleanup(void)
1207 {
1208     int pifItalic;
1209     int pifBold;
1210     int pifUnderline;
1211 
1212     for (pifBold = 0; pifBold <= 1; pifBold++)
1213 	for (pifItalic = 0; pifItalic <= 1; pifItalic++)
1214 	    for (pifUnderline = 0; pifUnderline <= 1; pifUnderline++)
1215 		DeleteObject(prt_font_handles[pifBold][pifItalic][pifUnderline]);
1216 
1217     if (prt_dlg.hDC != NULL)
1218 	DeleteDC(prt_dlg.hDC);
1219     if (!*bUserAbort)
1220 	SendMessage(hDlgPrint, WM_COMMAND, 0, 0);
1221 }
1222 
1223     static int
1224 to_device_units(int idx, int dpi, int physsize, int offset, int def_number)
1225 {
1226     int		ret = 0;
1227     int		u;
1228     int		nr;
1229 
1230     u = prt_get_unit(idx);
1231     if (u == PRT_UNIT_NONE)
1232     {
1233 	u = PRT_UNIT_PERC;
1234 	nr = def_number;
1235     }
1236     else
1237 	nr = printer_opts[idx].number;
1238 
1239     switch (u)
1240     {
1241 	case PRT_UNIT_PERC:
1242 	    ret = (physsize * nr) / 100;
1243 	    break;
1244 	case PRT_UNIT_INCH:
1245 	    ret = (nr * dpi);
1246 	    break;
1247 	case PRT_UNIT_MM:
1248 	    ret = (nr * 10 * dpi) / 254;
1249 	    break;
1250 	case PRT_UNIT_POINT:
1251 	    ret = (nr * 10 * dpi) / 720;
1252 	    break;
1253     }
1254 
1255     if (ret < offset)
1256 	return 0;
1257     else
1258 	return ret - offset;
1259 }
1260 
1261     static int
1262 prt_get_cpl(void)
1263 {
1264     int		hr;
1265     int		phyw;
1266     int		dvoff;
1267     int		rev_offset;
1268     int		dpi;
1269 
1270     GetTextMetrics(prt_dlg.hDC, &prt_tm);
1271     prt_line_height = prt_tm.tmHeight + prt_tm.tmExternalLeading;
1272 
1273     hr	    = GetDeviceCaps(prt_dlg.hDC, HORZRES);
1274     phyw    = GetDeviceCaps(prt_dlg.hDC, PHYSICALWIDTH);
1275     dvoff   = GetDeviceCaps(prt_dlg.hDC, PHYSICALOFFSETX);
1276     dpi	    = GetDeviceCaps(prt_dlg.hDC, LOGPIXELSX);
1277 
1278     rev_offset = phyw - (dvoff + hr);
1279 
1280     prt_left_margin = to_device_units(OPT_PRINT_LEFT, dpi, phyw, dvoff, 10);
1281     if (prt_use_number())
1282     {
1283 	prt_number_width = PRINT_NUMBER_WIDTH * prt_tm.tmAveCharWidth;
1284 	prt_left_margin += prt_number_width;
1285     }
1286     else
1287 	prt_number_width = 0;
1288 
1289     prt_right_margin = hr - to_device_units(OPT_PRINT_RIGHT, dpi, phyw,
1290 							       rev_offset, 5);
1291 
1292     return (prt_right_margin - prt_left_margin) / prt_tm.tmAveCharWidth;
1293 }
1294 
1295     static int
1296 prt_get_lpp(void)
1297 {
1298     int vr;
1299     int phyw;
1300     int dvoff;
1301     int rev_offset;
1302     int	bottom_margin;
1303     int	dpi;
1304 
1305     vr	    = GetDeviceCaps(prt_dlg.hDC, VERTRES);
1306     phyw    = GetDeviceCaps(prt_dlg.hDC, PHYSICALHEIGHT);
1307     dvoff   = GetDeviceCaps(prt_dlg.hDC, PHYSICALOFFSETY);
1308     dpi	    = GetDeviceCaps(prt_dlg.hDC, LOGPIXELSY);
1309 
1310     rev_offset = phyw - (dvoff + vr);
1311 
1312     prt_top_margin = to_device_units(OPT_PRINT_TOP, dpi, phyw, dvoff, 5);
1313 
1314     // adjust top margin if there is a header
1315     prt_top_margin += prt_line_height * prt_header_height();
1316 
1317     bottom_margin = vr - to_device_units(OPT_PRINT_BOT, dpi, phyw,
1318 							       rev_offset, 5);
1319 
1320     return (bottom_margin - prt_top_margin) / prt_line_height;
1321 }
1322 
1323     int
1324 mch_print_init(prt_settings_T *psettings, char_u *jobname, int forceit)
1325 {
1326     static HGLOBAL	stored_dm = NULL;
1327     static HGLOBAL	stored_devn = NULL;
1328     static int		stored_nCopies = 1;
1329     static int		stored_nFlags = 0;
1330 
1331     LOGFONTW		fLogFont;
1332     int			pifItalic;
1333     int			pifBold;
1334     int			pifUnderline;
1335 
1336     DEVMODEW		*mem;
1337     DEVNAMES		*devname;
1338     int			i;
1339 
1340     bUserAbort = &(psettings->user_abort);
1341     CLEAR_FIELD(prt_dlg);
1342     prt_dlg.lStructSize = sizeof(PRINTDLGW);
1343 # if !defined(FEAT_GUI) || defined(VIMDLL)
1344 #  ifdef VIMDLL
1345     if (!gui.in_use)
1346 #  endif
1347 	GetConsoleHwnd();	    // get value of s_hwnd
1348 # endif
1349     prt_dlg.hwndOwner = s_hwnd;
1350     prt_dlg.Flags = PD_NOPAGENUMS | PD_NOSELECTION | PD_RETURNDC;
1351     if (!forceit)
1352     {
1353 	prt_dlg.hDevMode = stored_dm;
1354 	prt_dlg.hDevNames = stored_devn;
1355 	prt_dlg.lCustData = stored_nCopies; // work around bug in print dialog
1356 # if !defined(FEAT_GUI) || defined(VIMDLL)
1357 #  ifdef VIMDLL
1358 	if (!gui.in_use)
1359 #  endif
1360 	{
1361 	    /*
1362 	     * Use hook to prevent console window being sent to back
1363 	     */
1364 	    prt_dlg.lpfnPrintHook = PrintHookProc;
1365 	    prt_dlg.Flags |= PD_ENABLEPRINTHOOK;
1366 	}
1367 # endif
1368 	prt_dlg.Flags |= stored_nFlags;
1369     }
1370 
1371     /*
1372      * If bang present, return default printer setup with no dialog
1373      * never show dialog if we are running over telnet
1374      */
1375     if (forceit
1376 # if !defined(FEAT_GUI) || defined(VIMDLL)
1377 #  ifdef VIMDLL
1378 	    || (!gui.in_use && !term_console)
1379 #  else
1380 	    || !term_console
1381 #  endif
1382 # endif
1383 	    )
1384     {
1385 	prt_dlg.Flags |= PD_RETURNDEFAULT;
1386 	/*
1387 	 * MSDN suggests setting the first parameter to WINSPOOL for
1388 	 * NT, but NULL appears to work just as well.
1389 	 */
1390 	if (*p_pdev != NUL)
1391 	    prt_dlg.hDC = CreateDC(NULL, (LPCSTR)p_pdev, NULL, NULL);
1392 	else
1393 	{
1394 	    prt_dlg.Flags |= PD_RETURNDEFAULT;
1395 	    if (PrintDlgW(&prt_dlg) == 0)
1396 		goto init_fail_dlg;
1397 	}
1398     }
1399     else if (PrintDlgW(&prt_dlg) == 0)
1400 	goto init_fail_dlg;
1401     else
1402     {
1403 	/*
1404 	 * keep the previous driver context
1405 	 */
1406 	stored_dm = prt_dlg.hDevMode;
1407 	stored_devn = prt_dlg.hDevNames;
1408 	stored_nFlags = prt_dlg.Flags;
1409 	stored_nCopies = prt_dlg.nCopies;
1410     }
1411 
1412     if (prt_dlg.hDC == NULL)
1413     {
1414 	emsg(_("E237: Printer selection failed"));
1415 	mch_print_cleanup();
1416 	return FALSE;
1417     }
1418 
1419     // Not all printer drivers report the support of color (or grey) in the
1420     // same way.  Let's set has_color if there appears to be some way to print
1421     // more than B&W.
1422     i = GetDeviceCaps(prt_dlg.hDC, NUMCOLORS);
1423     psettings->has_color = (GetDeviceCaps(prt_dlg.hDC, BITSPIXEL) > 1
1424 				   || GetDeviceCaps(prt_dlg.hDC, PLANES) > 1
1425 				   || i > 2 || i == -1);
1426 
1427     // Ensure all font styles are baseline aligned
1428     SetTextAlign(prt_dlg.hDC, TA_BASELINE|TA_LEFT);
1429 
1430     /*
1431      * On some windows systems the nCopies parameter is not
1432      * passed back correctly. It must be retrieved from the
1433      * hDevMode struct.
1434      */
1435     mem = (DEVMODEW *)GlobalLock(prt_dlg.hDevMode);
1436     if (mem != NULL)
1437     {
1438 	if (mem->dmCopies != 1)
1439 	    stored_nCopies = mem->dmCopies;
1440 	if ((mem->dmFields & DM_DUPLEX) && (mem->dmDuplex & ~DMDUP_SIMPLEX))
1441 	    psettings->duplex = TRUE;
1442 	if ((mem->dmFields & DM_COLOR) && (mem->dmColor & DMCOLOR_COLOR))
1443 	    psettings->has_color = TRUE;
1444     }
1445     GlobalUnlock(prt_dlg.hDevMode);
1446 
1447     devname = (DEVNAMES *)GlobalLock(prt_dlg.hDevNames);
1448     if (devname != 0)
1449     {
1450 	WCHAR	*wprinter_name = (WCHAR *)devname + devname->wDeviceOffset;
1451 	WCHAR	*wport_name = (WCHAR *)devname + devname->wOutputOffset;
1452 	char_u	*text = (char_u *)_("to %s on %s");
1453 	char_u  *printer_name = utf16_to_enc(wprinter_name, NULL);
1454 	char_u	*port_name = utf16_to_enc(wport_name, NULL);
1455 
1456 	if (printer_name != NULL && port_name != NULL)
1457 	    prt_name = alloc(STRLEN(printer_name)
1458 					   + STRLEN(port_name) + STRLEN(text));
1459 	if (prt_name != NULL)
1460 	    wsprintf((char *)prt_name, (const char *)text,
1461 		    printer_name, port_name);
1462 	vim_free(printer_name);
1463 	vim_free(port_name);
1464     }
1465     GlobalUnlock(prt_dlg.hDevNames);
1466 
1467     /*
1468      * Initialise the font according to 'printfont'
1469      */
1470     CLEAR_FIELD(fLogFont);
1471     if (get_logfont(&fLogFont, p_pfn, prt_dlg.hDC, TRUE) == FAIL)
1472     {
1473 	semsg(_("E613: Unknown printer font: %s"), p_pfn);
1474 	mch_print_cleanup();
1475 	return FALSE;
1476     }
1477 
1478     for (pifBold = 0; pifBold <= 1; pifBold++)
1479 	for (pifItalic = 0; pifItalic <= 1; pifItalic++)
1480 	    for (pifUnderline = 0; pifUnderline <= 1; pifUnderline++)
1481 	    {
1482 		fLogFont.lfWeight =  boldface[pifBold];
1483 		fLogFont.lfItalic = pifItalic;
1484 		fLogFont.lfUnderline = pifUnderline;
1485 		prt_font_handles[pifBold][pifItalic][pifUnderline]
1486 					      = CreateFontIndirectW(&fLogFont);
1487 	    }
1488 
1489     SetBkMode(prt_dlg.hDC, OPAQUE);
1490     SelectObject(prt_dlg.hDC, prt_font_handles[0][0][0]);
1491 
1492     /*
1493      * Fill in the settings struct
1494      */
1495     psettings->chars_per_line = prt_get_cpl();
1496     psettings->lines_per_page = prt_get_lpp();
1497     if (prt_dlg.Flags & PD_USEDEVMODECOPIESANDCOLLATE)
1498     {
1499 	psettings->n_collated_copies = (prt_dlg.Flags & PD_COLLATE)
1500 						    ? prt_dlg.nCopies : 1;
1501 	psettings->n_uncollated_copies = (prt_dlg.Flags & PD_COLLATE)
1502 						    ? 1 : prt_dlg.nCopies;
1503 
1504 	if (psettings->n_collated_copies == 0)
1505 	    psettings->n_collated_copies = 1;
1506 
1507 	if (psettings->n_uncollated_copies == 0)
1508 	    psettings->n_uncollated_copies = 1;
1509     }
1510     else
1511     {
1512 	psettings->n_collated_copies = 1;
1513 	psettings->n_uncollated_copies = 1;
1514     }
1515 
1516     psettings->jobname = jobname;
1517 
1518     return TRUE;
1519 
1520 init_fail_dlg:
1521     {
1522 	DWORD err = CommDlgExtendedError();
1523 
1524 	if (err)
1525 	{
1526 	    char_u *buf;
1527 
1528 	    // I suspect FormatMessage() doesn't work for values returned by
1529 	    // CommDlgExtendedError().  What does?
1530 	    FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER |
1531 			  FORMAT_MESSAGE_FROM_SYSTEM |
1532 			  FORMAT_MESSAGE_IGNORE_INSERTS,
1533 			  NULL, err, 0, (LPTSTR)(&buf), 0, NULL);
1534 	    semsg(_("E238: Print error: %s"),
1535 				  buf == NULL ? (char_u *)_("Unknown") : buf);
1536 	    LocalFree((LPVOID)(buf));
1537 	}
1538 	else
1539 	    msg_clr_eos(); // Maybe canceled
1540 
1541 	mch_print_cleanup();
1542 	return FALSE;
1543     }
1544 }
1545 
1546 
1547     int
1548 mch_print_begin(prt_settings_T *psettings)
1549 {
1550     int			ret = 0;
1551     char		szBuffer[300];
1552     WCHAR		*wp;
1553 
1554     hDlgPrint = CreateDialog(g_hinst, TEXT("PrintDlgBox"),
1555 					     prt_dlg.hwndOwner, PrintDlgProc);
1556     SetAbortProc(prt_dlg.hDC, AbortProc);
1557     wsprintf(szBuffer, _("Printing '%s'"), gettail(psettings->jobname));
1558     vimSetDlgItemText(hDlgPrint, IDC_PRINTTEXT1, (char_u *)szBuffer);
1559 
1560     wp = enc_to_utf16(psettings->jobname, NULL);
1561     if (wp != NULL)
1562     {
1563 	DOCINFOW	di;
1564 
1565 	CLEAR_FIELD(di);
1566 	di.cbSize = sizeof(di);
1567 	di.lpszDocName = wp;
1568 	ret = StartDocW(prt_dlg.hDC, &di);
1569 	vim_free(wp);
1570     }
1571 
1572 # ifdef FEAT_GUI
1573     // Give focus back to main window (when using MDI).
1574 #  ifdef VIMDLL
1575     if (gui.in_use)
1576 #  endif
1577 	SetFocus(s_hwnd);
1578 # endif
1579 
1580     return (ret > 0);
1581 }
1582 
1583     void
1584 mch_print_end(prt_settings_T *psettings UNUSED)
1585 {
1586     EndDoc(prt_dlg.hDC);
1587     if (!*bUserAbort)
1588 	SendMessage(hDlgPrint, WM_COMMAND, 0, 0);
1589 }
1590 
1591     int
1592 mch_print_end_page(void)
1593 {
1594     return (EndPage(prt_dlg.hDC) > 0);
1595 }
1596 
1597     int
1598 mch_print_begin_page(char_u *msg)
1599 {
1600     if (msg != NULL)
1601 	vimSetDlgItemText(hDlgPrint, IDC_PROGRESS, msg);
1602     return (StartPage(prt_dlg.hDC) > 0);
1603 }
1604 
1605     int
1606 mch_print_blank_page(void)
1607 {
1608     return (mch_print_begin_page(NULL) ? (mch_print_end_page()) : FALSE);
1609 }
1610 
1611 static int prt_pos_x = 0;
1612 static int prt_pos_y = 0;
1613 
1614     void
1615 mch_print_start_line(int margin, int page_line)
1616 {
1617     if (margin)
1618 	prt_pos_x = -prt_number_width;
1619     else
1620 	prt_pos_x = 0;
1621     prt_pos_y = page_line * prt_line_height
1622 				 + prt_tm.tmAscent + prt_tm.tmExternalLeading;
1623 }
1624 
1625     int
1626 mch_print_text_out(char_u *p, int len)
1627 {
1628     SIZE	sz;
1629     WCHAR	*wp;
1630     int		wlen = len;
1631     int		ret = FALSE;
1632 
1633     wp = enc_to_utf16(p, &wlen);
1634     if (wp == NULL)
1635 	return FALSE;
1636 
1637     TextOutW(prt_dlg.hDC, prt_pos_x + prt_left_margin,
1638 	    prt_pos_y + prt_top_margin, wp, wlen);
1639     GetTextExtentPoint32W(prt_dlg.hDC, wp, wlen, &sz);
1640     vim_free(wp);
1641     prt_pos_x += (sz.cx - prt_tm.tmOverhang);
1642     // This is wrong when printing spaces for a TAB.
1643     if (p[len] != NUL)
1644     {
1645 	wlen = mb_ptr2len(p + len);
1646 	wp = enc_to_utf16(p + len, &wlen);
1647 	if (wp != NULL)
1648 	{
1649 	    GetTextExtentPoint32W(prt_dlg.hDC, wp, 1, &sz);
1650 	    ret = (prt_pos_x + prt_left_margin + sz.cx > prt_right_margin);
1651 	    vim_free(wp);
1652 	}
1653     }
1654     return ret;
1655 }
1656 
1657     void
1658 mch_print_set_font(int iBold, int iItalic, int iUnderline)
1659 {
1660     SelectObject(prt_dlg.hDC, prt_font_handles[iBold][iItalic][iUnderline]);
1661 }
1662 
1663     void
1664 mch_print_set_bg(long_u bgcol)
1665 {
1666     SetBkColor(prt_dlg.hDC, GetNearestColor(prt_dlg.hDC,
1667 						   swap_me((COLORREF)bgcol)));
1668     /*
1669      * With a white background we can draw characters transparent, which is
1670      * good for italic characters that overlap to the next char cell.
1671      */
1672     if (bgcol == 0xffffffUL)
1673 	SetBkMode(prt_dlg.hDC, TRANSPARENT);
1674     else
1675 	SetBkMode(prt_dlg.hDC, OPAQUE);
1676 }
1677 
1678     void
1679 mch_print_set_fg(long_u fgcol)
1680 {
1681     SetTextColor(prt_dlg.hDC, GetNearestColor(prt_dlg.hDC,
1682 						   swap_me((COLORREF)fgcol)));
1683 }
1684 
1685 #endif // FEAT_PRINTER && !FEAT_POSTSCRIPT
1686 
1687 
1688 
1689 #if defined(FEAT_SHORTCUT) || defined(PROTO)
1690 # ifndef PROTO
1691 #  include <shlobj.h>
1692 # endif
1693 
1694 typedef BOOL (WINAPI *pfnGetFinalPathNameByHandleW)(
1695 	HANDLE	hFile,
1696 	LPWSTR	lpszFilePath,
1697 	DWORD	cchFilePath,
1698 	DWORD	dwFlags);
1699 static pfnGetFinalPathNameByHandleW pGetFinalPathNameByHandleW = NULL;
1700 
1701 # define is_path_sep(c)	    ((c) == L'\\' || (c) == L'/')
1702 
1703     static int
1704 is_reparse_point_included(LPCWSTR fname)
1705 {
1706     LPCWSTR	p = fname, q;
1707     WCHAR	buf[MAX_PATH];
1708     DWORD	attr;
1709 
1710     if (isalpha(p[0]) && p[1] == L':' && is_path_sep(p[2]))
1711 	p += 3;
1712     else if (is_path_sep(p[0]) && is_path_sep(p[1]))
1713 	p += 2;
1714 
1715     while (*p != L'\0')
1716     {
1717 	q = wcspbrk(p, L"\\/");
1718 	if (q == NULL)
1719 	    p = q = fname + wcslen(fname);
1720 	else
1721 	    p = q + 1;
1722 	if (q - fname >= MAX_PATH)
1723 	    return FALSE;
1724 	wcsncpy(buf, fname, q - fname);
1725 	buf[q - fname] = L'\0';
1726 	attr = GetFileAttributesW(buf);
1727 	if (attr != INVALID_FILE_ATTRIBUTES
1728 		&& (attr & FILE_ATTRIBUTE_REPARSE_POINT) != 0)
1729 	    return TRUE;
1730     }
1731     return FALSE;
1732 }
1733 
1734     static char_u *
1735 resolve_reparse_point(char_u *fname)
1736 {
1737     HANDLE	    h = INVALID_HANDLE_VALUE;
1738     DWORD	    size;
1739     WCHAR	    *p, *wp;
1740     char_u	    *rfname = NULL;
1741     WCHAR	    *buff = NULL;
1742     static BOOL	    loaded = FALSE;
1743 
1744     if (pGetFinalPathNameByHandleW == NULL)
1745     {
1746 	HMODULE hmod = GetModuleHandle("kernel32.dll");
1747 
1748 	if (loaded == TRUE)
1749 	    return NULL;
1750 	pGetFinalPathNameByHandleW = (pfnGetFinalPathNameByHandleW)
1751 		GetProcAddress(hmod, "GetFinalPathNameByHandleW");
1752 	loaded = TRUE;
1753 	if (pGetFinalPathNameByHandleW == NULL)
1754 	    return NULL;
1755     }
1756 
1757     p = enc_to_utf16(fname, NULL);
1758     if (p == NULL)
1759 	goto fail;
1760 
1761     if (!is_reparse_point_included(p))
1762     {
1763 	vim_free(p);
1764 	goto fail;
1765     }
1766 
1767     h = CreateFileW(p, 0, 0, NULL, OPEN_EXISTING,
1768 	    FILE_FLAG_BACKUP_SEMANTICS, NULL);
1769     vim_free(p);
1770 
1771     if (h == INVALID_HANDLE_VALUE)
1772 	goto fail;
1773 
1774     size = pGetFinalPathNameByHandleW(h, NULL, 0, 0);
1775     if (size == 0)
1776 	goto fail;
1777     buff = ALLOC_MULT(WCHAR, size);
1778     if (buff == NULL)
1779 	goto fail;
1780     if (pGetFinalPathNameByHandleW(h, buff, size, 0) == 0)
1781 	goto fail;
1782 
1783     if (wcsncmp(buff, L"\\\\?\\UNC\\", 8) == 0)
1784     {
1785 	buff[6] = L'\\';
1786 	wp = buff + 6;
1787     }
1788     else if (wcsncmp(buff, L"\\\\?\\", 4) == 0)
1789 	wp = buff + 4;
1790     else
1791 	wp = buff;
1792 
1793     rfname = utf16_to_enc(wp, NULL);
1794 
1795 fail:
1796     if (h != INVALID_HANDLE_VALUE)
1797 	CloseHandle(h);
1798     if (buff != NULL)
1799 	vim_free(buff);
1800 
1801     return rfname;
1802 }
1803 
1804 /*
1805  * When "fname" is the name of a shortcut (*.lnk) resolve the file it points
1806  * to and return that name in allocated memory.
1807  * Otherwise NULL is returned.
1808  */
1809     static char_u *
1810 resolve_shortcut(char_u *fname)
1811 {
1812     HRESULT		hr;
1813     IShellLink		*psl = NULL;
1814     IPersistFile	*ppf = NULL;
1815     OLECHAR		wsz[MAX_PATH];
1816     char_u		*rfname = NULL;
1817     int			len;
1818     IShellLinkW		*pslw = NULL;
1819     WIN32_FIND_DATAW	ffdw; // we get those free of charge
1820 
1821     // Check if the file name ends in ".lnk". Avoid calling
1822     // CoCreateInstance(), it's quite slow.
1823     if (fname == NULL)
1824 	return rfname;
1825     len = (int)STRLEN(fname);
1826     if (len <= 4 || STRNICMP(fname + len - 4, ".lnk", 4) != 0)
1827 	return rfname;
1828 
1829     CoInitialize(NULL);
1830 
1831     // create a link manager object and request its interface
1832     hr = CoCreateInstance(
1833 	    &CLSID_ShellLink, NULL, CLSCTX_INPROC_SERVER,
1834 	    &IID_IShellLinkW, (void**)&pslw);
1835     if (hr == S_OK)
1836     {
1837 	WCHAR	*p = enc_to_utf16(fname, NULL);
1838 
1839 	if (p != NULL)
1840 	{
1841 	    // Get a pointer to the IPersistFile interface.
1842 	    hr = pslw->lpVtbl->QueryInterface(
1843 		    pslw, &IID_IPersistFile, (void**)&ppf);
1844 	    if (hr != S_OK)
1845 		goto shortcut_errorw;
1846 
1847 	    // "load" the name and resolve the link
1848 	    hr = ppf->lpVtbl->Load(ppf, p, STGM_READ);
1849 	    if (hr != S_OK)
1850 		goto shortcut_errorw;
1851 # if 0  // This makes Vim wait a long time if the target does not exist.
1852 	    hr = pslw->lpVtbl->Resolve(pslw, NULL, SLR_NO_UI);
1853 	    if (hr != S_OK)
1854 		goto shortcut_errorw;
1855 # endif
1856 
1857 	    // Get the path to the link target.
1858 	    ZeroMemory(wsz, MAX_PATH * sizeof(WCHAR));
1859 	    hr = pslw->lpVtbl->GetPath(pslw, wsz, MAX_PATH, &ffdw, 0);
1860 	    if (hr == S_OK && wsz[0] != NUL)
1861 		rfname = utf16_to_enc(wsz, NULL);
1862 
1863 shortcut_errorw:
1864 	    vim_free(p);
1865 	}
1866     }
1867 
1868     // Release all interface pointers (both belong to the same object)
1869     if (ppf != NULL)
1870 	ppf->lpVtbl->Release(ppf);
1871     if (psl != NULL)
1872 	psl->lpVtbl->Release(psl);
1873     if (pslw != NULL)
1874 	pslw->lpVtbl->Release(pslw);
1875 
1876     CoUninitialize();
1877     return rfname;
1878 }
1879 
1880     char_u *
1881 mch_resolve_path(char_u *fname, int reparse_point)
1882 {
1883     char_u  *path = resolve_shortcut(fname);
1884 
1885     if (path == NULL && reparse_point)
1886 	path = resolve_reparse_point(fname);
1887     return path;
1888 }
1889 #endif
1890 
1891 #if (defined(FEAT_EVAL) && (!defined(FEAT_GUI) || defined(VIMDLL))) || defined(PROTO)
1892 /*
1893  * Bring ourselves to the foreground.  Does work if the OS doesn't allow it.
1894  */
1895     void
1896 win32_set_foreground(void)
1897 {
1898     GetConsoleHwnd();	    // get value of s_hwnd
1899     if (s_hwnd != 0)
1900 	SetForegroundWindow(s_hwnd);
1901 }
1902 #endif
1903 
1904 #if defined(FEAT_CLIENTSERVER) || defined(PROTO)
1905 /*
1906  * Client-server code for Vim
1907  *
1908  * Originally written by Paul Moore
1909  */
1910 
1911 // In order to handle inter-process messages, we need to have a window. But
1912 // the functions in this module can be called before the main GUI window is
1913 // created (and may also be called in the console version, where there is no
1914 // GUI window at all).
1915 //
1916 // So we create a hidden window, and arrange to destroy it on exit.
1917 HWND message_window = 0;	    // window that's handling messages
1918 
1919 # define VIM_CLASSNAME      "VIM_MESSAGES"
1920 # define VIM_CLASSNAME_LEN  (sizeof(VIM_CLASSNAME) - 1)
1921 
1922 // Communication is via WM_COPYDATA messages. The message type is send in
1923 // the dwData parameter. Types are defined here.
1924 # define COPYDATA_KEYS		0
1925 # define COPYDATA_REPLY		1
1926 # define COPYDATA_EXPR		10
1927 # define COPYDATA_RESULT	11
1928 # define COPYDATA_ERROR_RESULT	12
1929 # define COPYDATA_ENCODING	20
1930 
1931 // This is a structure containing a server HWND and its name.
1932 struct server_id
1933 {
1934     HWND hwnd;
1935     char_u *name;
1936 };
1937 
1938 // Last received 'encoding' that the client uses.
1939 static char_u	*client_enc = NULL;
1940 
1941 /*
1942  * Tell the other side what encoding we are using.
1943  * Errors are ignored.
1944  */
1945     static void
1946 serverSendEnc(HWND target)
1947 {
1948     COPYDATASTRUCT data;
1949 
1950     data.dwData = COPYDATA_ENCODING;
1951     data.cbData = (DWORD)STRLEN(p_enc) + 1;
1952     data.lpData = p_enc;
1953     (void)SendMessage(target, WM_COPYDATA, (WPARAM)message_window,
1954 							     (LPARAM)(&data));
1955 }
1956 
1957 /*
1958  * Clean up on exit. This destroys the hidden message window.
1959  */
1960     static void
1961 CleanUpMessaging(void)
1962 {
1963     if (message_window != 0)
1964     {
1965 	DestroyWindow(message_window);
1966 	message_window = 0;
1967     }
1968 }
1969 
1970 static int save_reply(HWND server, char_u *reply, int expr);
1971 
1972 /*
1973  * The window procedure for the hidden message window.
1974  * It handles callback messages and notifications from servers.
1975  * In order to process these messages, it is necessary to run a
1976  * message loop. Code which may run before the main message loop
1977  * is started (in the GUI) is careful to pump messages when it needs
1978  * to. Features which require message delivery during normal use will
1979  * not work in the console version - this basically means those
1980  * features which allow Vim to act as a server, rather than a client.
1981  */
1982     static LRESULT CALLBACK
1983 Messaging_WndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
1984 {
1985     if (msg == WM_COPYDATA)
1986     {
1987 	// This is a message from another Vim. The dwData member of the
1988 	// COPYDATASTRUCT determines the type of message:
1989 	//   COPYDATA_ENCODING:
1990 	//	The encoding that the client uses. Following messages will
1991 	//	use this encoding, convert if needed.
1992 	//   COPYDATA_KEYS:
1993 	//	A key sequence. We are a server, and a client wants these keys
1994 	//	adding to the input queue.
1995 	//   COPYDATA_REPLY:
1996 	//	A reply. We are a client, and a server has sent this message
1997 	//	in response to a request.  (server2client())
1998 	//   COPYDATA_EXPR:
1999 	//	An expression. We are a server, and a client wants us to
2000 	//	evaluate this expression.
2001 	//   COPYDATA_RESULT:
2002 	//	A reply. We are a client, and a server has sent this message
2003 	//	in response to a COPYDATA_EXPR.
2004 	//   COPYDATA_ERROR_RESULT:
2005 	//	A reply. We are a client, and a server has sent this message
2006 	//	in response to a COPYDATA_EXPR that failed to evaluate.
2007 	COPYDATASTRUCT	*data = (COPYDATASTRUCT*)lParam;
2008 	HWND		sender = (HWND)wParam;
2009 	COPYDATASTRUCT	reply;
2010 	char_u		*res;
2011 	int		retval;
2012 	char_u		*str;
2013 	char_u		*tofree;
2014 
2015 	switch (data->dwData)
2016 	{
2017 	case COPYDATA_ENCODING:
2018 	    // Remember the encoding that the client uses.
2019 	    vim_free(client_enc);
2020 	    client_enc = enc_canonize((char_u *)data->lpData);
2021 	    return 1;
2022 
2023 	case COPYDATA_KEYS:
2024 	    // Remember who sent this, for <client>
2025 	    clientWindow = sender;
2026 
2027 	    // Add the received keys to the input buffer.  The loop waiting
2028 	    // for the user to do something should check the input buffer.
2029 	    str = serverConvert(client_enc, (char_u *)data->lpData, &tofree);
2030 	    server_to_input_buf(str);
2031 	    vim_free(tofree);
2032 
2033 # ifdef FEAT_GUI
2034 	    // Wake up the main GUI loop.
2035 #  ifdef VIMDLL
2036 	    if (gui.in_use)
2037 #  endif
2038 		if (s_hwnd != 0)
2039 		    PostMessage(s_hwnd, WM_NULL, 0, 0);
2040 # endif
2041 	    return 1;
2042 
2043 	case COPYDATA_EXPR:
2044 	    // Remember who sent this, for <client>
2045 	    clientWindow = sender;
2046 
2047 	    str = serverConvert(client_enc, (char_u *)data->lpData, &tofree);
2048 	    res = eval_client_expr_to_string(str);
2049 
2050 	    if (res == NULL)
2051 	    {
2052 		char	*err = _(e_invexprmsg);
2053 		size_t	len = STRLEN(str) + STRLEN(err) + 5;
2054 
2055 		res = alloc(len);
2056 		if (res != NULL)
2057 		    vim_snprintf((char *)res, len, "%s: \"%s\"", err, str);
2058 		reply.dwData = COPYDATA_ERROR_RESULT;
2059 	    }
2060 	    else
2061 		reply.dwData = COPYDATA_RESULT;
2062 	    reply.lpData = res;
2063 	    reply.cbData = (DWORD)STRLEN(res) + 1;
2064 
2065 	    serverSendEnc(sender);
2066 	    retval = (int)SendMessage(sender, WM_COPYDATA,
2067 				    (WPARAM)message_window, (LPARAM)(&reply));
2068 	    vim_free(tofree);
2069 	    vim_free(res);
2070 	    return retval;
2071 
2072 	case COPYDATA_REPLY:
2073 	case COPYDATA_RESULT:
2074 	case COPYDATA_ERROR_RESULT:
2075 	    if (data->lpData != NULL)
2076 	    {
2077 		str = serverConvert(client_enc, (char_u *)data->lpData,
2078 								     &tofree);
2079 		if (tofree == NULL)
2080 		    str = vim_strsave(str);
2081 		if (save_reply(sender, str,
2082 			   (data->dwData == COPYDATA_REPLY ?  0 :
2083 			   (data->dwData == COPYDATA_RESULT ? 1 :
2084 							      2))) == FAIL)
2085 		    vim_free(str);
2086 		else if (data->dwData == COPYDATA_REPLY)
2087 		{
2088 		    char_u	winstr[30];
2089 
2090 		    sprintf((char *)winstr, PRINTF_HEX_LONG_U, (long_u)sender);
2091 		    apply_autocmds(EVENT_REMOTEREPLY, winstr, str,
2092 								TRUE, curbuf);
2093 		}
2094 	    }
2095 	    return 1;
2096 	}
2097 
2098 	return 0;
2099     }
2100 
2101     else if (msg == WM_ACTIVATE && wParam == WA_ACTIVE)
2102     {
2103 	// When the message window is activated (brought to the foreground),
2104 	// this actually applies to the text window.
2105 # if !defined(FEAT_GUI) || defined(VIMDLL)
2106 #  ifdef VIMDLL
2107 	if (!gui.in_use)
2108 #  endif
2109 	    GetConsoleHwnd();	    // get value of s_hwnd
2110 # endif
2111 	if (s_hwnd != 0)
2112 	{
2113 	    SetForegroundWindow(s_hwnd);
2114 	    return 0;
2115 	}
2116     }
2117 
2118     return DefWindowProc(hwnd, msg, wParam, lParam);
2119 }
2120 
2121 /*
2122  * Initialise the message handling process.  This involves creating a window
2123  * to handle messages - the window will not be visible.
2124  */
2125     void
2126 serverInitMessaging(void)
2127 {
2128     WNDCLASS wndclass;
2129 
2130     // Clean up on exit
2131     atexit(CleanUpMessaging);
2132 
2133     // Register a window class - we only really care
2134     // about the window procedure
2135     wndclass.style = 0;
2136     wndclass.lpfnWndProc = Messaging_WndProc;
2137     wndclass.cbClsExtra = 0;
2138     wndclass.cbWndExtra = 0;
2139     wndclass.hInstance = g_hinst;
2140     wndclass.hIcon = NULL;
2141     wndclass.hCursor = NULL;
2142     wndclass.hbrBackground = NULL;
2143     wndclass.lpszMenuName = NULL;
2144     wndclass.lpszClassName = VIM_CLASSNAME;
2145     RegisterClass(&wndclass);
2146 
2147     // Create the message window. It will be hidden, so the details don't
2148     // matter.  Don't use WS_OVERLAPPEDWINDOW, it will make a shortcut remove
2149     // focus from gvim.
2150     message_window = CreateWindow(VIM_CLASSNAME, "",
2151 			 WS_POPUPWINDOW | WS_CAPTION,
2152 			 CW_USEDEFAULT, CW_USEDEFAULT,
2153 			 100, 100, NULL, NULL,
2154 			 g_hinst, NULL);
2155 }
2156 
2157 // Used by serverSendToVim() to find an alternate server name.
2158 static char_u *altname_buf_ptr = NULL;
2159 
2160 /*
2161  * Get the title of the window "hwnd", which is the Vim server name, in
2162  * "name[namelen]" and return the length.
2163  * Returns zero if window "hwnd" is not a Vim server.
2164  */
2165     static int
2166 getVimServerName(HWND hwnd, char *name, int namelen)
2167 {
2168     int		len;
2169     char	buffer[VIM_CLASSNAME_LEN + 1];
2170 
2171     // Ignore windows which aren't Vim message windows
2172     len = GetClassName(hwnd, buffer, sizeof(buffer));
2173     if (len != VIM_CLASSNAME_LEN || STRCMP(buffer, VIM_CLASSNAME) != 0)
2174 	return 0;
2175 
2176     // Get the title of the window
2177     return GetWindowText(hwnd, name, namelen);
2178 }
2179 
2180     static BOOL CALLBACK
2181 enumWindowsGetServer(HWND hwnd, LPARAM lparam)
2182 {
2183     struct	server_id *id = (struct server_id *)lparam;
2184     char	server[MAX_PATH];
2185 
2186     // Get the title of the window
2187     if (getVimServerName(hwnd, server, sizeof(server)) == 0)
2188 	return TRUE;
2189 
2190     // If this is the server we're looking for, return its HWND
2191     if (STRICMP(server, id->name) == 0)
2192     {
2193 	id->hwnd = hwnd;
2194 	return FALSE;
2195     }
2196 
2197     // If we are looking for an alternate server, remember this name.
2198     if (altname_buf_ptr != NULL
2199 	    && STRNICMP(server, id->name, STRLEN(id->name)) == 0
2200 	    && vim_isdigit(server[STRLEN(id->name)]))
2201     {
2202 	STRCPY(altname_buf_ptr, server);
2203 	altname_buf_ptr = NULL;	    // don't use another name
2204     }
2205 
2206     // Otherwise, keep looking
2207     return TRUE;
2208 }
2209 
2210     static BOOL CALLBACK
2211 enumWindowsGetNames(HWND hwnd, LPARAM lparam)
2212 {
2213     garray_T	*ga = (garray_T *)lparam;
2214     char	server[MAX_PATH];
2215 
2216     // Get the title of the window
2217     if (getVimServerName(hwnd, server, sizeof(server)) == 0)
2218 	return TRUE;
2219 
2220     // Add the name to the list
2221     ga_concat(ga, (char_u *)server);
2222     ga_concat(ga, (char_u *)"\n");
2223     return TRUE;
2224 }
2225 
2226 struct enum_windows_s
2227 {
2228     WNDENUMPROC lpEnumFunc;
2229     LPARAM      lParam;
2230 };
2231 
2232     static BOOL CALLBACK
2233 enum_windows_child(HWND hwnd, LPARAM lParam)
2234 {
2235     struct enum_windows_s *ew = (struct enum_windows_s *)lParam;
2236 
2237     return (ew->lpEnumFunc)(hwnd, ew->lParam);
2238 }
2239 
2240     static BOOL CALLBACK
2241 enum_windows_toplevel(HWND hwnd, LPARAM lParam)
2242 {
2243     struct enum_windows_s *ew = (struct enum_windows_s *)lParam;
2244 
2245     if ((ew->lpEnumFunc)(hwnd, ew->lParam))
2246 	return TRUE;
2247     return EnumChildWindows(hwnd, enum_windows_child, lParam);
2248 }
2249 
2250 /*
2251  * Enumerate all windows including children.
2252  */
2253     static BOOL
2254 enum_windows(WNDENUMPROC lpEnumFunc, LPARAM lParam)
2255 {
2256     struct enum_windows_s ew;
2257 
2258     ew.lpEnumFunc = lpEnumFunc;
2259     ew.lParam = lParam;
2260     return EnumWindows(enum_windows_toplevel, (LPARAM)&ew);
2261 }
2262 
2263     static HWND
2264 findServer(char_u *name)
2265 {
2266     struct server_id id;
2267 
2268     id.name = name;
2269     id.hwnd = 0;
2270 
2271     enum_windows(enumWindowsGetServer, (LPARAM)(&id));
2272 
2273     return id.hwnd;
2274 }
2275 
2276     void
2277 serverSetName(char_u *name)
2278 {
2279     char_u	*ok_name;
2280     HWND	hwnd = 0;
2281     int		i = 0;
2282     char_u	*p;
2283 
2284     // Leave enough space for a 9-digit suffix to ensure uniqueness!
2285     ok_name = alloc(STRLEN(name) + 10);
2286 
2287     STRCPY(ok_name, name);
2288     p = ok_name + STRLEN(name);
2289 
2290     for (;;)
2291     {
2292 	// This is inefficient - we're doing an EnumWindows loop for each
2293 	// possible name. It would be better to grab all names in one go,
2294 	// and scan the list each time...
2295 	hwnd = findServer(ok_name);
2296 	if (hwnd == 0)
2297 	    break;
2298 
2299 	++i;
2300 	if (i >= 1000)
2301 	    break;
2302 
2303 	sprintf((char *)p, "%d", i);
2304     }
2305 
2306     if (hwnd != 0)
2307 	vim_free(ok_name);
2308     else
2309     {
2310 	// Remember the name
2311 	serverName = ok_name;
2312 # ifdef FEAT_TITLE
2313 	need_maketitle = TRUE;	// update Vim window title later
2314 # endif
2315 
2316 	// Update the message window title
2317 	SetWindowText(message_window, (LPCSTR)ok_name);
2318 
2319 # ifdef FEAT_EVAL
2320 	// Set the servername variable
2321 	set_vim_var_string(VV_SEND_SERVER, serverName, -1);
2322 # endif
2323     }
2324 }
2325 
2326     char_u *
2327 serverGetVimNames(void)
2328 {
2329     garray_T ga;
2330 
2331     ga_init2(&ga, 1, 100);
2332 
2333     enum_windows(enumWindowsGetNames, (LPARAM)(&ga));
2334     ga_append(&ga, NUL);
2335 
2336     return ga.ga_data;
2337 }
2338 
2339     int
2340 serverSendReply(
2341     char_u	*name,		// Where to send.
2342     char_u	*reply)		// What to send.
2343 {
2344     HWND	target;
2345     COPYDATASTRUCT data;
2346     long_u	n = 0;
2347 
2348     // The "name" argument is a magic cookie obtained from expand("<client>").
2349     // It should be of the form 0xXXXXX - i.e. a C hex literal, which is the
2350     // value of the client's message window HWND.
2351     sscanf((char *)name, SCANF_HEX_LONG_U, &n);
2352     if (n == 0)
2353 	return -1;
2354 
2355     target = (HWND)n;
2356     if (!IsWindow(target))
2357 	return -1;
2358 
2359     data.dwData = COPYDATA_REPLY;
2360     data.cbData = (DWORD)STRLEN(reply) + 1;
2361     data.lpData = reply;
2362 
2363     serverSendEnc(target);
2364     if (SendMessage(target, WM_COPYDATA, (WPARAM)message_window,
2365 							     (LPARAM)(&data)))
2366 	return 0;
2367 
2368     return -1;
2369 }
2370 
2371     int
2372 serverSendToVim(
2373     char_u	 *name,			// Where to send.
2374     char_u	 *cmd,			// What to send.
2375     char_u	 **result,		// Result of eval'ed expression
2376     void	 *ptarget,		// HWND of server
2377     int		 asExpr,		// Expression or keys?
2378     int		 timeout,		// timeout in seconds or zero
2379     int		 silent)		// don't complain about no server
2380 {
2381     HWND	target;
2382     COPYDATASTRUCT data;
2383     char_u	*retval = NULL;
2384     int		retcode = 0;
2385     char_u	altname_buf[MAX_PATH];
2386 
2387     // Execute locally if no display or target is ourselves
2388     if (serverName != NULL && STRICMP(name, serverName) == 0)
2389 	return sendToLocalVim(cmd, asExpr, result);
2390 
2391     // If the server name does not end in a digit then we look for an
2392     // alternate name.  e.g. when "name" is GVIM the we may find GVIM2.
2393     if (STRLEN(name) > 1 && !vim_isdigit(name[STRLEN(name) - 1]))
2394 	altname_buf_ptr = altname_buf;
2395     altname_buf[0] = NUL;
2396     target = findServer(name);
2397     altname_buf_ptr = NULL;
2398     if (target == 0 && altname_buf[0] != NUL)
2399 	// Use another server name we found.
2400 	target = findServer(altname_buf);
2401 
2402     if (target == 0)
2403     {
2404 	if (!silent)
2405 	    semsg(_(e_noserver), name);
2406 	return -1;
2407     }
2408 
2409     if (ptarget)
2410 	*(HWND *)ptarget = target;
2411 
2412     data.dwData = asExpr ? COPYDATA_EXPR : COPYDATA_KEYS;
2413     data.cbData = (DWORD)STRLEN(cmd) + 1;
2414     data.lpData = cmd;
2415 
2416     serverSendEnc(target);
2417     if (SendMessage(target, WM_COPYDATA, (WPARAM)message_window,
2418 							(LPARAM)(&data)) == 0)
2419 	return -1;
2420 
2421     if (asExpr)
2422 	retval = serverGetReply(target, &retcode, TRUE, TRUE, timeout);
2423 
2424     if (result == NULL)
2425 	vim_free(retval);
2426     else
2427 	*result = retval; // Caller assumes responsibility for freeing
2428 
2429     return retcode;
2430 }
2431 
2432 /*
2433  * Bring the server to the foreground.
2434  */
2435     void
2436 serverForeground(char_u *name)
2437 {
2438     HWND	target = findServer(name);
2439 
2440     if (target != 0)
2441 	SetForegroundWindow(target);
2442 }
2443 
2444 // Replies from server need to be stored until the client picks them up via
2445 // remote_read(). So we maintain a list of server-id/reply pairs.
2446 // Note that there could be multiple replies from one server pending if the
2447 // client is slow picking them up.
2448 // We just store the replies in a simple list. When we remove an entry, we
2449 // move list entries down to fill the gap.
2450 // The server ID is simply the HWND.
2451 typedef struct
2452 {
2453     HWND	server;		// server window
2454     char_u	*reply;		// reply string
2455     int		expr_result;	// 0 for REPLY, 1 for RESULT 2 for error
2456 } reply_T;
2457 
2458 static garray_T reply_list = {0, 0, sizeof(reply_T), 5, 0};
2459 
2460 # define REPLY_ITEM(i) ((reply_T *)(reply_list.ga_data) + (i))
2461 # define REPLY_COUNT (reply_list.ga_len)
2462 
2463 // Flag which is used to wait for a reply
2464 static int reply_received = 0;
2465 
2466 /*
2467  * Store a reply.  "reply" must be allocated memory (or NULL).
2468  */
2469     static int
2470 save_reply(HWND server, char_u *reply, int expr)
2471 {
2472     reply_T *rep;
2473 
2474     if (ga_grow(&reply_list, 1) == FAIL)
2475 	return FAIL;
2476 
2477     rep = REPLY_ITEM(REPLY_COUNT);
2478     rep->server = server;
2479     rep->reply = reply;
2480     rep->expr_result = expr;
2481     if (rep->reply == NULL)
2482 	return FAIL;
2483 
2484     ++REPLY_COUNT;
2485     reply_received = 1;
2486     return OK;
2487 }
2488 
2489 /*
2490  * Get a reply from server "server".
2491  * When "expr_res" is non NULL, get the result of an expression, otherwise a
2492  * server2client() message.
2493  * When non NULL, point to return code. 0 => OK, -1 => ERROR
2494  * If "remove" is TRUE, consume the message, the caller must free it then.
2495  * if "wait" is TRUE block until a message arrives (or the server exits).
2496  */
2497     char_u *
2498 serverGetReply(HWND server, int *expr_res, int remove, int wait, int timeout)
2499 {
2500     int		i;
2501     char_u	*reply;
2502     reply_T	*rep;
2503     int		did_process = FALSE;
2504     time_t	start;
2505     time_t	now;
2506 
2507     // When waiting, loop until the message waiting for is received.
2508     time(&start);
2509     for (;;)
2510     {
2511 	// Reset this here, in case a message arrives while we are going
2512 	// through the already received messages.
2513 	reply_received = 0;
2514 
2515 	for (i = 0; i < REPLY_COUNT; ++i)
2516 	{
2517 	    rep = REPLY_ITEM(i);
2518 	    if (rep->server == server
2519 		    && ((rep->expr_result != 0) == (expr_res != NULL)))
2520 	    {
2521 		// Save the values we've found for later
2522 		reply = rep->reply;
2523 		if (expr_res != NULL)
2524 		    *expr_res = rep->expr_result == 1 ? 0 : -1;
2525 
2526 		if (remove)
2527 		{
2528 		    // Move the rest of the list down to fill the gap
2529 		    mch_memmove(rep, rep + 1,
2530 				     (REPLY_COUNT - i - 1) * sizeof(reply_T));
2531 		    --REPLY_COUNT;
2532 		}
2533 
2534 		// Return the reply to the caller, who takes on responsibility
2535 		// for freeing it if "remove" is TRUE.
2536 		return reply;
2537 	    }
2538 	}
2539 
2540 	// If we got here, we didn't find a reply. Return immediately if the
2541 	// "wait" parameter isn't set.
2542 	if (!wait)
2543 	{
2544 	    // Process pending messages once. Without this, looping on
2545 	    // remote_peek() would never get the reply.
2546 	    if (!did_process)
2547 	    {
2548 		did_process = TRUE;
2549 		serverProcessPendingMessages();
2550 		continue;
2551 	    }
2552 	    break;
2553 	}
2554 
2555 	// We need to wait for a reply. Enter a message loop until the
2556 	// "reply_received" flag gets set.
2557 
2558 	// Loop until we receive a reply
2559 	while (reply_received == 0)
2560 	{
2561 # ifdef FEAT_TIMERS
2562 	    // TODO: use the return value to decide how long to wait.
2563 	    check_due_timer();
2564 # endif
2565 	    time(&now);
2566 	    if (timeout > 0 && (now - start) >= timeout)
2567 		break;
2568 
2569 	    // Wait for a SendMessage() call to us.  This could be the reply
2570 	    // we are waiting for.  Use a timeout of a second, to catch the
2571 	    // situation that the server died unexpectedly.
2572 	    MsgWaitForMultipleObjects(0, NULL, TRUE, 1000, QS_ALLINPUT);
2573 
2574 	    // If the server has died, give up
2575 	    if (!IsWindow(server))
2576 		return NULL;
2577 
2578 	    serverProcessPendingMessages();
2579 	}
2580     }
2581 
2582     return NULL;
2583 }
2584 
2585 /*
2586  * Process any messages in the Windows message queue.
2587  */
2588     void
2589 serverProcessPendingMessages(void)
2590 {
2591     MSG msg;
2592 
2593     while (pPeekMessage(&msg, NULL, 0, 0, PM_REMOVE))
2594     {
2595 	TranslateMessage(&msg);
2596 	pDispatchMessage(&msg);
2597     }
2598 }
2599 
2600 #endif // FEAT_CLIENTSERVER
2601 
2602 #if defined(FEAT_GUI) || (defined(FEAT_PRINTER) && !defined(FEAT_POSTSCRIPT)) \
2603 	|| defined(PROTO)
2604 
2605 struct charset_pair
2606 {
2607     char	*name;
2608     BYTE	charset;
2609 };
2610 
2611 static struct charset_pair
2612 charset_pairs[] =
2613 {
2614     {"ANSI",		ANSI_CHARSET},
2615     {"CHINESEBIG5",	CHINESEBIG5_CHARSET},
2616     {"DEFAULT",		DEFAULT_CHARSET},
2617     {"HANGEUL",		HANGEUL_CHARSET},
2618     {"OEM",		OEM_CHARSET},
2619     {"SHIFTJIS",	SHIFTJIS_CHARSET},
2620     {"SYMBOL",		SYMBOL_CHARSET},
2621     {"ARABIC",		ARABIC_CHARSET},
2622     {"BALTIC",		BALTIC_CHARSET},
2623     {"EASTEUROPE",	EASTEUROPE_CHARSET},
2624     {"GB2312",		GB2312_CHARSET},
2625     {"GREEK",		GREEK_CHARSET},
2626     {"HEBREW",		HEBREW_CHARSET},
2627     {"JOHAB",		JOHAB_CHARSET},
2628     {"MAC",		MAC_CHARSET},
2629     {"RUSSIAN",		RUSSIAN_CHARSET},
2630     {"THAI",		THAI_CHARSET},
2631     {"TURKISH",		TURKISH_CHARSET},
2632 # ifdef VIETNAMESE_CHARSET
2633     {"VIETNAMESE",	VIETNAMESE_CHARSET},
2634 # endif
2635     {NULL,		0}
2636 };
2637 
2638 struct quality_pair
2639 {
2640     char	*name;
2641     DWORD	quality;
2642 };
2643 
2644 static struct quality_pair
2645 quality_pairs[] = {
2646 # ifdef CLEARTYPE_QUALITY
2647     {"CLEARTYPE",	CLEARTYPE_QUALITY},
2648 # endif
2649 # ifdef ANTIALIASED_QUALITY
2650     {"ANTIALIASED",	ANTIALIASED_QUALITY},
2651 # endif
2652 # ifdef NONANTIALIASED_QUALITY
2653     {"NONANTIALIASED",	NONANTIALIASED_QUALITY},
2654 # endif
2655 # ifdef PROOF_QUALITY
2656     {"PROOF",		PROOF_QUALITY},
2657 # endif
2658 # ifdef DRAFT_QUALITY
2659     {"DRAFT",		DRAFT_QUALITY},
2660 # endif
2661     {"DEFAULT",		DEFAULT_QUALITY},
2662     {NULL,		0}
2663 };
2664 
2665 /*
2666  * Convert a charset ID to a name.
2667  * Return NULL when not recognized.
2668  */
2669     char *
2670 charset_id2name(int id)
2671 {
2672     struct charset_pair *cp;
2673 
2674     for (cp = charset_pairs; cp->name != NULL; ++cp)
2675 	if ((BYTE)id == cp->charset)
2676 	    break;
2677     return cp->name;
2678 }
2679 
2680 /*
2681  * Convert a quality ID to a name.
2682  * Return NULL when not recognized.
2683  */
2684     char *
2685 quality_id2name(DWORD id)
2686 {
2687     struct quality_pair *qp;
2688 
2689     for (qp = quality_pairs; qp->name != NULL; ++qp)
2690 	if (id == qp->quality)
2691 	    break;
2692     return qp->name;
2693 }
2694 
2695 static const LOGFONTW s_lfDefault =
2696 {
2697     -12, 0, 0, 0, FW_NORMAL, FALSE, FALSE, FALSE, DEFAULT_CHARSET,
2698     OUT_DEFAULT_PRECIS, CLIP_DEFAULT_PRECIS,
2699     PROOF_QUALITY, FIXED_PITCH | FF_DONTCARE,
2700     L"Fixedsys"	// see _ReadVimIni
2701 };
2702 
2703 // Initialise the "current height" to -12 (same as s_lfDefault) just
2704 // in case the user specifies a font in "guifont" with no size before a font
2705 // with an explicit size has been set. This defaults the size to this value
2706 // (-12 equates to roughly 9pt).
2707 int current_font_height = -12;		// also used in gui_w32.c
2708 
2709 /*
2710  * Convert a string representing a point size into pixels. The string should
2711  * be a positive decimal number, with an optional decimal point (eg, "12", or
2712  * "10.5"). The pixel value is returned, and a pointer to the next unconverted
2713  * character is stored in *end. The flag "vertical" says whether this
2714  * calculation is for a vertical (height) size or a horizontal (width) one.
2715  */
2716     static int
2717 points_to_pixels(WCHAR *str, WCHAR **end, int vertical, long_i pprinter_dc)
2718 {
2719     int		pixels;
2720     int		points = 0;
2721     int		divisor = 0;
2722     HWND	hwnd = (HWND)0;
2723     HDC		hdc;
2724     HDC		printer_dc = (HDC)pprinter_dc;
2725 
2726     while (*str != NUL)
2727     {
2728 	if (*str == L'.' && divisor == 0)
2729 	{
2730 	    // Start keeping a divisor, for later
2731 	    divisor = 1;
2732 	}
2733 	else
2734 	{
2735 	    if (!VIM_ISDIGIT(*str))
2736 		break;
2737 
2738 	    points *= 10;
2739 	    points += *str - L'0';
2740 	    divisor *= 10;
2741 	}
2742 	++str;
2743     }
2744 
2745     if (divisor == 0)
2746 	divisor = 1;
2747 
2748     if (printer_dc == NULL)
2749     {
2750 	hwnd = GetDesktopWindow();
2751 	hdc = GetWindowDC(hwnd);
2752     }
2753     else
2754 	hdc = printer_dc;
2755 
2756     pixels = MulDiv(points,
2757 		    GetDeviceCaps(hdc, vertical ? LOGPIXELSY : LOGPIXELSX),
2758 		    72 * divisor);
2759 
2760     if (printer_dc == NULL)
2761 	ReleaseDC(hwnd, hdc);
2762 
2763     *end = str;
2764     return pixels;
2765 }
2766 
2767     static int CALLBACK
2768 font_enumproc(
2769     ENUMLOGFONTW    *elf,
2770     NEWTEXTMETRICW  *ntm UNUSED,
2771     DWORD	    type UNUSED,
2772     LPARAM	    lparam)
2773 {
2774     // Return value:
2775     //	  0 = terminate now (monospace & ANSI)
2776     //	  1 = continue, still no luck...
2777     //	  2 = continue, but we have an acceptable LOGFONTW
2778     //	      (monospace, not ANSI)
2779     // We use these values, as EnumFontFamilies returns 1 if the
2780     // callback function is never called. So, we check the return as
2781     // 0 = perfect, 2 = OK, 1 = no good...
2782     // It's not pretty, but it works!
2783 
2784     LOGFONTW *lf = (LOGFONTW *)(lparam);
2785 
2786 # ifndef FEAT_PROPORTIONAL_FONTS
2787     // Ignore non-monospace fonts without further ado
2788     if ((ntm->tmPitchAndFamily & 1) != 0)
2789 	return 1;
2790 # endif
2791 
2792     // Remember this LOGFONTW as a "possible"
2793     *lf = elf->elfLogFont;
2794 
2795     // Terminate the scan as soon as we find an ANSI font
2796     if (lf->lfCharSet == ANSI_CHARSET
2797 	    || lf->lfCharSet == OEM_CHARSET
2798 	    || lf->lfCharSet == DEFAULT_CHARSET)
2799 	return 0;
2800 
2801     // Continue the scan - we have a non-ANSI font
2802     return 2;
2803 }
2804 
2805     static int
2806 init_logfont(LOGFONTW *lf)
2807 {
2808     int		n;
2809     HWND	hwnd = GetDesktopWindow();
2810     HDC		hdc = GetWindowDC(hwnd);
2811 
2812     n = EnumFontFamiliesW(hdc,
2813 			 lf->lfFaceName,
2814 			 (FONTENUMPROCW)font_enumproc,
2815 			 (LPARAM)lf);
2816 
2817     ReleaseDC(hwnd, hdc);
2818 
2819     // If we couldn't find a usable font, return failure
2820     if (n == 1)
2821 	return FAIL;
2822 
2823     // Tidy up the rest of the LOGFONTW structure. We set to a basic
2824     // font - get_logfont() sets bold, italic, etc based on the user's
2825     // input.
2826     lf->lfHeight = current_font_height;
2827     lf->lfWidth = 0;
2828     lf->lfItalic = FALSE;
2829     lf->lfUnderline = FALSE;
2830     lf->lfStrikeOut = FALSE;
2831     lf->lfWeight = FW_NORMAL;
2832 
2833     // Return success
2834     return OK;
2835 }
2836 
2837 /*
2838  * Compare a UTF-16 string and an ASCII string literally.
2839  * Only works all the code points are inside ASCII range.
2840  */
2841     static int
2842 utf16ascncmp(const WCHAR *w, const char *p, size_t n)
2843 {
2844     size_t i;
2845 
2846     for (i = 0; i < n; i++)
2847     {
2848 	if (w[i] == 0 || w[i] != p[i])
2849 	    return w[i] - p[i];
2850     }
2851     return 0;
2852 }
2853 
2854 /*
2855  * Get font info from "name" into logfont "lf".
2856  * Return OK for a valid name, FAIL otherwise.
2857  */
2858     int
2859 get_logfont(
2860     LOGFONTW	*lf,
2861     char_u	*name,
2862     HDC		printer_dc,
2863     int		verbose)
2864 {
2865     WCHAR	*p;
2866     int		i;
2867     int		ret = FAIL;
2868     static LOGFONTW *lastlf = NULL;
2869     WCHAR	*wname;
2870 
2871     *lf = s_lfDefault;
2872     if (name == NULL)
2873 	return OK;
2874 
2875     wname = enc_to_utf16(name, NULL);
2876     if (wname == NULL)
2877 	return FAIL;
2878 
2879     if (wcscmp(wname, L"*") == 0)
2880     {
2881 # if defined(FEAT_GUI_MSWIN)
2882 	CHOOSEFONTW	cf;
2883 	// if name is "*", bring up std font dialog:
2884 	CLEAR_FIELD(cf);
2885 	cf.lStructSize = sizeof(cf);
2886 	cf.hwndOwner = s_hwnd;
2887 	cf.Flags = CF_SCREENFONTS | CF_FIXEDPITCHONLY | CF_INITTOLOGFONTSTRUCT;
2888 	if (lastlf != NULL)
2889 	    *lf = *lastlf;
2890 	cf.lpLogFont = lf;
2891 	cf.nFontType = 0 ; //REGULAR_FONTTYPE;
2892 	if (ChooseFontW(&cf))
2893 	    ret = OK;
2894 # endif
2895 	goto theend;
2896     }
2897 
2898     /*
2899      * Split name up, it could be <name>:h<height>:w<width> etc.
2900      */
2901     for (p = wname; *p && *p != L':'; p++)
2902     {
2903 	if (p - wname + 1 >= LF_FACESIZE)
2904 	    goto theend;			// Name too long
2905 	lf->lfFaceName[p - wname] = *p;
2906     }
2907     if (p != wname)
2908 	lf->lfFaceName[p - wname] = NUL;
2909 
2910     // First set defaults
2911     lf->lfHeight = -12;
2912     lf->lfWidth = 0;
2913     lf->lfWeight = FW_NORMAL;
2914     lf->lfItalic = FALSE;
2915     lf->lfUnderline = FALSE;
2916     lf->lfStrikeOut = FALSE;
2917 
2918     /*
2919      * If the font can't be found, try replacing '_' by ' '.
2920      */
2921     if (init_logfont(lf) == FAIL)
2922     {
2923 	int	did_replace = FALSE;
2924 
2925 	for (i = 0; lf->lfFaceName[i]; ++i)
2926 	    if (lf->lfFaceName[i] == L'_')
2927 	    {
2928 		lf->lfFaceName[i] = L' ';
2929 		did_replace = TRUE;
2930 	    }
2931 	if (!did_replace || init_logfont(lf) == FAIL)
2932 	    goto theend;
2933     }
2934 
2935     while (*p == L':')
2936 	p++;
2937 
2938     // Set the values found after ':'
2939     while (*p)
2940     {
2941 	switch (*p++)
2942 	{
2943 	    case L'h':
2944 		lf->lfHeight = - points_to_pixels(p, &p, TRUE, (long_i)printer_dc);
2945 		break;
2946 	    case L'w':
2947 		lf->lfWidth = points_to_pixels(p, &p, FALSE, (long_i)printer_dc);
2948 		break;
2949 	    case L'W':
2950 		lf->lfWeight = wcstol(p, &p, 10);
2951 		break;
2952 	    case L'b':
2953 		lf->lfWeight = FW_BOLD;
2954 		break;
2955 	    case L'i':
2956 		lf->lfItalic = TRUE;
2957 		break;
2958 	    case L'u':
2959 		lf->lfUnderline = TRUE;
2960 		break;
2961 	    case L's':
2962 		lf->lfStrikeOut = TRUE;
2963 		break;
2964 	    case L'c':
2965 		{
2966 		    struct charset_pair *cp;
2967 
2968 		    for (cp = charset_pairs; cp->name != NULL; ++cp)
2969 			if (utf16ascncmp(p, cp->name, strlen(cp->name)) == 0)
2970 			{
2971 			    lf->lfCharSet = cp->charset;
2972 			    p += strlen(cp->name);
2973 			    break;
2974 			}
2975 		    if (cp->name == NULL && verbose)
2976 		    {
2977 			char_u *s = utf16_to_enc(p, NULL);
2978 			semsg(_("E244: Illegal charset name \"%s\" in font name \"%s\""), s, name);
2979 			vim_free(s);
2980 			break;
2981 		    }
2982 		    break;
2983 		}
2984 	    case L'q':
2985 		{
2986 		    struct quality_pair *qp;
2987 
2988 		    for (qp = quality_pairs; qp->name != NULL; ++qp)
2989 			if (utf16ascncmp(p, qp->name, strlen(qp->name)) == 0)
2990 			{
2991 			    lf->lfQuality = qp->quality;
2992 			    p += strlen(qp->name);
2993 			    break;
2994 			}
2995 		    if (qp->name == NULL && verbose)
2996 		    {
2997 			char_u *s = utf16_to_enc(p, NULL);
2998 			semsg(_("E244: Illegal quality name \"%s\" in font name \"%s\""), s, name);
2999 			vim_free(s);
3000 			break;
3001 		    }
3002 		    break;
3003 		}
3004 	    default:
3005 		if (verbose)
3006 		    semsg(_("E245: Illegal char '%c' in font name \"%s\""), p[-1], name);
3007 		goto theend;
3008 	}
3009 	while (*p == L':')
3010 	    p++;
3011     }
3012     ret = OK;
3013 
3014 theend:
3015     // ron: init lastlf
3016     if (ret == OK && printer_dc == NULL)
3017     {
3018 	vim_free(lastlf);
3019 	lastlf = ALLOC_ONE(LOGFONTW);
3020 	if (lastlf != NULL)
3021 	    mch_memmove(lastlf, lf, sizeof(LOGFONTW));
3022     }
3023     vim_free(wname);
3024 
3025     return ret;
3026 }
3027 
3028 #endif // defined(FEAT_GUI) || defined(FEAT_PRINTER)
3029 
3030 #if defined(FEAT_JOB_CHANNEL) || defined(PROTO)
3031 /*
3032  * Initialize the Winsock dll.
3033  */
3034     void
3035 channel_init_winsock(void)
3036 {
3037     WSADATA wsaData;
3038     int wsaerr;
3039 
3040     if (WSInitialized)
3041 	return;
3042 
3043     wsaerr = WSAStartup(MAKEWORD(2, 2), &wsaData);
3044     if (wsaerr == 0)
3045 	WSInitialized = TRUE;
3046 }
3047 #endif
3048