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