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