xref: /vim-8.2.3635/src/winclip.c (revision 94688b8a)
1 /* vi:set ts=8 sts=4 sw=4 noet:
2  *
3  * VIM - Vi IMproved by Bram Moolenaar
4  *
5  * Do ":help uganda"  in Vim to read copying and usage conditions.
6  * Do ":help credits" in Vim to see a list of people who contributed.
7  * See README.txt for an overview of the Vim source code.
8  */
9 
10 /*
11  * winclip.c
12  *
13  * Routines for Win32 clipboard handling.
14  * Also used by Cygwin, using os_unix.c.
15  */
16 
17 #include "vimio.h"
18 #include "vim.h"
19 
20 /*
21  * Compile only the clipboard handling features when compiling for cygwin
22  * posix environment.
23  */
24 #ifdef FEAT_CYGWIN_WIN32_CLIPBOARD
25 # define WIN3264
26 # define WIN32_LEAN_AND_MEAN
27 # include <windows.h>
28 # include "winclip.pro"
29 #endif
30 
31 /*
32  * When generating prototypes for Win32 on Unix, these lines make the syntax
33  * errors disappear.  They do not need to be correct.
34  */
35 #ifdef PROTO
36 #define WINAPI
37 #define WINBASEAPI
38 typedef int DWORD;
39 typedef int LPBOOL;
40 typedef int LPCSTR;
41 typedef int LPCWSTR;
42 typedef int LPSTR;
43 typedef int LPWSTR;
44 typedef int UINT;
45 #endif
46 
47 /*
48  * Convert an UTF-8 string to UTF-16.
49  * "instr[inlen]" is the input.  "inlen" is in bytes.
50  * When "outstr" is NULL only return the number of UTF-16 words produced.
51  * Otherwise "outstr" must be a buffer of sufficient size.
52  * Returns the number of UTF-16 words produced.
53  */
54     int
55 utf8_to_utf16(char_u *instr, int inlen, short_u *outstr, int *unconvlenp)
56 {
57     int		outlen = 0;
58     char_u	*p = instr;
59     int		todo = inlen;
60     int		l;
61     int		ch;
62 
63     while (todo > 0)
64     {
65 	/* Only convert if we have a complete sequence. */
66 	l = utf_ptr2len_len(p, todo);
67 	if (l > todo)
68 	{
69 	    /* Return length of incomplete sequence. */
70 	    if (unconvlenp != NULL)
71 		*unconvlenp = todo;
72 	    break;
73 	}
74 
75 	ch = utf_ptr2char(p);
76 	if (ch >= 0x10000)
77 	{
78 	    /* non-BMP character, encoding with surrogate pairs */
79 	    ++outlen;
80 	    if (outstr != NULL)
81 	    {
82 		*outstr++ = (0xD800 - (0x10000 >> 10)) + (ch >> 10);
83 		*outstr++ = 0xDC00 | (ch & 0x3FF);
84 	    }
85 	}
86 	else if (outstr != NULL)
87 	    *outstr++ = ch;
88 	++outlen;
89 	p += l;
90 	todo -= l;
91     }
92 
93     return outlen;
94 }
95 
96 /*
97  * Convert an UTF-16 string to UTF-8.
98  * The input is "instr[inlen]" with "inlen" in number of UTF-16 words.
99  * When "outstr" is NULL only return the required number of bytes.
100  * Otherwise "outstr" must be a buffer of sufficient size.
101  * Return the number of bytes produced.
102  */
103     int
104 utf16_to_utf8(short_u *instr, int inlen, char_u *outstr)
105 {
106     int		outlen = 0;
107     int		todo = inlen;
108     short_u	*p = instr;
109     int		l;
110     int		ch, ch2;
111 
112     while (todo > 0)
113     {
114 	ch = *p;
115 	if (ch >= 0xD800 && ch <= 0xDBFF && todo > 1)
116 	{
117 	    /* surrogate pairs handling */
118 	    ch2 = p[1];
119 	    if (ch2 >= 0xDC00 && ch2 <= 0xDFFF)
120 	    {
121 		ch = ((ch - 0xD800) << 10) + (ch2 & 0x3FF) + 0x10000;
122 		++p;
123 		--todo;
124 	    }
125 	}
126 	if (outstr != NULL)
127 	{
128 	    l = utf_char2bytes(ch, outstr);
129 	    outstr += l;
130 	}
131 	else
132 	    l = utf_char2len(ch);
133 	++p;
134 	outlen += l;
135 	--todo;
136     }
137 
138     return outlen;
139 }
140 
141 /*
142  * Call MultiByteToWideChar() and allocate memory for the result.
143  * Returns the result in "*out[*outlen]" with an extra zero appended.
144  * "outlen" is in words.
145  */
146     void
147 MultiByteToWideChar_alloc(UINT cp, DWORD flags,
148 	LPCSTR in, int inlen,
149 	LPWSTR *out, int *outlen)
150 {
151     *outlen = MultiByteToWideChar(cp, flags, in, inlen, 0, 0);
152     /* Add one one word to avoid a zero-length alloc(). */
153     *out = (LPWSTR)alloc(sizeof(WCHAR) * (*outlen + 1));
154     if (*out != NULL)
155     {
156 	MultiByteToWideChar(cp, flags, in, inlen, *out, *outlen);
157 	(*out)[*outlen] = 0;
158     }
159 }
160 
161 /*
162  * Call WideCharToMultiByte() and allocate memory for the result.
163  * Returns the result in "*out[*outlen]" with an extra NUL appended.
164  */
165     void
166 WideCharToMultiByte_alloc(UINT cp, DWORD flags,
167 	LPCWSTR in, int inlen,
168 	LPSTR *out, int *outlen,
169 	LPCSTR def, LPBOOL useddef)
170 {
171     *outlen = WideCharToMultiByte(cp, flags, in, inlen, NULL, 0, def, useddef);
172     /* Add one one byte to avoid a zero-length alloc(). */
173     *out = (LPSTR)alloc((unsigned)*outlen + 1);
174     if (*out != NULL)
175     {
176 	WideCharToMultiByte(cp, flags, in, inlen, *out, *outlen, def, useddef);
177 	(*out)[*outlen] = 0;
178     }
179 }
180 
181 
182 #ifdef FEAT_CLIPBOARD
183 /*
184  * Clipboard stuff, for cutting and pasting text to other windows.
185  */
186 
187     void
188 win_clip_init(void)
189 {
190     clip_init(TRUE);
191 
192     /*
193      * Vim's own clipboard format recognises whether the text is char, line,
194      * or rectangular block.  Only useful for copying between two Vims.
195      * "VimClipboard" was used for previous versions, using the first
196      * character to specify MCHAR, MLINE or MBLOCK.
197      */
198     clip_star.format = RegisterClipboardFormat("VimClipboard2");
199     clip_star.format_raw = RegisterClipboardFormat("VimRawBytes");
200 }
201 
202 /* Type used for the clipboard type of Vim's data. */
203 typedef struct
204 {
205     int type;		/* MCHAR, MBLOCK or MLINE */
206     int txtlen;		/* length of CF_TEXT in bytes */
207     int ucslen;		/* length of CF_UNICODETEXT in words */
208     int rawlen;		/* length of clip_star.format_raw, including encoding,
209 			   excluding terminating NUL */
210 } VimClipType_t;
211 
212 /*
213  * Make vim the owner of the current selection.  Return OK upon success.
214  */
215     int
216 clip_mch_own_selection(VimClipboard *cbd UNUSED)
217 {
218     /*
219      * Never actually own the clipboard.  If another application sets the
220      * clipboard, we don't want to think that we still own it.
221      */
222     return FAIL;
223 }
224 
225 /*
226  * Make vim NOT the owner of the current selection.
227  */
228     void
229 clip_mch_lose_selection(VimClipboard *cbd UNUSED)
230 {
231     /* Nothing needs to be done here */
232 }
233 
234 /*
235  * Copy "str[*size]" into allocated memory, changing CR-NL to NL.
236  * Return the allocated result and the size in "*size".
237  * Returns NULL when out of memory.
238  */
239     static char_u *
240 crnl_to_nl(const char_u *str, int *size)
241 {
242     int		pos = 0;
243     int		str_len = *size;
244     char_u	*ret;
245     char_u	*retp;
246 
247     /* Avoid allocating zero bytes, it generates an error message. */
248     ret = lalloc((long_u)(str_len == 0 ? 1 : str_len), TRUE);
249     if (ret != NULL)
250     {
251 	retp = ret;
252 	for (pos = 0; pos < str_len; ++pos)
253 	{
254 	    if (str[pos] == '\r' && str[pos + 1] == '\n')
255 	    {
256 		++pos;
257 		--(*size);
258 	    }
259 	    *retp++ = str[pos];
260 	}
261     }
262 
263     return ret;
264 }
265 
266 /*
267  * Wait for another process to Close the Clipboard.
268  * Returns TRUE for success.
269  */
270     static int
271 vim_open_clipboard(void)
272 {
273     int delay = 10;
274 
275     while (!OpenClipboard(NULL))
276     {
277 	if (delay > 500)
278 	    return FALSE;  /* waited too long, give up */
279 	Sleep(delay);
280 	delay *= 2;	/* wait for 10, 20, 40, 80, etc. msec */
281     }
282     return TRUE;
283 }
284 
285 /*
286  * Get the current selection and put it in the clipboard register.
287  *
288  * NOTE: Must use GlobalLock/Unlock here to ensure Win32s compatibility.
289  * On NT/W95 the clipboard data is a fixed global memory object and
290  * so its handle = its pointer.
291  * On Win32s, however, co-operation with the Win16 system means that
292  * the clipboard data is moveable and its handle is not a pointer at all,
293  * so we can't just cast the return value of GetClipboardData to (char_u*).
294  * <VN>
295  */
296     void
297 clip_mch_request_selection(VimClipboard *cbd)
298 {
299     VimClipType_t	metadata = { -1, -1, -1, -1 };
300     HGLOBAL		hMem = NULL;
301     char_u		*str = NULL;
302 #if defined(WIN3264)
303     char_u		*to_free = NULL;
304 #endif
305     HGLOBAL		rawh = NULL;
306     int			str_size = 0;
307     int			maxlen;
308     size_t		n;
309 
310     /*
311      * Don't pass GetActiveWindow() as an argument to OpenClipboard() because
312      * then we can't paste back into the same window for some reason - webb.
313      */
314     if (!vim_open_clipboard())
315 	return;
316 
317     /* Check for vim's own clipboard format first.  This only gets the type of
318      * the data, still need to use CF_UNICODETEXT or CF_TEXT for the text. */
319     if (IsClipboardFormatAvailable(cbd->format))
320     {
321 	VimClipType_t	*meta_p;
322 	HGLOBAL		meta_h;
323 
324 	/* We have metadata on the clipboard; try to get it. */
325 	if ((meta_h = GetClipboardData(cbd->format)) != NULL
326 		&& (meta_p = (VimClipType_t *)GlobalLock(meta_h)) != NULL)
327 	{
328 	    /* The size of "VimClipType_t" changed, "rawlen" was added later.
329 	     * Only copy what is available for backwards compatibility. */
330 	    n = sizeof(VimClipType_t);
331 	    if (GlobalSize(meta_h) < n)
332 		n = GlobalSize(meta_h);
333 	    memcpy(&metadata, meta_p, n);
334 	    GlobalUnlock(meta_h);
335 	}
336     }
337 
338     /* Check for Vim's raw clipboard format first.  This is used without
339      * conversion, but only if 'encoding' matches. */
340     if (IsClipboardFormatAvailable(cbd->format_raw)
341 				      && metadata.rawlen > (int)STRLEN(p_enc))
342     {
343 	/* We have raw data on the clipboard; try to get it. */
344 	if ((rawh = GetClipboardData(cbd->format_raw)) != NULL)
345 	{
346 	    char_u	*rawp;
347 
348 	    rawp = (char_u *)GlobalLock(rawh);
349 	    if (rawp != NULL && STRCMP(p_enc, rawp) == 0)
350 	    {
351 		n = STRLEN(p_enc) + 1;
352 		str = rawp + n;
353 		str_size = (int)(metadata.rawlen - n);
354 	    }
355 	    else
356 	    {
357 		GlobalUnlock(rawh);
358 		rawh = NULL;
359 	    }
360 	}
361     }
362     if (str == NULL)
363     {
364 #if defined(WIN3264)
365 	/* Try to get the clipboard in Unicode if it's not an empty string. */
366 	if (IsClipboardFormatAvailable(CF_UNICODETEXT) && metadata.ucslen != 0)
367 	{
368 	    HGLOBAL hMemW;
369 
370 	    if ((hMemW = GetClipboardData(CF_UNICODETEXT)) != NULL)
371 	    {
372 		WCHAR *hMemWstr = (WCHAR *)GlobalLock(hMemW);
373 
374 		/* Use the length of our metadata if possible, but limit it to
375 		 * the GlobalSize() for safety. */
376 		maxlen = (int)(GlobalSize(hMemW) / sizeof(WCHAR));
377 		if (metadata.ucslen >= 0)
378 		{
379 		    if (metadata.ucslen > maxlen)
380 			str_size = maxlen;
381 		    else
382 			str_size = metadata.ucslen;
383 		}
384 		else
385 		{
386 		    for (str_size = 0; str_size < maxlen; ++str_size)
387 			if (hMemWstr[str_size] == NUL)
388 			    break;
389 		}
390 		to_free = str = utf16_to_enc((short_u *)hMemWstr, &str_size);
391 		GlobalUnlock(hMemW);
392 	    }
393 	}
394 	else
395 #endif
396 	    /* Get the clipboard in the Active codepage. */
397 	    if (IsClipboardFormatAvailable(CF_TEXT))
398 	{
399 	    if ((hMem = GetClipboardData(CF_TEXT)) != NULL)
400 	    {
401 		str = (char_u *)GlobalLock(hMem);
402 
403 		/* The length is either what our metadata says or the strlen().
404 		 * But limit it to the GlobalSize() for safety. */
405 		maxlen = (int)GlobalSize(hMem);
406 		if (metadata.txtlen >= 0)
407 		{
408 		    if (metadata.txtlen > maxlen)
409 			str_size = maxlen;
410 		    else
411 			str_size = metadata.txtlen;
412 		}
413 		else
414 		{
415 		    for (str_size = 0; str_size < maxlen; ++str_size)
416 			if (str[str_size] == NUL)
417 			    break;
418 		}
419 
420 #if defined(WIN3264)
421 		/* The text is in the active codepage.  Convert to
422 		 * 'encoding', going through UTF-16. */
423 		acp_to_enc(str, str_size, &to_free, &maxlen);
424 		if (to_free != NULL)
425 		{
426 		    str_size = maxlen;
427 		    str = to_free;
428 		}
429 #endif
430 	    }
431 	}
432     }
433 
434     if (str != NULL && *str != NUL)
435     {
436 	char_u *temp_clipboard;
437 
438 	/* If the type is not known detect it. */
439 	if (metadata.type == -1)
440 	    metadata.type = MAUTO;
441 
442 	/* Translate <CR><NL> into <NL>. */
443 	temp_clipboard = crnl_to_nl(str, &str_size);
444 	if (temp_clipboard != NULL)
445 	{
446 	    clip_yank_selection(metadata.type, temp_clipboard, str_size, cbd);
447 	    vim_free(temp_clipboard);
448 	}
449     }
450 
451     /* unlock the global object */
452     if (hMem != NULL)
453 	GlobalUnlock(hMem);
454     if (rawh != NULL)
455 	GlobalUnlock(rawh);
456     CloseClipboard();
457 #if defined(WIN3264)
458     vim_free(to_free);
459 #endif
460 }
461 
462 /*
463  * Send the current selection to the clipboard.
464  */
465     void
466 clip_mch_set_selection(VimClipboard *cbd)
467 {
468     char_u		*str = NULL;
469     VimClipType_t	metadata;
470     long_u		txtlen;
471     HGLOBAL		hMemRaw = NULL;
472     HGLOBAL		hMem = NULL;
473     HGLOBAL		hMemVim = NULL;
474 # if defined(WIN3264)
475     HGLOBAL		hMemW = NULL;
476 # endif
477 
478     /* If the '*' register isn't already filled in, fill it in now */
479     cbd->owned = TRUE;
480     clip_get_selection(cbd);
481     cbd->owned = FALSE;
482 
483     /* Get the text to be put on the clipboard, with CR-LF. */
484     metadata.type = clip_convert_selection(&str, &txtlen, cbd);
485     if (metadata.type < 0)
486 	return;
487     metadata.txtlen = (int)txtlen;
488     metadata.ucslen = 0;
489     metadata.rawlen = 0;
490 
491     /* Always set the raw bytes: 'encoding', NUL and the text.  This is used
492      * when copy/paste from/to Vim with the same 'encoding', so that illegal
493      * bytes can also be copied and no conversion is needed. */
494     {
495 	LPSTR lpszMemRaw;
496 
497 	metadata.rawlen = (int)(txtlen + STRLEN(p_enc) + 1);
498 	hMemRaw = (LPSTR)GlobalAlloc(GMEM_MOVEABLE | GMEM_DDESHARE,
499 							 metadata.rawlen + 1);
500 	lpszMemRaw = (LPSTR)GlobalLock(hMemRaw);
501 	if (lpszMemRaw != NULL)
502 	{
503 	    STRCPY(lpszMemRaw, p_enc);
504 	    memcpy(lpszMemRaw + STRLEN(p_enc) + 1, str, txtlen + 1);
505 	    GlobalUnlock(hMemRaw);
506 	}
507 	else
508 	    metadata.rawlen = 0;
509     }
510 
511 # if defined(WIN3264)
512     {
513 	WCHAR		*out;
514 	int		len = metadata.txtlen;
515 
516 	/* Convert the text to UTF-16. This is put on the clipboard as
517 	 * CF_UNICODETEXT. */
518 	out = (WCHAR *)enc_to_utf16(str, &len);
519 	if (out != NULL)
520 	{
521 	    WCHAR *lpszMemW;
522 
523 	    /* Convert the text for CF_TEXT to Active codepage. Otherwise it's
524 	     * p_enc, which has no relation to the Active codepage. */
525 	    metadata.txtlen = WideCharToMultiByte(GetACP(), 0, out, len,
526 							       NULL, 0, 0, 0);
527 	    vim_free(str);
528 	    str = (char_u *)alloc((unsigned)(metadata.txtlen == 0 ? 1
529 							  : metadata.txtlen));
530 	    if (str == NULL)
531 	    {
532 		vim_free(out);
533 		return;		/* out of memory */
534 	    }
535 	    WideCharToMultiByte(GetACP(), 0, out, len,
536 					   (LPSTR)str, metadata.txtlen, 0, 0);
537 
538 	    /* Allocate memory for the UTF-16 text, add one NUL word to
539 	     * terminate the string. */
540 	    hMemW = (LPSTR)GlobalAlloc(GMEM_MOVEABLE | GMEM_DDESHARE,
541 						   (len + 1) * sizeof(WCHAR));
542 	    lpszMemW = (WCHAR *)GlobalLock(hMemW);
543 	    if (lpszMemW != NULL)
544 	    {
545 		memcpy(lpszMemW, out, len * sizeof(WCHAR));
546 		lpszMemW[len] = NUL;
547 		GlobalUnlock(hMemW);
548 	    }
549 	    vim_free(out);
550 	    metadata.ucslen = len;
551 	}
552     }
553 # endif
554 
555     /* Allocate memory for the text, add one NUL byte to terminate the string.
556      */
557     hMem = GlobalAlloc(GMEM_MOVEABLE | GMEM_DDESHARE, metadata.txtlen + 1);
558     {
559 	LPSTR lpszMem = (LPSTR)GlobalLock(hMem);
560 
561 	if (lpszMem)
562 	{
563 	    vim_strncpy((char_u *)lpszMem, str, metadata.txtlen);
564 	    GlobalUnlock(hMem);
565 	}
566     }
567 
568     /* Set up metadata: */
569     {
570 	VimClipType_t *lpszMemVim = NULL;
571 
572 	hMemVim = GlobalAlloc(GMEM_MOVEABLE|GMEM_DDESHARE,
573 						       sizeof(VimClipType_t));
574 	lpszMemVim = (VimClipType_t *)GlobalLock(hMemVim);
575 	memcpy(lpszMemVim, &metadata, sizeof(metadata));
576 	GlobalUnlock(hMemVim);
577     }
578 
579     /*
580      * Open the clipboard, clear it and put our text on it.
581      * Always set our Vim format.  Put Unicode and plain text on it.
582      *
583      * Don't pass GetActiveWindow() as an argument to OpenClipboard()
584      * because then we can't paste back into the same window for some
585      * reason - webb.
586      */
587     if (vim_open_clipboard())
588     {
589 	if (EmptyClipboard())
590 	{
591 	    SetClipboardData(cbd->format, hMemVim);
592 	    hMemVim = 0;
593 # if defined(WIN3264)
594 	    if (hMemW != NULL)
595 	    {
596 		if (SetClipboardData(CF_UNICODETEXT, hMemW) != NULL)
597 		    hMemW = NULL;
598 	    }
599 # endif
600 	    /* Always use CF_TEXT.  On Win98 Notepad won't obtain the
601 	     * CF_UNICODETEXT text, only CF_TEXT. */
602 	    SetClipboardData(CF_TEXT, hMem);
603 	    hMem = 0;
604 	}
605 	CloseClipboard();
606     }
607 
608     vim_free(str);
609     /* Free any allocations we didn't give to the clipboard: */
610     if (hMemRaw)
611 	GlobalFree(hMemRaw);
612     if (hMem)
613 	GlobalFree(hMem);
614 # if defined(WIN3264)
615     if (hMemW)
616 	GlobalFree(hMemW);
617 # endif
618     if (hMemVim)
619 	GlobalFree(hMemVim);
620 }
621 
622 #endif /* FEAT_CLIPBOARD */
623 
624 /*
625  * Note: the following two functions are only guaranteed to work when using
626  * valid MS-Windows codepages or when iconv() is available.
627  */
628 
629 /*
630  * Convert "str" from 'encoding' to UTF-16.
631  * Input in "str" with length "*lenp".  When "lenp" is NULL, use strlen().
632  * Output is returned as an allocated string.  "*lenp" is set to the length of
633  * the result.  A trailing NUL is always added.
634  * Returns NULL when out of memory.
635  */
636     short_u *
637 enc_to_utf16(char_u *str, int *lenp)
638 {
639     vimconv_T	conv;
640     WCHAR	*ret;
641     char_u	*allocbuf = NULL;
642     int		len_loc;
643     int		length;
644 
645     if (lenp == NULL)
646     {
647 	len_loc = (int)STRLEN(str) + 1;
648 	lenp = &len_loc;
649     }
650 
651     if (enc_codepage > 0)
652     {
653 	/* We can do any CP### -> UTF-16 in one pass, and we can do it
654 	 * without iconv() (convert_* may need iconv). */
655 	MultiByteToWideChar_alloc(enc_codepage, 0, (LPCSTR)str, *lenp,
656 							       &ret, &length);
657     }
658     else
659     {
660 	/* Use "latin1" by default, we might be called before we have p_enc
661 	 * set up.  Convert to utf-8 first, works better with iconv().  Does
662 	 * nothing if 'encoding' is "utf-8". */
663 	conv.vc_type = CONV_NONE;
664 	if (convert_setup(&conv, p_enc ? p_enc : (char_u *)"latin1",
665 						   (char_u *)"utf-8") == FAIL)
666 	    return NULL;
667 	if (conv.vc_type != CONV_NONE)
668 	{
669 	    str = allocbuf = string_convert(&conv, str, lenp);
670 	    if (str == NULL)
671 		return NULL;
672 	}
673 	convert_setup(&conv, NULL, NULL);
674 
675 	length = utf8_to_utf16(str, *lenp, NULL, NULL);
676 	ret = (WCHAR *)alloc((unsigned)((length + 1) * sizeof(WCHAR)));
677 	if (ret != NULL)
678 	{
679 	    utf8_to_utf16(str, *lenp, (short_u *)ret, NULL);
680 	    ret[length] = 0;
681 	}
682 
683 	vim_free(allocbuf);
684     }
685 
686     *lenp = length;
687     return (short_u *)ret;
688 }
689 
690 /*
691  * Convert an UTF-16 string to 'encoding'.
692  * Input in "str" with length (counted in wide characters) "*lenp".  When
693  * "lenp" is NULL, use wcslen().
694  * Output is returned as an allocated string.  If "*lenp" is not NULL it is
695  * set to the length of the result.
696  * Returns NULL when out of memory.
697  */
698     char_u *
699 utf16_to_enc(short_u *str, int *lenp)
700 {
701     vimconv_T	conv;
702     char_u	*utf8_str = NULL, *enc_str = NULL;
703     int		len_loc;
704 
705     if (lenp == NULL)
706     {
707 	len_loc = (int)wcslen(str) + 1;
708 	lenp = &len_loc;
709     }
710 
711     if (enc_codepage > 0)
712     {
713 	/* We can do any UTF-16 -> CP### in one pass. */
714 	int length;
715 
716 	WideCharToMultiByte_alloc(enc_codepage, 0, str, *lenp,
717 					    (LPSTR *)&enc_str, &length, 0, 0);
718 	*lenp = length;
719 	return enc_str;
720     }
721 
722     /* Avoid allocating zero bytes, it generates an error message. */
723     utf8_str = alloc(utf16_to_utf8(str, *lenp == 0 ? 1 : *lenp, NULL));
724     if (utf8_str != NULL)
725     {
726 	*lenp = utf16_to_utf8(str, *lenp, utf8_str);
727 
728 	/* We might be called before we have p_enc set up. */
729 	conv.vc_type = CONV_NONE;
730 	convert_setup(&conv, (char_u *)"utf-8",
731 					    p_enc? p_enc: (char_u *)"latin1");
732 	if (conv.vc_type == CONV_NONE)
733 	{
734 	    /* p_enc is utf-8, so we're done. */
735 	    enc_str = utf8_str;
736 	}
737 	else
738 	{
739 	    enc_str = string_convert(&conv, utf8_str, lenp);
740 	    vim_free(utf8_str);
741 	}
742 
743 	convert_setup(&conv, NULL, NULL);
744     }
745 
746     return enc_str;
747 }
748 
749 #if defined(WIN3264) || defined(PROTO)
750 /*
751  * Convert from the active codepage to 'encoding'.
752  * Input is "str[str_size]".
753  * The result is in allocated memory: "out[outlen]".  With terminating NUL.
754  */
755     void
756 acp_to_enc(
757     char_u	*str,
758     int		str_size,
759     char_u	**out,
760     int		*outlen)
761 
762 {
763     LPWSTR	widestr;
764 
765     MultiByteToWideChar_alloc(GetACP(), 0, (LPCSTR)str, str_size,
766 							    &widestr, outlen);
767     if (widestr != NULL)
768     {
769 	++*outlen;	/* Include the 0 after the string */
770 	*out = utf16_to_enc((short_u *)widestr, outlen);
771 	vim_free(widestr);
772     }
773 }
774 
775 /*
776  * Convert from 'encoding' to the active codepage.
777  * Input is "str[str_size]".
778  * The result is in allocated memory: "out[outlen]".  With terminating NUL.
779  */
780     void
781 enc_to_acp(
782     char_u	*str,
783     int		str_size,
784     char_u	**out,
785     int		*outlen)
786 
787 {
788     LPWSTR	widestr;
789     int		len = str_size;
790 
791     widestr = (WCHAR *)enc_to_utf16(str, &len);
792     if (widestr != NULL)
793     {
794 	WideCharToMultiByte_alloc(GetACP(), 0, widestr, len,
795 						(LPSTR *)out, outlen, 0, 0);
796 	vim_free(widestr);
797     }
798 }
799 #endif
800