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