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