1 /* vi:set ts=8 sts=4 sw=4:
3 * VIM - Vi IMproved by Bram Moolenaar
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.
13 * Routines common to both Win16 and Win32.
29 # define SHORT_FNAME /* always 8.3 file name */
33 #include <sys/types.h>
48 #if defined(FEAT_TITLE) && !defined(FEAT_GUI_W32)
49 # include <shellapi.h>
52 #if defined(FEAT_PRINTER) && !defined(FEAT_POSTSCRIPT)
55 # include <winspool.h>
63 # ifndef FROM_LEFT_1ST_BUTTON_PRESSED
64 # define FROM_LEFT_1ST_BUTTON_PRESSED 0x0001
66 # ifndef RIGHTMOST_BUTTON_PRESSED
67 # define RIGHTMOST_BUTTON_PRESSED 0x0002
69 # ifndef FROM_LEFT_2ND_BUTTON_PRESSED
70 # define FROM_LEFT_2ND_BUTTON_PRESSED 0x0004
72 # ifndef FROM_LEFT_3RD_BUTTON_PRESSED
73 # define FROM_LEFT_3RD_BUTTON_PRESSED 0x0008
75 # ifndef FROM_LEFT_4TH_BUTTON_PRESSED
76 # define FROM_LEFT_4TH_BUTTON_PRESSED 0x0010
83 # define MOUSE_MOVED 0x0001
86 # define DOUBLE_CLICK 0x0002
91 * When generating prototypes for Win32 on Unix, these lines make the syntax
92 * errors disappear. They do not need to be correct.
100 typedef int CONSOLE_CURSOR_INFO
;
103 typedef int ENUMLOGFONT
;
109 typedef int INPUT_RECORD
;
110 typedef int KEY_EVENT_RECORD
;
120 typedef int MOUSE_EVENT_RECORD
;
121 typedef int NEWTEXTMETRIC
;
123 typedef int PRINTDLG
;
124 typedef int PSECURITY_DESCRIPTOR
;
126 typedef int SECURITY_INFORMATION
;
128 typedef int SMALL_RECT
;
129 typedef int TEXTMETRIC
;
137 /* Record all output and all keyboard & mouse input */
138 /* #define MCH_WRITE_DUMP */
140 #ifdef MCH_WRITE_DUMP
145 extern DWORD g_PlatformId
;
148 #ifndef FEAT_GUI_MSWIN
149 extern char g_szOrigTitle
[];
155 static HWND s_hwnd
= 0; /* console window handle, set by GetConsoleHwnd() */
158 extern int WSInitialized
;
160 /* Don't generate prototypes here, because some systems do have these
162 #if defined(__GNUC__) && !defined(PROTO)
164 int _stricoll(char *a
, char *b
)
166 // the ANSI-ish correct way is to use strxfrm():
167 char a_buff
[512], b_buff
[512]; // file names, so this is enough on Win32
168 strxfrm(a_buff
, a
, 512);
169 strxfrm(b_buff
, b
, 512);
170 return strcoll(a_buff
, b_buff
);
173 char * _fullpath(char *buf
, char *fname
, int len
)
177 return (char *)GetFullPathName(fname
, len
, buf
, &toss
);
181 int _chdrive(int drive
)
183 char temp
[3] = "-:";
184 temp
[0] = drive
+ 'A' - 1;
185 return !SetCurrentDirectory(temp
);
189 /* being a more ANSI compliant compiler, BorlandC doesn't define _stricoll:
190 * but it does in BC 5.02! */
191 # if __BORLANDC__ < 0x502
192 int _stricoll(char *a
, char *b
)
195 // this is fast but not correct:
196 return stricmp(a
, b
);
198 // the ANSI-ish correct way is to use strxfrm():
199 char a_buff
[512], b_buff
[512]; // file names, so this is enough on Win32
200 strxfrm(a_buff
, a
, 512);
201 strxfrm(b_buff
, b
, 512);
202 return strcoll(a_buff
, b_buff
);
210 #if defined(FEAT_GUI_MSWIN) || defined(PROTO)
212 * GUI version of mch_exit().
213 * Shut down and exit with status `r'
214 * Careful: mch_exit() may be called before mch_init()!
221 ml_close_all(TRUE
); /* remove all memfiles */
226 # ifdef FEAT_NETBEANS_INTG
229 WSInitialized
= FALSE
;
233 #ifdef DYNAMIC_GETTEXT
247 #endif /* FEAT_GUI_MSWIN */
251 * Init the tables for toupper() and tolower().
262 /* Init the tables for toupper() and tolower() */
263 for (i
= 0; i
< 256; ++i
)
264 toupper_tab
[i
] = tolower_tab
[i
] = i
;
266 CharUpperBuff(toupper_tab
, 256);
267 CharLowerBuff(tolower_tab
, 256);
269 AnsiUpperBuff(toupper_tab
, 256);
270 AnsiLowerBuff(tolower_tab
, 256);
273 #if defined(FEAT_MBYTE) && !defined(FEAT_GUI)
274 (void)get_cmd_argsW(NULL
);
280 * Return TRUE if the input comes from a terminal, FALSE otherwise.
285 #ifdef FEAT_GUI_MSWIN
286 return OK
; /* GUI always has a tty */
288 if (isatty(read_cmd_fd
))
296 * mch_settitle(): set titlebar of our window
303 # ifdef FEAT_GUI_MSWIN
304 gui_mch_settitle(title
, icon
);
309 if (enc_codepage
>= 0 && (int)GetACP() != enc_codepage
)
311 /* Convert the title from 'encoding' to the active codepage. */
312 WCHAR
*wp
= enc_to_utf16(title
, NULL
);
317 n
= SetConsoleTitleW(wp
);
319 if (n
!= 0 || GetLastError() != ERROR_CALL_NOT_IMPLEMENTED
)
324 SetConsoleTitle(title
);
331 * Restore the window/icon title.
333 * 1: Just restore title
334 * 2: Just restore icon (which we don't have)
335 * 3: Restore title and icon (which we don't have)
342 #ifndef FEAT_GUI_MSWIN
343 mch_settitle((which
& 1) ? g_szOrigTitle
: NULL
, NULL
);
349 * Return TRUE if we can restore the title (we can)
352 mch_can_restore_title()
359 * Return TRUE if we can restore the icon title (we can't)
362 mch_can_restore_icon()
366 #endif /* FEAT_TITLE */
370 * Get absolute file name into buffer "buf" of length "len" bytes,
371 * turning all '/'s into '\\'s and getting the correct case of each component
372 * of the file name. Append a (back)slash to a directory name.
373 * When 'shellslash' set do it the other way around.
387 if (*fname
== NUL
) /* Borland behaves badly here - make it consistent */
388 nResult
= mch_dirname(buf
, len
);
393 if (enc_codepage
>= 0 && (int)GetACP() != enc_codepage
395 /* Wide functions of Borland C 5.5 do not work on Windows 98. */
396 && g_PlatformId
== VER_PLATFORM_WIN32_NT
401 WCHAR wbuf
[MAX_PATH
];
402 char_u
*cname
= NULL
;
404 /* Use the wide function:
405 * - convert the fname from 'encoding' to UCS2.
406 * - invoke _wfullpath()
407 * - convert the result from UCS2 to 'encoding'.
409 wname
= enc_to_utf16(fname
, NULL
);
410 if (wname
!= NULL
&& _wfullpath(wbuf
, wname
, MAX_PATH
- 1) != NULL
)
412 cname
= utf16_to_enc((short_u
*)wbuf
, NULL
);
415 vim_strncpy(buf
, cname
, len
- 1);
422 if (nResult
== FAIL
) /* fall back to non-wide function */
425 if (_fullpath(buf
, fname
, len
- 1) == NULL
)
427 /* failed, use relative path name */
428 vim_strncpy(buf
, fname
, len
- 1);
435 #ifdef USE_FNAME_CASE
436 fname_case(buf
, len
);
446 * Return TRUE if "fname" does not depend on the current directory.
449 mch_isFullName(char_u
*fname
)
451 char szName
[_MAX_PATH
+ 1];
453 /* A name like "d:/foo" and "//server/share" is absolute */
454 if ((fname
[0] && fname
[1] == ':' && (fname
[2] == '/' || fname
[2] == '\\'))
455 || (fname
[0] == fname
[1] && (fname
[0] == '/' || fname
[0] == '\\')))
458 /* A name that can't be made absolute probably isn't absolute. */
459 if (mch_FullName(fname
, szName
, _MAX_PATH
, FALSE
) == FAIL
)
462 return pathcmp(fname
, szName
, -1) == 0;
466 * Replace all slashes by backslashes.
467 * This used to be the other way around, but MS-DOS sometimes has problems
468 * with slashes (e.g. in a command name). We can't have mixed slashes and
469 * backslashes, because comparing file names will not work correctly. The
470 * commands that use a file name should try to avoid the need to type a
472 * When 'shellslash' set do it the other way around.
488 * stat() can't handle a trailing '/' or '\', remove it first.
491 vim_stat(const char *name
, struct stat
*stp
)
493 char buf
[_MAX_PATH
+ 1];
496 vim_strncpy((char_u
*)buf
, (char_u
*)name
, _MAX_PATH
);
497 p
= buf
+ strlen(buf
);
500 if (p
> buf
&& (*p
== '\\' || *p
== '/') && p
[-1] != ':')
503 if (enc_codepage
>= 0 && (int)GetACP() != enc_codepage
505 /* Wide functions of Borland C 5.5 do not work on Windows 98. */
506 && g_PlatformId
== VER_PLATFORM_WIN32_NT
510 WCHAR
*wp
= enc_to_utf16(buf
, NULL
);
515 n
= _wstat(wp
, (struct _stat
*)stp
);
519 /* Retry with non-wide function (for Windows 98). Can't use
520 * GetLastError() here and it's unclear what errno gets set to if
521 * the _wstat() fails for missing wide functions. */
525 return stat(buf
, stp
);
528 #if defined(FEAT_GUI_MSWIN) || defined(PROTO)
531 mch_settmode(int tmode
)
537 mch_get_shellsize(void)
544 mch_set_shellsize(void)
550 * Rows and/or Columns has changed.
553 mch_new_shellsize(void)
561 * We have no job control, so fake it by starting a new shell.
569 #if defined(USE_MCH_ERRMSG) || defined(PROTO)
571 #ifdef display_errors
572 # undef display_errors
576 * Display the saved error message(s).
583 if (error_ga
.ga_data
!= NULL
)
585 /* avoid putting up a message box with blanks only */
586 for (p
= (char *)error_ga
.ga_data
; *p
; ++p
)
589 (void)gui_mch_dialog(
591 gui
.starting
? VIM_INFO
:
595 gui
.starting
? (char_u
*)_("Message") :
597 (char_u
*)_("Error"),
598 p
, (char_u
*)_("&Ok"), 1, NULL
);
608 * Return TRUE if "p" contain a wildcard that can be expanded by
612 mch_has_exp_wildcard(char_u
*p
)
614 for ( ; *p
; mb_ptr_adv(p
))
616 if (vim_strchr((char_u
*)"?*[", *p
) != NULL
617 || (*p
== '~' && p
[1] != NUL
))
624 * Return TRUE if "p" contain a wildcard or a "~1" kind of thing (could be a
625 * shortened file name).
628 mch_has_wildcard(char_u
*p
)
630 for ( ; *p
; mb_ptr_adv(p
))
632 if (vim_strchr((char_u
*)
639 || (*p
== '~' && p
[1] != NUL
))
647 * The normal _chdir() does not change the default drive. This one does.
648 * Returning 0 implies success; -1 implies failure.
651 mch_chdir(char *path
)
653 if (path
[0] == NUL
) /* just checking... */
659 smsg((char_u
*)"chdir(%s)", path
);
662 if (isalpha(path
[0]) && path
[1] == ':') /* has a drive name */
664 /* If we can change to the drive, skip that part of the path. If we
665 * can't then the current directory may be invalid, try using chdir()
666 * with the whole path. */
667 if (_chdrive(TOLOWER_ASC(path
[0]) - 'a' + 1) == 0)
671 if (*path
== NUL
) /* drive name only */
675 if (enc_codepage
>= 0 && (int)GetACP() != enc_codepage
)
677 WCHAR
*p
= enc_to_utf16(path
, NULL
);
686 /* Retry with non-wide function (for Windows 98). */
691 return chdir(path
); /* let the normal chdir() do the rest */
696 * Switching off termcap mode is only allowed when Columns is 80, otherwise a
697 * crash may result. It's always allowed on NT or when running the GUI.
701 can_end_termcap_mode(
704 #ifdef FEAT_GUI_MSWIN
705 return TRUE
; /* GUI starts a new console anyway */
707 if (g_PlatformId
== VER_PLATFORM_WIN32_NT
|| Columns
== 80)
710 msg(_("'columns' is not 80, cannot execute external commands"));
715 #ifdef FEAT_GUI_MSWIN
717 * return non-zero if a character is available
729 * set screen mode, always fails.
736 EMSG(_(e_screenmode
));
741 #if defined(FEAT_LIBCALL) || defined(PROTO)
743 * Call a DLL routine which takes either a string or int param
744 * and returns an allocated string.
745 * Return OK if it worked, FAIL if not.
748 typedef LPTSTR (*MYSTRPROCSTR
)(LPTSTR
);
749 typedef LPTSTR (*MYINTPROCSTR
)(int);
750 typedef int (*MYSTRPROCINT
)(LPTSTR
);
751 typedef int (*MYINTPROCINT
)(int);
753 typedef LPSTR (*MYSTRPROCSTR
)(LPSTR
);
754 typedef LPSTR (*MYINTPROCSTR
)(int);
755 typedef int (*MYSTRPROCINT
)(LPSTR
);
756 typedef int (*MYINTPROCINT
)(int);
761 * Check if a pointer points to a valid NUL terminated string.
762 * Return the length of the string, including terminating NUL.
763 * Returns 0 for an invalid pointer, 1 for an empty string.
766 check_str_len(char_u
*str
)
769 MEMORY_BASIC_INFORMATION mbi
;
777 /* get memory information */
778 if (VirtualQuery(str
, &mbi
, sizeof(mbi
)))
780 /* pre cast these (typing savers) */
781 long_u dwStr
= (long_u
)str
;
782 long_u dwBaseAddress
= (long_u
)mbi
.BaseAddress
;
784 /* get start address of page that str is on */
785 long_u strPage
= dwStr
- (dwStr
- dwBaseAddress
) % si
.dwPageSize
;
787 /* get length from str to end of page */
788 long_u pageLength
= si
.dwPageSize
- (dwStr
- strPage
);
790 for (p
= str
; !IsBadReadPtr(p
, pageLength
);
791 p
+= pageLength
, pageLength
= si
.dwPageSize
)
792 for (i
= 0; i
< pageLength
; ++i
, ++length
)
805 char_u
*argstring
, /* NULL when using a argint */
807 char_u
**string_result
,/* NULL when using number_result */
811 MYSTRPROCSTR ProcAdd
;
812 MYINTPROCSTR ProcAddI
;
813 char_u
*retval_str
= NULL
;
817 BOOL fRunTimeLinkSuccess
= FALSE
;
819 // Get a handle to the DLL module.
820 hinstLib
= LoadLibrary(libname
);
822 // If the handle is valid, try to get the function address.
823 if (hinstLib
!= NULL
)
825 #ifdef HAVE_TRY_EXCEPT
829 if (argstring
!= NULL
)
831 /* Call with string argument */
832 ProcAdd
= (MYSTRPROCSTR
) GetProcAddress(hinstLib
, funcname
);
833 if ((fRunTimeLinkSuccess
= (ProcAdd
!= NULL
)) != 0)
835 if (string_result
== NULL
)
836 retval_int
= ((MYSTRPROCINT
)ProcAdd
)(argstring
);
838 retval_str
= (ProcAdd
)(argstring
);
843 /* Call with number argument */
844 ProcAddI
= (MYINTPROCSTR
) GetProcAddress(hinstLib
, funcname
);
845 if ((fRunTimeLinkSuccess
= (ProcAddI
!= NULL
)) != 0)
847 if (string_result
== NULL
)
848 retval_int
= ((MYINTPROCINT
)ProcAddI
)(argint
);
850 retval_str
= (ProcAddI
)(argint
);
854 // Save the string before we free the library.
855 // Assume that a "1" result is an illegal pointer.
856 if (string_result
== NULL
)
857 *number_result
= retval_int
;
858 else if (retval_str
!= NULL
860 && retval_str
!= (char_u
*)1
861 && retval_str
!= (char_u
*)-1
862 && !IsBadStringPtr(retval_str
, INT_MAX
)
863 && (len
= strlen(retval_str
) + 1) > 0
865 && (len
= check_str_len(retval_str
)) > 0
869 *string_result
= lalloc((long_u
)len
, TRUE
);
870 if (*string_result
!= NULL
)
871 mch_memmove(*string_result
, retval_str
, len
);
874 #ifdef HAVE_TRY_EXCEPT
876 __except(EXCEPTION_EXECUTE_HANDLER
)
878 if (GetExceptionCode() == EXCEPTION_STACK_OVERFLOW
)
880 fRunTimeLinkSuccess
= 0;
884 // Free the DLL module.
885 (void)FreeLibrary(hinstLib
);
888 if (!fRunTimeLinkSuccess
)
890 EMSG2(_(e_libcall
), funcname
);
898 #if defined(FEAT_MBYTE) || defined(PROTO)
900 * Convert an UTF-8 string to UTF-16.
901 * "instr[inlen]" is the input. "inlen" is in bytes.
902 * When "outstr" is NULL only return the number of UTF-16 words produced.
903 * Otherwise "outstr" must be a buffer of sufficient size.
904 * Returns the number of UTF-16 words produced.
907 utf8_to_utf16(char_u
*instr
, int inlen
, short_u
*outstr
, int *unconvlenp
)
917 /* Only convert if we have a complete sequence. */
918 l
= utf_ptr2len_len(p
, todo
);
921 /* Return length of incomplete sequence. */
922 if (unconvlenp
!= NULL
)
927 ch
= utf_ptr2char(p
);
930 /* non-BMP character, encoding with surrogate pairs */
934 *outstr
++ = (0xD800 - (0x10000 >> 10)) + (ch
>> 10);
935 *outstr
++ = 0xDC00 | (ch
& 0x3FF);
938 else if (outstr
!= NULL
)
949 * Convert an UTF-16 string to UTF-8.
950 * The input is "instr[inlen]" with "inlen" in number of UTF-16 words.
951 * When "outstr" is NULL only return the required number of bytes.
952 * Otherwise "outstr" must be a buffer of sufficient size.
953 * Return the number of bytes produced.
956 utf16_to_utf8(short_u
*instr
, int inlen
, char_u
*outstr
)
967 if (ch
>= 0xD800 && ch
<= 0xDBFF && todo
> 1)
969 /* surrogate pairs handling */
971 if (ch2
>= 0xDC00 && ch2
<= 0xDFFF)
973 ch
= ((ch
- 0xD800) << 10) + (ch2
& 0x3FF) + 0x10000;
980 l
= utf_char2bytes(ch
, outstr
);
984 l
= utf_char2len(ch
);
994 * Call MultiByteToWideChar() and allocate memory for the result.
995 * Returns the result in "*out[*outlen]" with an extra zero appended.
996 * "outlen" is in words.
999 MultiByteToWideChar_alloc(UINT cp
, DWORD flags
,
1000 LPCSTR in
, int inlen
,
1001 LPWSTR
*out
, int *outlen
)
1003 *outlen
= MultiByteToWideChar(cp
, flags
, in
, inlen
, 0, 0);
1004 /* Add one one word to avoid a zero-length alloc(). */
1005 *out
= (LPWSTR
)alloc(sizeof(WCHAR
) * (*outlen
+ 1));
1008 MultiByteToWideChar(cp
, flags
, in
, inlen
, *out
, *outlen
);
1009 (*out
)[*outlen
] = 0;
1014 * Call WideCharToMultiByte() and allocate memory for the result.
1015 * Returns the result in "*out[*outlen]" with an extra NUL appended.
1018 WideCharToMultiByte_alloc(UINT cp
, DWORD flags
,
1019 LPCWSTR in
, int inlen
,
1020 LPSTR
*out
, int *outlen
,
1021 LPCSTR def
, LPBOOL useddef
)
1023 *outlen
= WideCharToMultiByte(cp
, flags
, in
, inlen
, NULL
, 0, def
, useddef
);
1024 /* Add one one byte to avoid a zero-length alloc(). */
1025 *out
= alloc((unsigned)*outlen
+ 1);
1028 WideCharToMultiByte(cp
, flags
, in
, inlen
, *out
, *outlen
, def
, useddef
);
1029 (*out
)[*outlen
] = 0;
1033 #endif /* FEAT_MBYTE */
1035 #ifdef FEAT_CLIPBOARD
1037 * Clipboard stuff, for cutting and pasting text to other windows.
1040 /* Type used for the clipboard type of Vim's data. */
1043 int type
; /* MCHAR, MBLOCK or MLINE */
1044 int txtlen
; /* length of CF_TEXT in bytes */
1045 int ucslen
; /* length of CF_UNICODETEXT in words */
1046 int rawlen
; /* length of clip_star.format_raw, including encoding,
1047 excluding terminating NUL */
1051 * Make vim the owner of the current selection. Return OK upon success.
1055 clip_mch_own_selection(VimClipboard
*cbd
)
1058 * Never actually own the clipboard. If another application sets the
1059 * clipboard, we don't want to think that we still own it.
1065 * Make vim NOT the owner of the current selection.
1069 clip_mch_lose_selection(VimClipboard
*cbd
)
1071 /* Nothing needs to be done here */
1075 * Copy "str[*size]" into allocated memory, changing CR-NL to NL.
1076 * Return the allocated result and the size in "*size".
1077 * Returns NULL when out of memory.
1080 crnl_to_nl(const char_u
*str
, int *size
)
1083 int str_len
= *size
;
1087 /* Avoid allocating zero bytes, it generates an error message. */
1088 ret
= lalloc((long_u
)(str_len
== 0 ? 1 : str_len
), TRUE
);
1092 for (pos
= 0; pos
< str_len
; ++pos
)
1094 if (str
[pos
] == '\r' && str
[pos
+ 1] == '\n')
1106 #if defined(FEAT_MBYTE) || defined(PROTO)
1108 * Note: the following two functions are only guaranteed to work when using
1109 * valid MS-Windows codepages or when iconv() is available.
1113 * Convert "str" from 'encoding' to UTF-16.
1114 * Input in "str" with length "*lenp". When "lenp" is NULL, use strlen().
1115 * Output is returned as an allocated string. "*lenp" is set to the length of
1116 * the result. A trailing NUL is always added.
1117 * Returns NULL when out of memory.
1120 enc_to_utf16(char_u
*str
, int *lenp
)
1124 char_u
*allocbuf
= NULL
;
1130 len_loc
= (int)STRLEN(str
) + 1;
1134 if (enc_codepage
> 0)
1136 /* We can do any CP### -> UTF-16 in one pass, and we can do it
1137 * without iconv() (convert_* may need iconv). */
1138 MultiByteToWideChar_alloc(enc_codepage
, 0, str
, *lenp
, &ret
, &length
);
1142 /* Use "latin1" by default, we might be called before we have p_enc
1143 * set up. Convert to utf-8 first, works better with iconv(). Does
1144 * nothing if 'encoding' is "utf-8". */
1145 conv
.vc_type
= CONV_NONE
;
1146 if (convert_setup(&conv
, p_enc
? p_enc
: (char_u
*)"latin1",
1147 (char_u
*)"utf-8") == FAIL
)
1149 if (conv
.vc_type
!= CONV_NONE
)
1151 str
= allocbuf
= string_convert(&conv
, str
, lenp
);
1155 convert_setup(&conv
, NULL
, NULL
);
1157 length
= utf8_to_utf16(str
, *lenp
, NULL
, NULL
);
1158 ret
= (WCHAR
*)alloc((unsigned)((length
+ 1) * sizeof(WCHAR
)));
1161 utf8_to_utf16(str
, *lenp
, (short_u
*)ret
, NULL
);
1169 return (short_u
*)ret
;
1173 * Convert an UTF-16 string to 'encoding'.
1174 * Input in "str" with length (counted in wide characters) "*lenp". When
1175 * "lenp" is NULL, use wcslen().
1176 * Output is returned as an allocated string. If "*lenp" is not NULL it is
1177 * set to the length of the result.
1178 * Returns NULL when out of memory.
1181 utf16_to_enc(short_u
*str
, int *lenp
)
1184 char_u
*utf8_str
= NULL
, *enc_str
= NULL
;
1189 len_loc
= (int)wcslen(str
) + 1;
1193 if (enc_codepage
> 0)
1195 /* We can do any UTF-16 -> CP### in one pass. */
1198 WideCharToMultiByte_alloc(enc_codepage
, 0, str
, *lenp
,
1199 (LPSTR
*)&enc_str
, &length
, 0, 0);
1204 /* Avoid allocating zero bytes, it generates an error message. */
1205 utf8_str
= alloc(utf16_to_utf8(str
, *lenp
== 0 ? 1 : *lenp
, NULL
));
1206 if (utf8_str
!= NULL
)
1208 *lenp
= utf16_to_utf8(str
, *lenp
, utf8_str
);
1210 /* We might be called before we have p_enc set up. */
1211 conv
.vc_type
= CONV_NONE
;
1212 convert_setup(&conv
, (char_u
*)"utf-8",
1213 p_enc
? p_enc
: (char_u
*)"latin1");
1214 if (conv
.vc_type
== CONV_NONE
)
1216 /* p_enc is utf-8, so we're done. */
1221 enc_str
= string_convert(&conv
, utf8_str
, lenp
);
1225 convert_setup(&conv
, NULL
, NULL
);
1230 #endif /* FEAT_MBYTE */
1233 * Wait for another process to Close the Clipboard.
1234 * Returns TRUE for success.
1237 vim_open_clipboard(void)
1241 while (!OpenClipboard(NULL
))
1244 return FALSE
; /* waited too long, give up */
1246 delay
*= 2; /* wait for 10, 20, 40, 80, etc. msec */
1252 * Get the current selection and put it in the clipboard register.
1254 * NOTE: Must use GlobalLock/Unlock here to ensure Win32s compatibility.
1255 * On NT/W95 the clipboard data is a fixed global memory object and
1256 * so its handle = its pointer.
1257 * On Win32s, however, co-operation with the Win16 system means that
1258 * the clipboard data is moveable and its handle is not a pointer at all,
1259 * so we can't just cast the return value of GetClipboardData to (char_u*).
1263 clip_mch_request_selection(VimClipboard
*cbd
)
1265 VimClipType_t metadata
= { -1, -1, -1, -1 };
1266 HGLOBAL hMem
= NULL
;
1268 #if defined(FEAT_MBYTE) && defined(WIN3264)
1269 char_u
*to_free
= NULL
;
1272 HGLOBAL rawh
= NULL
;
1279 * Don't pass GetActiveWindow() as an argument to OpenClipboard() because
1280 * then we can't paste back into the same window for some reason - webb.
1282 if (!vim_open_clipboard())
1285 /* Check for vim's own clipboard format first. This only gets the type of
1286 * the data, still need to use CF_UNICODETEXT or CF_TEXT for the text. */
1287 if (IsClipboardFormatAvailable(cbd
->format
))
1289 VimClipType_t
*meta_p
;
1292 /* We have metadata on the clipboard; try to get it. */
1293 if ((meta_h
= GetClipboardData(cbd
->format
)) != NULL
1294 && (meta_p
= (VimClipType_t
*)GlobalLock(meta_h
)) != NULL
)
1296 /* The size of "VimClipType_t" changed, "rawlen" was added later.
1297 * Only copy what is available for backwards compatibility. */
1298 n
= sizeof(VimClipType_t
);
1299 if (GlobalSize(meta_h
) < n
)
1300 n
= GlobalSize(meta_h
);
1301 memcpy(&metadata
, meta_p
, n
);
1302 GlobalUnlock(meta_h
);
1307 /* Check for Vim's raw clipboard format first. This is used without
1308 * conversion, but only if 'encoding' matches. */
1309 if (IsClipboardFormatAvailable(cbd
->format_raw
)
1310 && metadata
.rawlen
> (int)STRLEN(p_enc
))
1312 /* We have raw data on the clipboard; try to get it. */
1313 if ((rawh
= GetClipboardData(cbd
->format_raw
)) != NULL
)
1317 rawp
= (char_u
*)GlobalLock(rawh
);
1318 if (rawp
!= NULL
&& STRCMP(p_enc
, rawp
) == 0)
1320 n
= STRLEN(p_enc
) + 1;
1322 str_size
= (int)(metadata
.rawlen
- n
);
1335 #if defined(FEAT_MBYTE) && defined(WIN3264)
1336 /* Try to get the clipboard in Unicode if it's not an empty string. */
1337 if (IsClipboardFormatAvailable(CF_UNICODETEXT
) && metadata
.ucslen
!= 0)
1341 if ((hMemW
= GetClipboardData(CF_UNICODETEXT
)) != NULL
)
1343 WCHAR
*hMemWstr
= (WCHAR
*)GlobalLock(hMemW
);
1345 /* Use the length of our metadata if possible, but limit it to the
1346 * GlobalSize() for safety. */
1347 maxlen
= (int)(GlobalSize(hMemW
) / sizeof(WCHAR
));
1348 if (metadata
.ucslen
>= 0)
1350 if (metadata
.ucslen
> maxlen
)
1353 str_size
= metadata
.ucslen
;
1357 for (str_size
= 0; str_size
< maxlen
; ++str_size
)
1358 if (hMemWstr
[str_size
] == NUL
)
1361 to_free
= str
= utf16_to_enc((short_u
*)hMemWstr
, &str_size
);
1362 GlobalUnlock(hMemW
);
1367 /* Get the clipboard in the Active codepage. */
1368 if (IsClipboardFormatAvailable(CF_TEXT
))
1370 if ((hMem
= GetClipboardData(CF_TEXT
)) != NULL
)
1372 str
= (char_u
*)GlobalLock(hMem
);
1374 /* The length is either what our metadata says or the strlen().
1375 * But limit it to the GlobalSize() for safety. */
1376 maxlen
= (int)GlobalSize(hMem
);
1377 if (metadata
.txtlen
>= 0)
1379 if (metadata
.txtlen
> maxlen
)
1382 str_size
= metadata
.txtlen
;
1386 for (str_size
= 0; str_size
< maxlen
; ++str_size
)
1387 if (str
[str_size
] == NUL
)
1391 # if defined(FEAT_MBYTE) && defined(WIN3264)
1392 /* The text is in the active codepage. Convert to 'encoding',
1393 * going through UTF-16. */
1394 acp_to_enc(str
, str_size
, &to_free
, &maxlen
);
1395 if (to_free
!= NULL
)
1407 if (str
!= NULL
&& *str
!= NUL
)
1409 char_u
*temp_clipboard
;
1411 /* If the type is not known guess it. */
1412 if (metadata
.type
== -1)
1413 metadata
.type
= (vim_strchr(str
, '\n') == NULL
) ? MCHAR
: MLINE
;
1415 /* Translate <CR><NL> into <NL>. */
1416 temp_clipboard
= crnl_to_nl(str
, &str_size
);
1417 if (temp_clipboard
!= NULL
)
1419 clip_yank_selection(metadata
.type
, temp_clipboard
, str_size
, cbd
);
1420 vim_free(temp_clipboard
);
1424 /* unlock the global object */
1432 #if defined(FEAT_MBYTE) && defined(WIN3264)
1437 #if (defined(FEAT_MBYTE) && defined(WIN3264)) || defined(PROTO)
1439 * Convert from the active codepage to 'encoding'.
1440 * Input is "str[str_size]".
1441 * The result is in allocated memory: "out[outlen]". With terminating NUL.
1444 acp_to_enc(str
, str_size
, out
, outlen
)
1453 MultiByteToWideChar_alloc(GetACP(), 0, str
, str_size
, &widestr
, outlen
);
1454 if (widestr
!= NULL
)
1456 ++*outlen
; /* Include the 0 after the string */
1457 *out
= utf16_to_enc((short_u
*)widestr
, outlen
);
1464 * Send the current selection to the clipboard.
1467 clip_mch_set_selection(VimClipboard
*cbd
)
1470 VimClipType_t metadata
;
1472 HGLOBAL hMemRaw
= NULL
;
1473 HGLOBAL hMem
= NULL
;
1474 HGLOBAL hMemVim
= NULL
;
1475 # if defined(FEAT_MBYTE) && defined(WIN3264)
1476 HGLOBAL hMemW
= NULL
;
1479 /* If the '*' register isn't already filled in, fill it in now */
1481 clip_get_selection(cbd
);
1484 /* Get the text to be put on the clipboard, with CR-LF. */
1485 metadata
.type
= clip_convert_selection(&str
, &txtlen
, cbd
);
1486 if (metadata
.type
< 0)
1488 metadata
.txtlen
= (int)txtlen
;
1489 metadata
.ucslen
= 0;
1490 metadata
.rawlen
= 0;
1493 /* Always set the raw bytes: 'encoding', NUL and the text. This is used
1494 * when copy/paste from/to Vim with the same 'encoding', so that illegal
1495 * bytes can also be copied and no conversion is needed. */
1499 metadata
.rawlen
= (int)(txtlen
+ STRLEN(p_enc
) + 1);
1500 hMemRaw
= (LPSTR
)GlobalAlloc(GMEM_MOVEABLE
| GMEM_DDESHARE
,
1501 metadata
.rawlen
+ 1);
1502 lpszMemRaw
= (LPSTR
)GlobalLock(hMemRaw
);
1503 if (lpszMemRaw
!= NULL
)
1505 STRCPY(lpszMemRaw
, p_enc
);
1506 memcpy(lpszMemRaw
+ STRLEN(p_enc
) + 1, str
, txtlen
+ 1);
1507 GlobalUnlock(hMemRaw
);
1510 metadata
.rawlen
= 0;
1514 # if defined(FEAT_MBYTE) && defined(WIN3264)
1517 int len
= metadata
.txtlen
;
1519 /* Convert the text to UTF-16. This is put on the clipboard as
1520 * CF_UNICODETEXT. */
1521 out
= (WCHAR
*)enc_to_utf16(str
, &len
);
1526 /* Convert the text for CF_TEXT to Active codepage. Otherwise it's
1527 * p_enc, which has no relation to the Active codepage. */
1528 metadata
.txtlen
= WideCharToMultiByte(GetACP(), 0, out
, len
,
1531 str
= (char_u
*)alloc((unsigned)(metadata
.txtlen
== 0 ? 1
1532 : metadata
.txtlen
));
1536 return; /* out of memory */
1538 WideCharToMultiByte(GetACP(), 0, out
, len
,
1539 str
, metadata
.txtlen
, 0, 0);
1541 /* Allocate memory for the UTF-16 text, add one NUL word to
1542 * terminate the string. */
1543 hMemW
= (LPSTR
)GlobalAlloc(GMEM_MOVEABLE
| GMEM_DDESHARE
,
1544 (len
+ 1) * sizeof(WCHAR
));
1545 lpszMemW
= (WCHAR
*)GlobalLock(hMemW
);
1546 if (lpszMemW
!= NULL
)
1548 memcpy(lpszMemW
, out
, len
* sizeof(WCHAR
));
1549 lpszMemW
[len
] = NUL
;
1550 GlobalUnlock(hMemW
);
1553 metadata
.ucslen
= len
;
1558 /* Allocate memory for the text, add one NUL byte to terminate the string.
1560 hMem
= GlobalAlloc(GMEM_MOVEABLE
| GMEM_DDESHARE
, metadata
.txtlen
+ 1);
1562 LPSTR lpszMem
= (LPSTR
)GlobalLock(hMem
);
1566 vim_strncpy(lpszMem
, str
, metadata
.txtlen
);
1571 /* Set up metadata: */
1573 VimClipType_t
*lpszMemVim
= NULL
;
1575 hMemVim
= GlobalAlloc(GMEM_MOVEABLE
|GMEM_DDESHARE
,
1576 sizeof(VimClipType_t
));
1577 lpszMemVim
= (VimClipType_t
*)GlobalLock(hMemVim
);
1578 memcpy(lpszMemVim
, &metadata
, sizeof(metadata
));
1579 GlobalUnlock(hMemVim
);
1583 * Open the clipboard, clear it and put our text on it.
1584 * Always set our Vim format. Put Unicode and plain text on it.
1586 * Don't pass GetActiveWindow() as an argument to OpenClipboard()
1587 * because then we can't paste back into the same window for some
1590 if (vim_open_clipboard())
1592 if (EmptyClipboard())
1594 SetClipboardData(cbd
->format
, hMemVim
);
1596 # if defined(FEAT_MBYTE) && defined(WIN3264)
1599 if (SetClipboardData(CF_UNICODETEXT
, hMemW
) != NULL
)
1603 /* Always use CF_TEXT. On Win98 Notepad won't obtain the
1604 * CF_UNICODETEXT text, only CF_TEXT. */
1605 SetClipboardData(CF_TEXT
, hMem
);
1612 /* Free any allocations we didn't give to the clipboard: */
1614 GlobalFree(hMemRaw
);
1617 # if defined(FEAT_MBYTE) && defined(WIN3264)
1622 GlobalFree(hMemVim
);
1625 #endif /* FEAT_CLIPBOARD */
1629 * Debugging helper: expose the MCH_WRITE_DUMP stuff to other modules
1636 # ifdef MCH_WRITE_DUMP
1640 if (psz
[strlen(psz
) - 1] != '\n')
1641 fputc('\n', fdDump
);
1657 va_start(args
, pszFormat
);
1658 vsprintf(szBuff
, pszFormat
, args
);
1661 OutputDebugString(szBuff
);
1666 #if !defined(FEAT_GUI) || defined(PROTO)
1667 # if defined(FEAT_TITLE) && defined(WIN3264)
1668 extern HWND g_hWnd
; /* This is in os_win32.c. */
1672 * Showing the printer dialog is tricky since we have no GUI
1673 * window to parent it. The following routines are needed to
1674 * get the window parenting and Z-order to work properly.
1677 GetConsoleHwnd(void)
1679 # define MY_BUFSIZE 1024 // Buffer size for console window titles.
1681 char pszNewWindowTitle
[MY_BUFSIZE
]; // Contains fabricated WindowTitle.
1682 char pszOldWindowTitle
[MY_BUFSIZE
]; // Contains original WindowTitle.
1684 /* Skip if it's already set. */
1688 # if defined(FEAT_TITLE) && defined(WIN3264)
1689 /* Window handle may have been found by init code (Windows NT only) */
1697 GetConsoleTitle(pszOldWindowTitle
, MY_BUFSIZE
);
1699 wsprintf(pszNewWindowTitle
, "%s/%d/%d",
1702 GetCurrentProcessId());
1703 SetConsoleTitle(pszNewWindowTitle
);
1705 s_hwnd
= FindWindow(NULL
, pszNewWindowTitle
);
1707 SetConsoleTitle(pszOldWindowTitle
);
1711 * Console implementation of ":winpos".
1714 mch_get_winpos(int *x
, int *y
)
1719 GetWindowRect(s_hwnd
, &rect
);
1726 * Console implementation of ":winpos x y".
1729 mch_set_winpos(int x
, int y
)
1732 SetWindowPos(s_hwnd
, NULL
, x
, y
, 0, 0,
1733 SWP_NOZORDER
| SWP_NOSIZE
| SWP_NOACTIVATE
);
1737 #if (defined(FEAT_PRINTER) && !defined(FEAT_POSTSCRIPT)) || defined(PROTO)
1742 /*=================================================================
1743 * Win32 printer stuff
1746 static HFONT prt_font_handles
[2][2][2];
1747 static PRINTDLG prt_dlg
;
1748 static const int boldface
[2] = {FW_REGULAR
, FW_BOLD
};
1749 static TEXTMETRIC prt_tm
;
1750 static int prt_line_height
;
1751 static int prt_number_width
;
1752 static int prt_left_margin
;
1753 static int prt_right_margin
;
1754 static int prt_top_margin
;
1755 static char_u szAppName
[] = TEXT("VIM");
1756 static HWND hDlgPrint
;
1757 static int *bUserAbort
= NULL
;
1758 static char_u
*prt_name
= NULL
;
1760 /* Defines which are also in vim.rc. */
1761 #define IDC_BOX1 400
1762 #define IDC_PRINTTEXT1 401
1763 #define IDC_PRINTTEXT2 402
1764 #define IDC_PROGRESS 403
1767 * Convert BGR to RGB for Windows GDI calls
1770 swap_me(COLORREF colorref
)
1773 char *ptr
= (char *)&colorref
;
1776 *(ptr
) = *(ptr
+ 2);
1781 /* Attempt to make this work for old and new compilers */
1783 # define PDP_RETVAL BOOL
1785 # define PDP_RETVAL INT_PTR
1789 static PDP_RETVAL CALLBACK
1790 PrintDlgProc(HWND hDlg
, UINT message
, WPARAM wParam
, LPARAM lParam
)
1793 NONCLIENTMETRICS nm
;
1801 nm
.cbSize
= sizeof(NONCLIENTMETRICS
);
1802 if (SystemParametersInfo(
1803 SPI_GETNONCLIENTMETRICS
,
1804 sizeof(NONCLIENTMETRICS
),
1808 char buff
[MAX_PATH
];
1811 /* Translate the dialog texts */
1812 hfont
= CreateFontIndirect(&nm
.lfMessageFont
);
1813 for (i
= IDC_PRINTTEXT1
; i
<= IDC_PROGRESS
; i
++)
1815 SendDlgItemMessage(hDlg
, i
, WM_SETFONT
, (WPARAM
)hfont
, 1);
1816 if (GetDlgItemText(hDlg
,i
, buff
, sizeof(buff
)))
1817 SetDlgItemText(hDlg
,i
, _(buff
));
1819 SendDlgItemMessage(hDlg
, IDCANCEL
,
1820 WM_SETFONT
, (WPARAM
)hfont
, 1);
1821 if (GetDlgItemText(hDlg
,IDCANCEL
, buff
, sizeof(buff
)))
1822 SetDlgItemText(hDlg
,IDCANCEL
, _(buff
));
1825 SetWindowText(hDlg
, szAppName
);
1826 if (prt_name
!= NULL
)
1828 SetDlgItemText(hDlg
, IDC_PRINTTEXT2
, (LPSTR
)prt_name
);
1832 EnableMenuItem(GetSystemMenu(hDlg
, FALSE
), SC_CLOSE
, MF_GRAYED
);
1834 BringWindowToTop(s_hwnd
);
1840 EnableWindow(GetParent(hDlg
), TRUE
);
1841 DestroyWindow(hDlg
);
1844 DeleteObject(hfont
);
1852 static BOOL CALLBACK
1853 AbortProc(HDC hdcPrn
, int iCode
)
1857 while (!*bUserAbort
&& PeekMessage(&msg
, NULL
, 0, 0, PM_REMOVE
))
1859 if (!hDlgPrint
|| !IsDialogMessage(hDlgPrint
, &msg
))
1861 TranslateMessage(&msg
);
1862 DispatchMessage(&msg
);
1865 return !*bUserAbort
;
1870 static UINT CALLBACK
1872 HWND hDlg
, // handle to dialog box
1873 UINT uiMsg
, // message identifier
1874 WPARAM wParam
, // message parameter
1875 LPARAM lParam
// message parameter
1879 RECT rc
, rcDlg
, rcOwner
;
1882 if (uiMsg
== WM_INITDIALOG
)
1884 // Get the owner window and dialog box rectangles.
1885 if ((hwndOwner
= GetParent(hDlg
)) == NULL
)
1886 hwndOwner
= GetDesktopWindow();
1888 GetWindowRect(hwndOwner
, &rcOwner
);
1889 GetWindowRect(hDlg
, &rcDlg
);
1890 CopyRect(&rc
, &rcOwner
);
1892 // Offset the owner and dialog box rectangles so that
1893 // right and bottom values represent the width and
1894 // height, and then offset the owner again to discard
1895 // space taken up by the dialog box.
1897 OffsetRect(&rcDlg
, -rcDlg
.left
, -rcDlg
.top
);
1898 OffsetRect(&rc
, -rc
.left
, -rc
.top
);
1899 OffsetRect(&rc
, -rcDlg
.right
, -rcDlg
.bottom
);
1901 // The new position is the sum of half the remaining
1902 // space and the owner's original position.
1906 rcOwner
.left
+ (rc
.right
/ 2),
1907 rcOwner
.top
+ (rc
.bottom
/ 2),
1908 0, 0, // ignores size arguments
1911 /* tackle the printdlg copiesctrl problem */
1912 pPD
= (PRINTDLG
*)lParam
;
1913 pPD
->nCopies
= (WORD
)pPD
->lCustData
;
1914 SetDlgItemInt( hDlg
, edt3
, pPD
->nCopies
, FALSE
);
1915 /* Bring the window to top */
1916 BringWindowToTop(GetParent(hDlg
));
1917 SetForegroundWindow(hDlg
);
1925 mch_print_cleanup(void)
1931 for (pifBold
= 0; pifBold
<= 1; pifBold
++)
1932 for (pifItalic
= 0; pifItalic
<= 1; pifItalic
++)
1933 for (pifUnderline
= 0; pifUnderline
<= 1; pifUnderline
++)
1934 DeleteObject(prt_font_handles
[pifBold
][pifItalic
][pifUnderline
]);
1936 if (prt_dlg
.hDC
!= NULL
)
1937 DeleteDC(prt_dlg
.hDC
);
1939 SendMessage(hDlgPrint
, WM_COMMAND
, 0, 0);
1943 to_device_units(int idx
, int dpi
, int physsize
, int offset
, int def_number
)
1949 u
= prt_get_unit(idx
);
1950 if (u
== PRT_UNIT_NONE
)
1956 nr
= printer_opts
[idx
].number
;
1961 ret
= (physsize
* nr
) / 100;
1967 ret
= (nr
* 10 * dpi
) / 254;
1969 case PRT_UNIT_POINT
:
1970 ret
= (nr
* 10 * dpi
) / 720;
1977 return ret
- offset
;
1992 GetTextMetrics(prt_dlg
.hDC
, &prt_tm
);
1993 prt_line_height
= prt_tm
.tmHeight
+ prt_tm
.tmExternalLeading
;
1995 hr
= GetDeviceCaps(prt_dlg
.hDC
, HORZRES
);
1997 Escape(prt_dlg
.hDC
, GETPHYSPAGESIZE
, NULL
, NULL
, &pagesize
);
1999 Escape(prt_dlg
.hDC
, GETPRINTINGOFFSET
, NULL
, NULL
, &pagesize
);
2002 phyw
= GetDeviceCaps(prt_dlg
.hDC
, PHYSICALWIDTH
);
2003 dvoff
= GetDeviceCaps(prt_dlg
.hDC
, PHYSICALOFFSETX
);
2005 dpi
= GetDeviceCaps(prt_dlg
.hDC
, LOGPIXELSX
);
2007 rev_offset
= phyw
- (dvoff
+ hr
);
2009 prt_left_margin
= to_device_units(OPT_PRINT_LEFT
, dpi
, phyw
, dvoff
, 10);
2010 if (prt_use_number())
2012 prt_number_width
= PRINT_NUMBER_WIDTH
* prt_tm
.tmAveCharWidth
;
2013 prt_left_margin
+= prt_number_width
;
2016 prt_number_width
= 0;
2018 prt_right_margin
= hr
- to_device_units(OPT_PRINT_RIGHT
, dpi
, phyw
,
2021 return (prt_right_margin
- prt_left_margin
) / prt_tm
.tmAveCharWidth
;
2037 vr
= GetDeviceCaps(prt_dlg
.hDC
, VERTRES
);
2039 Escape(prt_dlg
.hDC
, GETPHYSPAGESIZE
, NULL
, NULL
, &pagesize
);
2041 Escape(prt_dlg
.hDC
, GETPRINTINGOFFSET
, NULL
, NULL
, &pagesize
);
2044 phyw
= GetDeviceCaps(prt_dlg
.hDC
, PHYSICALHEIGHT
);
2045 dvoff
= GetDeviceCaps(prt_dlg
.hDC
, PHYSICALOFFSETY
);
2047 dpi
= GetDeviceCaps(prt_dlg
.hDC
, LOGPIXELSY
);
2049 rev_offset
= phyw
- (dvoff
+ vr
);
2051 prt_top_margin
= to_device_units(OPT_PRINT_TOP
, dpi
, phyw
, dvoff
, 5);
2053 /* adjust top margin if there is a header */
2054 prt_top_margin
+= prt_line_height
* prt_header_height();
2056 bottom_margin
= vr
- to_device_units(OPT_PRINT_BOT
, dpi
, phyw
,
2059 return (bottom_margin
- prt_top_margin
) / prt_line_height
;
2063 mch_print_init(prt_settings_T
*psettings
, char_u
*jobname
, int forceit
)
2065 static HGLOBAL stored_dm
= NULL
;
2066 static HGLOBAL stored_devn
= NULL
;
2067 static int stored_nCopies
= 1;
2068 static int stored_nFlags
= 0;
2079 bUserAbort
= &(psettings
->user_abort
);
2080 memset(&prt_dlg
, 0, sizeof(PRINTDLG
));
2081 prt_dlg
.lStructSize
= sizeof(PRINTDLG
);
2083 GetConsoleHwnd(); /* get value of s_hwnd */
2085 prt_dlg
.hwndOwner
= s_hwnd
;
2086 prt_dlg
.Flags
= PD_NOPAGENUMS
| PD_NOSELECTION
| PD_RETURNDC
;
2089 prt_dlg
.hDevMode
= stored_dm
;
2090 prt_dlg
.hDevNames
= stored_devn
;
2091 prt_dlg
.lCustData
= stored_nCopies
; // work around bug in print dialog
2094 * Use hook to prevent console window being sent to back
2096 prt_dlg
.lpfnPrintHook
= PrintHookProc
;
2097 prt_dlg
.Flags
|= PD_ENABLEPRINTHOOK
;
2099 prt_dlg
.Flags
|= stored_nFlags
;
2103 * If bang present, return default printer setup with no dialog
2104 * never show dialog if we are running over telnet
2112 prt_dlg
.Flags
|= PD_RETURNDEFAULT
;
2115 * MSDN suggests setting the first parameter to WINSPOOL for
2116 * NT, but NULL appears to work just as well.
2119 prt_dlg
.hDC
= CreateDC(NULL
, p_pdev
, NULL
, NULL
);
2123 prt_dlg
.Flags
|= PD_RETURNDEFAULT
;
2124 if (PrintDlg(&prt_dlg
) == 0)
2128 else if (PrintDlg(&prt_dlg
) == 0)
2133 * keep the previous driver context
2135 stored_dm
= prt_dlg
.hDevMode
;
2136 stored_devn
= prt_dlg
.hDevNames
;
2137 stored_nFlags
= prt_dlg
.Flags
;
2138 stored_nCopies
= prt_dlg
.nCopies
;
2141 if (prt_dlg
.hDC
== NULL
)
2143 EMSG(_("E237: Printer selection failed"));
2144 mch_print_cleanup();
2148 /* Not all printer drivers report the support of color (or grey) in the
2149 * same way. Let's set has_color if there appears to be some way to print
2151 i
= GetDeviceCaps(prt_dlg
.hDC
, NUMCOLORS
);
2152 psettings
->has_color
= (GetDeviceCaps(prt_dlg
.hDC
, BITSPIXEL
) > 1
2153 || GetDeviceCaps(prt_dlg
.hDC
, PLANES
) > 1
2154 || i
> 2 || i
== -1);
2156 /* Ensure all font styles are baseline aligned */
2157 SetTextAlign(prt_dlg
.hDC
, TA_BASELINE
|TA_LEFT
);
2160 * On some windows systems the nCopies parameter is not
2161 * passed back correctly. It must be retrieved from the
2164 mem
= (DEVMODE
*)GlobalLock(prt_dlg
.hDevMode
);
2168 if (mem
->dmCopies
!= 1)
2169 stored_nCopies
= mem
->dmCopies
;
2171 if ((mem
->dmFields
& DM_DUPLEX
) && (mem
->dmDuplex
& ~DMDUP_SIMPLEX
))
2172 psettings
->duplex
= TRUE
;
2173 if ((mem
->dmFields
& DM_COLOR
) && (mem
->dmColor
& DMCOLOR_COLOR
))
2174 psettings
->has_color
= TRUE
;
2176 GlobalUnlock(prt_dlg
.hDevMode
);
2178 devname
= (DEVNAMES
*)GlobalLock(prt_dlg
.hDevNames
);
2181 char_u
*printer_name
= (char_u
*)devname
+ devname
->wDeviceOffset
;
2182 char_u
*port_name
= (char_u
*)devname
+devname
->wOutputOffset
;
2183 char_u
*text
= _("to %s on %s");
2185 prt_name
= alloc((unsigned)(STRLEN(printer_name
) + STRLEN(port_name
)
2187 if (prt_name
!= NULL
)
2188 wsprintf(prt_name
, text
, printer_name
, port_name
);
2190 GlobalUnlock(prt_dlg
.hDevNames
);
2193 * Initialise the font according to 'printfont'
2195 memset(&fLogFont
, 0, sizeof(fLogFont
));
2196 if (get_logfont(&fLogFont
, p_pfn
, prt_dlg
.hDC
, TRUE
) == FAIL
)
2198 EMSG2(_("E613: Unknown printer font: %s"), p_pfn
);
2199 mch_print_cleanup();
2203 for (pifBold
= 0; pifBold
<= 1; pifBold
++)
2204 for (pifItalic
= 0; pifItalic
<= 1; pifItalic
++)
2205 for (pifUnderline
= 0; pifUnderline
<= 1; pifUnderline
++)
2207 fLogFont
.lfWeight
= boldface
[pifBold
];
2208 fLogFont
.lfItalic
= pifItalic
;
2209 fLogFont
.lfUnderline
= pifUnderline
;
2210 prt_font_handles
[pifBold
][pifItalic
][pifUnderline
]
2211 = CreateFontIndirect(&fLogFont
);
2214 SetBkMode(prt_dlg
.hDC
, OPAQUE
);
2215 SelectObject(prt_dlg
.hDC
, prt_font_handles
[0][0][0]);
2218 * Fill in the settings struct
2220 psettings
->chars_per_line
= prt_get_cpl();
2221 psettings
->lines_per_page
= prt_get_lpp();
2222 psettings
->n_collated_copies
= (prt_dlg
.Flags
& PD_COLLATE
)
2223 ? prt_dlg
.nCopies
: 1;
2224 psettings
->n_uncollated_copies
= (prt_dlg
.Flags
& PD_COLLATE
)
2225 ? 1 : prt_dlg
.nCopies
;
2227 if (psettings
->n_collated_copies
== 0)
2228 psettings
->n_collated_copies
= 1;
2230 if (psettings
->n_uncollated_copies
== 0)
2231 psettings
->n_uncollated_copies
= 1;
2233 psettings
->jobname
= jobname
;
2239 DWORD err
= CommDlgExtendedError();
2246 sprintf(buf
, "%ld", err
);
2247 EMSG2(_("E238: Print error: %s"), buf
);
2251 /* I suspect FormatMessage() doesn't work for values returned by
2252 * CommDlgExtendedError(). What does? */
2253 FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER
|
2254 FORMAT_MESSAGE_FROM_SYSTEM
|
2255 FORMAT_MESSAGE_IGNORE_INSERTS
,
2256 NULL
, err
, 0, (LPTSTR
)(&buf
), 0, NULL
);
2257 EMSG2(_("E238: Print error: %s"),
2258 buf
== NULL
? (char_u
*)_("Unknown") : buf
);
2259 LocalFree((LPVOID
)(buf
));
2263 msg_clr_eos(); /* Maybe canceled */
2265 mch_print_cleanup();
2272 mch_print_begin(prt_settings_T
*psettings
)
2278 hDlgPrint
= CreateDialog(GetModuleHandle(NULL
), TEXT("PrintDlgBox"),
2279 prt_dlg
.hwndOwner
, PrintDlgProc
);
2281 Escape(prt_dlg
.hDC
, SETABORTPROC
, 0, (LPSTR
)AbortProc
, NULL
);
2283 SetAbortProc(prt_dlg
.hDC
, AbortProc
);
2285 wsprintf(szBuffer
, _("Printing '%s'"), gettail(psettings
->jobname
));
2286 SetDlgItemText(hDlgPrint
, IDC_PRINTTEXT1
, (LPSTR
)szBuffer
);
2288 memset(&di
, 0, sizeof(DOCINFO
));
2289 di
.cbSize
= sizeof(DOCINFO
);
2290 di
.lpszDocName
= psettings
->jobname
;
2291 ret
= StartDoc(prt_dlg
.hDC
, &di
);
2294 /* Give focus back to main window (when using MDI). */
2303 mch_print_end(prt_settings_T
*psettings
)
2305 EndDoc(prt_dlg
.hDC
);
2307 SendMessage(hDlgPrint
, WM_COMMAND
, 0, 0);
2311 mch_print_end_page(void)
2313 return (EndPage(prt_dlg
.hDC
) > 0);
2317 mch_print_begin_page(char_u
*msg
)
2320 SetDlgItemText(hDlgPrint
, IDC_PROGRESS
, (LPSTR
)msg
);
2321 return (StartPage(prt_dlg
.hDC
) > 0);
2325 mch_print_blank_page(void)
2327 return (mch_print_begin_page(NULL
) ? (mch_print_end_page()) : FALSE
);
2330 static int prt_pos_x
= 0;
2331 static int prt_pos_y
= 0;
2334 mch_print_start_line(margin
, page_line
)
2339 prt_pos_x
= -prt_number_width
;
2342 prt_pos_y
= page_line
* prt_line_height
2343 + prt_tm
.tmAscent
+ prt_tm
.tmExternalLeading
;
2347 mch_print_text_out(char_u
*p
, int len
)
2349 #ifdef FEAT_PROPORTIONAL_FONTS
2353 TextOut(prt_dlg
.hDC
, prt_pos_x
+ prt_left_margin
,
2354 prt_pos_y
+ prt_top_margin
, p
, len
);
2355 #ifndef FEAT_PROPORTIONAL_FONTS
2356 prt_pos_x
+= len
* prt_tm
.tmAveCharWidth
;
2357 return (prt_pos_x
+ prt_left_margin
+ prt_tm
.tmAveCharWidth
2358 + prt_tm
.tmOverhang
> prt_right_margin
);
2361 GetTextExtentPoint(prt_dlg
.hDC
, p
, len
, &sz
);
2363 GetTextExtentPoint32(prt_dlg
.hDC
, p
, len
, &sz
);
2365 prt_pos_x
+= (sz
.cx
- prt_tm
.tmOverhang
);
2366 /* This is wrong when printing spaces for a TAB. */
2370 GetTextExtentPoint(prt_dlg
.hDC
, p
+ len
, 1, &sz
);
2372 GetTextExtentPoint32(prt_dlg
.hDC
, p
+ len
, 1, &sz
);
2374 return (prt_pos_x
+ prt_left_margin
+ sz
.cx
> prt_right_margin
);
2379 mch_print_set_font(int iBold
, int iItalic
, int iUnderline
)
2381 SelectObject(prt_dlg
.hDC
, prt_font_handles
[iBold
][iItalic
][iUnderline
]);
2385 mch_print_set_bg(long_u bgcol
)
2387 SetBkColor(prt_dlg
.hDC
, GetNearestColor(prt_dlg
.hDC
,
2388 swap_me((COLORREF
)bgcol
)));
2390 * With a white background we can draw characters transparent, which is
2391 * good for italic characters that overlap to the next char cell.
2393 if (bgcol
== 0xffffffUL
)
2394 SetBkMode(prt_dlg
.hDC
, TRANSPARENT
);
2396 SetBkMode(prt_dlg
.hDC
, OPAQUE
);
2400 mch_print_set_fg(long_u fgcol
)
2402 SetTextColor(prt_dlg
.hDC
, GetNearestColor(prt_dlg
.hDC
,
2403 swap_me((COLORREF
)fgcol
)));
2406 #endif /*FEAT_PRINTER && !FEAT_POSTSCRIPT*/
2410 #if defined(FEAT_SHORTCUT) || defined(PROTO)
2411 # include <shlobj.h>
2414 * When "fname" is the name of a shortcut (*.lnk) resolve the file it points
2415 * to and return that name in allocated memory.
2416 * Otherwise NULL is returned.
2419 mch_resolve_shortcut(char_u
*fname
)
2422 IShellLink
*psl
= NULL
;
2423 IPersistFile
*ppf
= NULL
;
2424 OLECHAR wsz
[MAX_PATH
];
2425 WIN32_FIND_DATA ffd
; // we get those free of charge
2426 TCHAR buf
[MAX_PATH
]; // could have simply reused 'wsz'...
2427 char_u
*rfname
= NULL
;
2430 /* Check if the file name ends in ".lnk". Avoid calling
2431 * CoCreateInstance(), it's quite slow. */
2434 len
= (int)STRLEN(fname
);
2435 if (len
<= 4 || STRNICMP(fname
+ len
- 4, ".lnk", 4) != 0)
2440 // create a link manager object and request its interface
2441 hr
= CoCreateInstance(
2442 &CLSID_ShellLink
, NULL
, CLSCTX_INPROC_SERVER
,
2443 &IID_IShellLink
, (void**)&psl
);
2445 goto shortcut_error
;
2447 // Get a pointer to the IPersistFile interface.
2448 hr
= psl
->lpVtbl
->QueryInterface(
2449 psl
, &IID_IPersistFile
, (void**)&ppf
);
2451 goto shortcut_error
;
2453 // full path string must be in Unicode.
2454 MultiByteToWideChar(CP_ACP
, 0, fname
, -1, wsz
, MAX_PATH
);
2456 // "load" the name and resolve the link
2457 hr
= ppf
->lpVtbl
->Load(ppf
, wsz
, STGM_READ
);
2459 goto shortcut_error
;
2460 #if 0 // This makes Vim wait a long time if the target doesn't exist.
2461 hr
= psl
->lpVtbl
->Resolve(psl
, NULL
, SLR_NO_UI
);
2463 goto shortcut_error
;
2466 // Get the path to the link target.
2467 ZeroMemory(buf
, MAX_PATH
);
2468 hr
= psl
->lpVtbl
->GetPath(psl
, buf
, MAX_PATH
, &ffd
, 0);
2469 if (hr
== S_OK
&& buf
[0] != NUL
)
2470 rfname
= vim_strsave(buf
);
2473 // Release all interface pointers (both belong to the same object)
2475 ppf
->lpVtbl
->Release(ppf
);
2477 psl
->lpVtbl
->Release(psl
);
2484 #if (defined(FEAT_EVAL) && !defined(FEAT_GUI)) || defined(PROTO)
2486 * Bring ourselves to the foreground. Does work if the OS doesn't allow it.
2489 win32_set_foreground()
2492 GetConsoleHwnd(); /* get value of s_hwnd */
2495 SetForegroundWindow(s_hwnd
);
2499 #if defined(FEAT_CLIENTSERVER) || defined(PROTO)
2501 * Client-server code for Vim
2503 * Originally written by Paul Moore
2506 /* In order to handle inter-process messages, we need to have a window. But
2507 * the functions in this module can be called before the main GUI window is
2508 * created (and may also be called in the console version, where there is no
2509 * GUI window at all).
2511 * So we create a hidden window, and arrange to destroy it on exit.
2513 HWND message_window
= 0; /* window that's handling messsages */
2515 #define VIM_CLASSNAME "VIM_MESSAGES"
2516 #define VIM_CLASSNAME_LEN (sizeof(VIM_CLASSNAME) - 1)
2518 /* Communication is via WM_COPYDATA messages. The message type is send in
2519 * the dwData parameter. Types are defined here. */
2520 #define COPYDATA_KEYS 0
2521 #define COPYDATA_REPLY 1
2522 #define COPYDATA_EXPR 10
2523 #define COPYDATA_RESULT 11
2524 #define COPYDATA_ERROR_RESULT 12
2525 #define COPYDATA_ENCODING 20
2527 /* This is a structure containing a server HWND and its name. */
2534 /* Last received 'encoding' that the client uses. */
2535 static char_u
*client_enc
= NULL
;
2538 * Tell the other side what encoding we are using.
2539 * Errors are ignored.
2542 serverSendEnc(HWND target
)
2544 COPYDATASTRUCT data
;
2546 data
.dwData
= COPYDATA_ENCODING
;
2548 data
.cbData
= (DWORD
)STRLEN(p_enc
) + 1;
2549 data
.lpData
= p_enc
;
2551 data
.cbData
= STRLEN("latin1") + 1;
2552 data
.lpData
= "latin1";
2554 (void)SendMessage(target
, WM_COPYDATA
, (WPARAM
)message_window
,
2559 * Clean up on exit. This destroys the hidden message window.
2565 CleanUpMessaging(void)
2567 if (message_window
!= 0)
2569 DestroyWindow(message_window
);
2574 static int save_reply(HWND server
, char_u
*reply
, int expr
);
2577 * The window procedure for the hidden message window.
2578 * It handles callback messages and notifications from servers.
2579 * In order to process these messages, it is necessary to run a
2580 * message loop. Code which may run before the main message loop
2581 * is started (in the GUI) is careful to pump messages when it needs
2582 * to. Features which require message delivery during normal use will
2583 * not work in the console version - this basically means those
2584 * features which allow Vim to act as a server, rather than a client.
2586 static LRESULT CALLBACK
2587 Messaging_WndProc(HWND hwnd
, UINT msg
, WPARAM wParam
, LPARAM lParam
)
2589 if (msg
== WM_COPYDATA
)
2591 /* This is a message from another Vim. The dwData member of the
2592 * COPYDATASTRUCT determines the type of message:
2593 * COPYDATA_ENCODING:
2594 * The encoding that the client uses. Following messages will
2595 * use this encoding, convert if needed.
2597 * A key sequence. We are a server, and a client wants these keys
2598 * adding to the input queue.
2600 * A reply. We are a client, and a server has sent this message
2601 * in response to a request. (server2client())
2603 * An expression. We are a server, and a client wants us to
2604 * evaluate this expression.
2606 * A reply. We are a client, and a server has sent this message
2607 * in response to a COPYDATA_EXPR.
2608 * COPYDATA_ERROR_RESULT:
2609 * A reply. We are a client, and a server has sent this message
2610 * in response to a COPYDATA_EXPR that failed to evaluate.
2612 COPYDATASTRUCT
*data
= (COPYDATASTRUCT
*)lParam
;
2613 HWND sender
= (HWND
)wParam
;
2614 COPYDATASTRUCT reply
;
2621 switch (data
->dwData
)
2623 case COPYDATA_ENCODING
:
2625 /* Remember the encoding that the client uses. */
2626 vim_free(client_enc
);
2627 client_enc
= enc_canonize((char_u
*)data
->lpData
);
2632 /* Remember who sent this, for <client> */
2633 clientWindow
= sender
;
2635 /* Add the received keys to the input buffer. The loop waiting
2636 * for the user to do something should check the input buffer. */
2637 str
= serverConvert(client_enc
, (char_u
*)data
->lpData
, &tofree
);
2638 server_to_input_buf(str
);
2642 /* Wake up the main GUI loop. */
2644 PostMessage(s_hwnd
, WM_NULL
, 0, 0);
2649 /* Remember who sent this, for <client> */
2650 clientWindow
= sender
;
2652 str
= serverConvert(client_enc
, (char_u
*)data
->lpData
, &tofree
);
2653 res
= eval_client_expr_to_string(str
);
2658 res
= vim_strsave(_(e_invexprmsg
));
2659 reply
.dwData
= COPYDATA_ERROR_RESULT
;
2662 reply
.dwData
= COPYDATA_RESULT
;
2664 reply
.cbData
= (DWORD
)STRLEN(res
) + 1;
2666 serverSendEnc(sender
);
2667 retval
= (int)SendMessage(sender
, WM_COPYDATA
, (WPARAM
)message_window
,
2672 case COPYDATA_REPLY
:
2673 case COPYDATA_RESULT
:
2674 case COPYDATA_ERROR_RESULT
:
2675 if (data
->lpData
!= NULL
)
2677 str
= serverConvert(client_enc
, (char_u
*)data
->lpData
,
2680 str
= vim_strsave(str
);
2681 if (save_reply(sender
, str
,
2682 (data
->dwData
== COPYDATA_REPLY
? 0 :
2683 (data
->dwData
== COPYDATA_RESULT
? 1 :
2687 else if (data
->dwData
== COPYDATA_REPLY
)
2689 sprintf((char *)winstr
, PRINTF_HEX_LONG_U
, (long_u
)sender
);
2690 apply_autocmds(EVENT_REMOTEREPLY
, winstr
, str
,
2701 else if (msg
== WM_ACTIVATE
&& wParam
== WA_ACTIVE
)
2703 /* When the message window is activated (brought to the foreground),
2704 * this actually applies to the text window. */
2706 GetConsoleHwnd(); /* get value of s_hwnd */
2710 SetForegroundWindow(s_hwnd
);
2715 return DefWindowProc(hwnd
, msg
, wParam
, lParam
);
2719 * Initialise the message handling process. This involves creating a window
2720 * to handle messages - the window will not be visible.
2723 serverInitMessaging(void)
2728 /* Clean up on exit */
2729 atexit(CleanUpMessaging
);
2731 /* Register a window class - we only really care
2732 * about the window procedure
2734 s_hinst
= (HINSTANCE
)GetModuleHandle(0);
2736 wndclass
.lpfnWndProc
= Messaging_WndProc
;
2737 wndclass
.cbClsExtra
= 0;
2738 wndclass
.cbWndExtra
= 0;
2739 wndclass
.hInstance
= s_hinst
;
2740 wndclass
.hIcon
= NULL
;
2741 wndclass
.hCursor
= NULL
;
2742 wndclass
.hbrBackground
= NULL
;
2743 wndclass
.lpszMenuName
= NULL
;
2744 wndclass
.lpszClassName
= VIM_CLASSNAME
;
2745 RegisterClass(&wndclass
);
2747 /* Create the message window. It will be hidden, so the details don't
2748 * matter. Don't use WS_OVERLAPPEDWINDOW, it will make a shortcut remove
2749 * focus from gvim. */
2750 message_window
= CreateWindow(VIM_CLASSNAME
, "",
2751 WS_POPUPWINDOW
| WS_CAPTION
,
2752 CW_USEDEFAULT
, CW_USEDEFAULT
,
2753 100, 100, NULL
, NULL
,
2757 /* Used by serverSendToVim() to find an alternate server name. */
2758 static char_u
*altname_buf_ptr
= NULL
;
2761 * Get the title of the window "hwnd", which is the Vim server name, in
2762 * "name[namelen]" and return the length.
2763 * Returns zero if window "hwnd" is not a Vim server.
2766 getVimServerName(HWND hwnd
, char *name
, int namelen
)
2769 char buffer
[VIM_CLASSNAME_LEN
+ 1];
2771 /* Ignore windows which aren't Vim message windows */
2772 len
= GetClassName(hwnd
, buffer
, sizeof(buffer
));
2773 if (len
!= VIM_CLASSNAME_LEN
|| STRCMP(buffer
, VIM_CLASSNAME
) != 0)
2776 /* Get the title of the window */
2777 return GetWindowText(hwnd
, name
, namelen
);
2780 static BOOL CALLBACK
2781 enumWindowsGetServer(HWND hwnd
, LPARAM lparam
)
2783 struct server_id
*id
= (struct server_id
*)lparam
;
2784 char server
[MAX_PATH
];
2786 /* Get the title of the window */
2787 if (getVimServerName(hwnd
, server
, sizeof(server
)) == 0)
2790 /* If this is the server we're looking for, return its HWND */
2791 if (STRICMP(server
, id
->name
) == 0)
2797 /* If we are looking for an alternate server, remember this name. */
2798 if (altname_buf_ptr
!= NULL
2799 && STRNICMP(server
, id
->name
, STRLEN(id
->name
)) == 0
2800 && vim_isdigit(server
[STRLEN(id
->name
)]))
2802 STRCPY(altname_buf_ptr
, server
);
2803 altname_buf_ptr
= NULL
; /* don't use another name */
2806 /* Otherwise, keep looking */
2810 static BOOL CALLBACK
2811 enumWindowsGetNames(HWND hwnd
, LPARAM lparam
)
2813 garray_T
*ga
= (garray_T
*)lparam
;
2814 char server
[MAX_PATH
];
2816 /* Get the title of the window */
2817 if (getVimServerName(hwnd
, server
, sizeof(server
)) == 0)
2820 /* Add the name to the list */
2821 ga_concat(ga
, server
);
2822 ga_concat(ga
, "\n");
2827 findServer(char_u
*name
)
2829 struct server_id id
;
2834 EnumWindows(enumWindowsGetServer
, (LPARAM
)(&id
));
2840 serverSetName(char_u
*name
)
2847 /* Leave enough space for a 9-digit suffix to ensure uniqueness! */
2848 ok_name
= alloc((unsigned)STRLEN(name
) + 10);
2850 STRCPY(ok_name
, name
);
2851 p
= ok_name
+ STRLEN(name
);
2855 /* This is inefficient - we're doing an EnumWindows loop for each
2856 * possible name. It would be better to grab all names in one go,
2857 * and scan the list each time...
2859 hwnd
= findServer(ok_name
);
2867 sprintf((char *)p
, "%d", i
);
2874 /* Remember the name */
2875 serverName
= ok_name
;
2877 need_maketitle
= TRUE
; /* update Vim window title later */
2880 /* Update the message window title */
2881 SetWindowText(message_window
, ok_name
);
2884 /* Set the servername variable */
2885 set_vim_var_string(VV_SEND_SERVER
, serverName
, -1);
2891 serverGetVimNames(void)
2895 ga_init2(&ga
, 1, 100);
2897 EnumWindows(enumWindowsGetNames
, (LPARAM
)(&ga
));
2898 ga_append(&ga
, NUL
);
2904 serverSendReply(name
, reply
)
2905 char_u
*name
; /* Where to send. */
2906 char_u
*reply
; /* What to send. */
2909 COPYDATASTRUCT data
;
2912 /* The "name" argument is a magic cookie obtained from expand("<client>").
2913 * It should be of the form 0xXXXXX - i.e. a C hex literal, which is the
2914 * value of the client's message window HWND.
2916 sscanf((char *)name
, SCANF_HEX_LONG_U
, &n
);
2921 if (!IsWindow(target
))
2924 data
.dwData
= COPYDATA_REPLY
;
2925 data
.cbData
= (DWORD
)STRLEN(reply
) + 1;
2926 data
.lpData
= reply
;
2928 serverSendEnc(target
);
2929 if (SendMessage(target
, WM_COPYDATA
, (WPARAM
)message_window
,
2937 serverSendToVim(name
, cmd
, result
, ptarget
, asExpr
, silent
)
2938 char_u
*name
; /* Where to send. */
2939 char_u
*cmd
; /* What to send. */
2940 char_u
**result
; /* Result of eval'ed expression */
2941 void *ptarget
; /* HWND of server */
2942 int asExpr
; /* Expression or keys? */
2943 int silent
; /* don't complain about no server */
2946 COPYDATASTRUCT data
;
2947 char_u
*retval
= NULL
;
2949 char_u altname_buf
[MAX_PATH
];
2951 /* If the server name does not end in a digit then we look for an
2952 * alternate name. e.g. when "name" is GVIM the we may find GVIM2. */
2953 if (STRLEN(name
) > 1 && !vim_isdigit(name
[STRLEN(name
) - 1]))
2954 altname_buf_ptr
= altname_buf
;
2955 altname_buf
[0] = NUL
;
2956 target
= findServer(name
);
2957 altname_buf_ptr
= NULL
;
2958 if (target
== 0 && altname_buf
[0] != NUL
)
2959 /* Use another server name we found. */
2960 target
= findServer(altname_buf
);
2965 EMSG2(_(e_noserver
), name
);
2970 *(HWND
*)ptarget
= target
;
2972 data
.dwData
= asExpr
? COPYDATA_EXPR
: COPYDATA_KEYS
;
2973 data
.cbData
= (DWORD
)STRLEN(cmd
) + 1;
2976 serverSendEnc(target
);
2977 if (SendMessage(target
, WM_COPYDATA
, (WPARAM
)message_window
,
2978 (LPARAM
)(&data
)) == 0)
2982 retval
= serverGetReply(target
, &retcode
, TRUE
, TRUE
);
2987 *result
= retval
; /* Caller assumes responsibility for freeing */
2993 * Bring the server to the foreground.
2996 serverForeground(name
)
2999 HWND target
= findServer(name
);
3002 SetForegroundWindow(target
);
3005 /* Replies from server need to be stored until the client picks them up via
3006 * remote_read(). So we maintain a list of server-id/reply pairs.
3007 * Note that there could be multiple replies from one server pending if the
3008 * client is slow picking them up.
3009 * We just store the replies in a simple list. When we remove an entry, we
3010 * move list entries down to fill the gap.
3011 * The server ID is simply the HWND.
3015 HWND server
; /* server window */
3016 char_u
*reply
; /* reply string */
3017 int expr_result
; /* 0 for REPLY, 1 for RESULT 2 for error */
3020 static garray_T reply_list
= {0, 0, sizeof(reply_T
), 5, 0};
3022 #define REPLY_ITEM(i) ((reply_T *)(reply_list.ga_data) + (i))
3023 #define REPLY_COUNT (reply_list.ga_len)
3025 /* Flag which is used to wait for a reply */
3026 static int reply_received
= 0;
3029 * Store a reply. "reply" must be allocated memory (or NULL).
3032 save_reply(HWND server
, char_u
*reply
, int expr
)
3036 if (ga_grow(&reply_list
, 1) == FAIL
)
3039 rep
= REPLY_ITEM(REPLY_COUNT
);
3040 rep
->server
= server
;
3042 rep
->expr_result
= expr
;
3043 if (rep
->reply
== NULL
)
3052 * Get a reply from server "server".
3053 * When "expr_res" is non NULL, get the result of an expression, otherwise a
3054 * server2client() message.
3055 * When non NULL, point to return code. 0 => OK, -1 => ERROR
3056 * If "remove" is TRUE, consume the message, the caller must free it then.
3057 * if "wait" is TRUE block until a message arrives (or the server exits).
3060 serverGetReply(HWND server
, int *expr_res
, int remove
, int wait
)
3066 /* When waiting, loop until the message waiting for is received. */
3069 /* Reset this here, in case a message arrives while we are going
3070 * through the already received messages. */
3073 for (i
= 0; i
< REPLY_COUNT
; ++i
)
3075 rep
= REPLY_ITEM(i
);
3076 if (rep
->server
== server
3077 && ((rep
->expr_result
!= 0) == (expr_res
!= NULL
)))
3079 /* Save the values we've found for later */
3081 if (expr_res
!= NULL
)
3082 *expr_res
= rep
->expr_result
== 1 ? 0 : -1;
3086 /* Move the rest of the list down to fill the gap */
3087 mch_memmove(rep
, rep
+ 1,
3088 (REPLY_COUNT
- i
- 1) * sizeof(reply_T
));
3092 /* Return the reply to the caller, who takes on responsibility
3093 * for freeing it if "remove" is TRUE. */
3098 /* If we got here, we didn't find a reply. Return immediately if the
3099 * "wait" parameter isn't set. */
3103 /* We need to wait for a reply. Enter a message loop until the
3104 * "reply_received" flag gets set. */
3106 /* Loop until we receive a reply */
3107 while (reply_received
== 0)
3109 /* Wait for a SendMessage() call to us. This could be the reply
3110 * we are waiting for. Use a timeout of a second, to catch the
3111 * situation that the server died unexpectedly. */
3112 MsgWaitForMultipleObjects(0, NULL
, TRUE
, 1000, QS_ALLINPUT
);
3114 /* If the server has died, give up */
3115 if (!IsWindow(server
))
3118 serverProcessPendingMessages();
3126 * Process any messages in the Windows message queue.
3129 serverProcessPendingMessages(void)
3133 while (PeekMessage(&msg
, NULL
, 0, 0, PM_REMOVE
))
3135 TranslateMessage(&msg
);
3136 DispatchMessage(&msg
);
3140 #endif /* FEAT_CLIENTSERVER */
3142 #if defined(FEAT_GUI) || (defined(FEAT_PRINTER) && !defined(FEAT_POSTSCRIPT)) \
3151 static struct charset_pair
3154 {"ANSI", ANSI_CHARSET
},
3155 {"CHINESEBIG5", CHINESEBIG5_CHARSET
},
3156 {"DEFAULT", DEFAULT_CHARSET
},
3157 {"HANGEUL", HANGEUL_CHARSET
},
3158 {"OEM", OEM_CHARSET
},
3159 {"SHIFTJIS", SHIFTJIS_CHARSET
},
3160 {"SYMBOL", SYMBOL_CHARSET
},
3162 {"ARABIC", ARABIC_CHARSET
},
3163 {"BALTIC", BALTIC_CHARSET
},
3164 {"EASTEUROPE", EASTEUROPE_CHARSET
},
3165 {"GB2312", GB2312_CHARSET
},
3166 {"GREEK", GREEK_CHARSET
},
3167 {"HEBREW", HEBREW_CHARSET
},
3168 {"JOHAB", JOHAB_CHARSET
},
3169 {"MAC", MAC_CHARSET
},
3170 {"RUSSIAN", RUSSIAN_CHARSET
},
3171 {"THAI", THAI_CHARSET
},
3172 {"TURKISH", TURKISH_CHARSET
},
3173 # if (!defined(_MSC_VER) || (_MSC_VER > 1010)) \
3174 && (!defined(__BORLANDC__) || (__BORLANDC__ > 0x0500))
3175 {"VIETNAMESE", VIETNAMESE_CHARSET
},
3182 * Convert a charset ID to a name.
3183 * Return NULL when not recognized.
3186 charset_id2name(int id
)
3188 struct charset_pair
*cp
;
3190 for (cp
= charset_pairs
; cp
->name
!= NULL
; ++cp
)
3191 if ((BYTE
)id
== cp
->charset
)
3196 static const LOGFONT s_lfDefault
=
3198 -12, 0, 0, 0, FW_NORMAL
, FALSE
, FALSE
, FALSE
, DEFAULT_CHARSET
,
3199 OUT_DEFAULT_PRECIS
, CLIP_DEFAULT_PRECIS
,
3200 PROOF_QUALITY
, FIXED_PITCH
| FF_DONTCARE
,
3201 "Fixedsys" /* see _ReadVimIni */
3204 /* Initialise the "current height" to -12 (same as s_lfDefault) just
3205 * in case the user specifies a font in "guifont" with no size before a font
3206 * with an explicit size has been set. This defaults the size to this value
3207 * (-12 equates to roughly 9pt).
3209 int current_font_height
= -12; /* also used in gui_w48.c */
3211 /* Convert a string representing a point size into pixels. The string should
3212 * be a positive decimal number, with an optional decimal point (eg, "12", or
3213 * "10.5"). The pixel value is returned, and a pointer to the next unconverted
3214 * character is stored in *end. The flag "vertical" says whether this
3215 * calculation is for a vertical (height) size or a horizontal (width) one.
3218 points_to_pixels(char_u
*str
, char_u
**end
, int vertical
, long_i pprinter_dc
)
3223 HWND hwnd
= (HWND
)0;
3225 HDC printer_dc
= (HDC
)pprinter_dc
;
3229 if (*str
== '.' && divisor
== 0)
3231 /* Start keeping a divisor, for later */
3236 if (!VIM_ISDIGIT(*str
))
3240 points
+= *str
- '0';
3249 if (printer_dc
== NULL
)
3251 hwnd
= GetDesktopWindow();
3252 hdc
= GetWindowDC(hwnd
);
3257 pixels
= MulDiv(points
,
3258 GetDeviceCaps(hdc
, vertical
? LOGPIXELSY
: LOGPIXELSX
),
3261 if (printer_dc
== NULL
)
3262 ReleaseDC(hwnd
, hdc
);
3277 * 0 = terminate now (monospace & ANSI)
3278 * 1 = continue, still no luck...
3279 * 2 = continue, but we have an acceptable LOGFONT
3280 * (monospace, not ANSI)
3281 * We use these values, as EnumFontFamilies returns 1 if the
3282 * callback function is never called. So, we check the return as
3283 * 0 = perfect, 2 = OK, 1 = no good...
3284 * It's not pretty, but it works!
3287 LOGFONT
*lf
= (LOGFONT
*)(lparam
);
3289 #ifndef FEAT_PROPORTIONAL_FONTS
3290 /* Ignore non-monospace fonts without further ado */
3291 if ((ntm
->tmPitchAndFamily
& 1) != 0)
3295 /* Remember this LOGFONT as a "possible" */
3296 *lf
= elf
->elfLogFont
;
3298 /* Terminate the scan as soon as we find an ANSI font */
3299 if (lf
->lfCharSet
== ANSI_CHARSET
3300 || lf
->lfCharSet
== OEM_CHARSET
3301 || lf
->lfCharSet
== DEFAULT_CHARSET
)
3304 /* Continue the scan - we have a non-ANSI font */
3309 init_logfont(LOGFONT
*lf
)
3312 HWND hwnd
= GetDesktopWindow();
3313 HDC hdc
= GetWindowDC(hwnd
);
3315 n
= EnumFontFamilies(hdc
,
3316 (LPCSTR
)lf
->lfFaceName
,
3317 (FONTENUMPROC
)font_enumproc
,
3320 ReleaseDC(hwnd
, hdc
);
3322 /* If we couldn't find a useable font, return failure */
3326 /* Tidy up the rest of the LOGFONT structure. We set to a basic
3327 * font - get_logfont() sets bold, italic, etc based on the user's
3330 lf
->lfHeight
= current_font_height
;
3332 lf
->lfItalic
= FALSE
;
3333 lf
->lfUnderline
= FALSE
;
3334 lf
->lfStrikeOut
= FALSE
;
3335 lf
->lfWeight
= FW_NORMAL
;
3337 /* Return success */
3342 * Get font info from "name" into logfont "lf".
3343 * Return OK for a valid name, FAIL otherwise.
3354 static LOGFONT
*lastlf
= NULL
;
3360 if (STRCMP(name
, "*") == 0)
3362 #if defined(FEAT_GUI_W32)
3364 /* if name is "*", bring up std font dialog: */
3365 memset(&cf
, 0, sizeof(cf
));
3366 cf
.lStructSize
= sizeof(cf
);
3367 cf
.hwndOwner
= s_hwnd
;
3368 cf
.Flags
= CF_SCREENFONTS
| CF_FIXEDPITCHONLY
| CF_INITTOLOGFONTSTRUCT
;
3372 cf
.nFontType
= 0 ; //REGULAR_FONTTYPE;
3373 if (ChooseFont(&cf
))
3381 * Split name up, it could be <name>:h<height>:w<width> etc.
3383 for (p
= name
; *p
&& *p
!= ':'; p
++)
3385 if (p
- name
+ 1 > LF_FACESIZE
)
3386 return FAIL
; /* Name too long */
3387 lf
->lfFaceName
[p
- name
] = *p
;
3390 lf
->lfFaceName
[p
- name
] = NUL
;
3392 /* First set defaults */
3395 lf
->lfWeight
= FW_NORMAL
;
3396 lf
->lfItalic
= FALSE
;
3397 lf
->lfUnderline
= FALSE
;
3398 lf
->lfStrikeOut
= FALSE
;
3401 * If the font can't be found, try replacing '_' by ' '.
3403 if (init_logfont(lf
) == FAIL
)
3405 int did_replace
= FALSE
;
3407 for (i
= 0; lf
->lfFaceName
[i
]; ++i
)
3408 if (lf
->lfFaceName
[i
] == '_')
3410 lf
->lfFaceName
[i
] = ' ';
3413 if (!did_replace
|| init_logfont(lf
) == FAIL
)
3420 /* Set the values found after ':' */
3426 lf
->lfHeight
= - points_to_pixels(p
, &p
, TRUE
, (long_i
)printer_dc
);
3429 lf
->lfWidth
= points_to_pixels(p
, &p
, FALSE
, (long_i
)printer_dc
);
3432 #ifndef MSWIN16_FASTTEXT
3433 lf
->lfWeight
= FW_BOLD
;
3437 #ifndef MSWIN16_FASTTEXT
3438 lf
->lfItalic
= TRUE
;
3442 lf
->lfUnderline
= TRUE
;
3445 lf
->lfStrikeOut
= TRUE
;
3449 struct charset_pair
*cp
;
3451 for (cp
= charset_pairs
; cp
->name
!= NULL
; ++cp
)
3452 if (STRNCMP(p
, cp
->name
, strlen(cp
->name
)) == 0)
3454 lf
->lfCharSet
= cp
->charset
;
3455 p
+= strlen(cp
->name
);
3458 if (cp
->name
== NULL
&& verbose
)
3460 vim_snprintf((char *)IObuff
, IOSIZE
,
3461 _("E244: Illegal charset name \"%s\" in font name \"%s\""), p
, name
);
3470 vim_snprintf((char *)IObuff
, IOSIZE
,
3471 _("E245: Illegal char '%c' in font name \"%s\""),
3481 #if defined(FEAT_GUI_W32)
3484 /* ron: init lastlf */
3485 if (printer_dc
== NULL
)
3488 lastlf
= (LOGFONT
*)alloc(sizeof(LOGFONT
));
3490 mch_memmove(lastlf
, lf
, sizeof(LOGFONT
));
3496 #endif /* defined(FEAT_GUI) || defined(FEAT_PRINTER) */