[Vm-dev] Unicode clipboard in Windows VM...

Andreas Raab andreas.raab at gmx.de
Fri Jun 1 21:04:32 UTC 2007


Hi Chris -

This looks good; one question though: Do you know whether the windows 
clipboard automatically provides the CF_UNICODETEXT -> CF_TEXT translation?

Cheers,
   - Andreas

Chris Petsos wrote:
>  
> 
> 
> ------------------------------------------------------------------------
> 
> Ok guys... this is my solution for unicode clipboard support in Windows 
> VM... It works fine... I can make some improvements in memory management 
> but it's ok for now...
>  
> 
> /****************************************************************************/
> /*                      
> Clipboard                                           */
> /****************************************************************************/
>  
> int clipboardSize(void)
> { HANDLE h, h2;
>   WCHAR *src;
>   unsigned char *csrc;
>   int len, bytesNeeded;
>  
>   // Do we have text in the clipboard?
>   if(!IsClipboardFormatAvailable(CF_TEXT))
>     return 0;
>   if(!OpenClipboard(stWindow))
>     return 0;
>  
>   // Get it in unicode format.
>   h = GetClipboardData(CF_UNICODETEXT);
>  
>   src = GlobalLock(h);
>  
>   // How many bytes do we want to store those unicode chars in UTF8 format?
>   bytesNeeded = WideCharToMultiByte( CP_UTF8, 0, src, -1,
>         NULL, 0, NULL, NULL );
>  
>   h2 = GlobalAlloc(GMEM_MOVEABLE | GMEM_DDESHARE, bytesNeeded);
>   csrc = GlobalLock(h2);
>  
>   // Convert Unicode text to UTF8.
>   WideCharToMultiByte( CP_UTF8, 0, src, -1,
>         csrc, bytesNeeded, NULL, NULL );
>  
>   // Consider CrLf as a 1-byte character.
>   len = bytesNeeded;
>   while(len--)
>     if(((*csrc == 13) && (csrc[1] == 10)))
>       {
>  bytesNeeded--;
>  csrc++;
>       }
>     else
>       {
>  csrc++;
>       } 
>  
> 
>   // Clipboard size is bytesNeeded excluding the terminating character.
>   len = bytesNeeded - 1;
>  
>   GlobalUnlock(h);
>   GlobalUnlock(h2);
>  
>   return len;
> }
>  
> 
> /* send the given string to the clipboard */
> int clipboardWriteFromAt(int count, int byteArrayIndex, int startIndex)
> { HANDLE h, h2;
>   unsigned char *src;
>   int wcharsNeeded, len;
>   WCHAR *out, *tmp;
>  
>   if(!OpenClipboard(stWindow))
>     return 0;
>  
>   // Get the pointer to the byte array.
>   src = (unsigned char *)byteArrayIndex + startIndex;
>  
>   // How many WCHARs do we need to store the UTF8 represented bytes 
>  >from Squeak?
>   wcharsNeeded = MultiByteToWideChar( CP_UTF8, 0, src,
>         count+1, NULL,  
>  0 );
>  
>   // If we have Cr only "returns" then we will need another character 
> for Lf.
>   len = wcharsNeeded * sizeof(WCHAR);
>   while(len--)
>     if ((*src++ == 13) && (*src != 10))
>       wcharsNeeded++; 
>  
>   // Point to start of byte aray.
>   src = (unsigned char *)byteArrayIndex + startIndex;
>  
>   // Allocate needed memory for wcharsNeeded WCHARs.
>   h = GlobalAlloc(GMEM_MOVEABLE | GMEM_DDESHARE, wcharsNeeded * 
> sizeof(WCHAR));
>   out = GlobalLock(h);
>  
>   // Convert them to Unicode UTF16.
>   MultiByteToWideChar( CP_UTF8, 0, src,
>         count+1, out,  
>  wcharsNeeded );
>  
>   // Allocate needed memory for intermediate buffer.
>   // OK, i could do some more work here in order to avoid a whole new 
> buffer just for
>   // fixing the CrLf thing, but it's ok for now...
>   h2 = GlobalAlloc(GMEM_MOVEABLE | GMEM_DDESHARE, wcharsNeeded * 
> sizeof(WCHAR));
>   tmp = GlobalLock(h2);
>  
>   // Add missing Lf characters...
>   len = wcharsNeeded;
>   while(len--)
>     if((*out == 13))
>       { /* special case: crlf translation */
>  *tmp = 13;
>  tmp++;
>  *tmp = 10;
>  tmp++;
>  out++;
>       }
>     else
>       { /* regular case: lookup translation */
>  *tmp = *out;
>  tmp++;
>  out++;
>       }
>  
>   EmptyClipboard();
>   GlobalUnlock(h);
>   GlobalUnlock(h2);
>  
>   // Send the Unicode text to the clipboard.
>   SetClipboardData(CF_UNICODETEXT, h2);
>  
>   *src=0;
>   *tmp=0;
>  
>   /* Note: After setting clipboard data,
>      the memory block previously allocated belongs to
>      the clipboard - not to the app. */
>   CloseClipboard();
>   return 1;
> }
>  
> 
> /* transfer the clipboard data into the given byte array */
> int clipboardReadIntoAt(int count, int byteArrayIndex, int startIndex)
> { HANDLE h, h2;
>   unsigned char *dst, *tmp;
>   WCHAR *src;
>   int tel,len, bytesNeeded;
>  
> 
>   if(!IsClipboardFormatAvailable(CF_TEXT)) /* check for format CF_TEXT */
>     return 0;
>  
>   if(!OpenClipboard(stWindow))
>     return 0;
>  
>   // Get clipboard data in Unicode format
>   h = GetClipboardData(CF_UNICODETEXT);
>   src = GlobalLock(h);
>  
>   // How many bytes do we want to store the Unicode chars to UTF8 
> representation?
>   bytesNeeded = WideCharToMultiByte( CP_UTF8, 0, src, -1,
>         tmp, 0, NULL, NULL ) + 1;
>  
>   h2 = GlobalAlloc(GMEM_MOVEABLE | GMEM_DDESHARE, bytesNeeded);
>   tmp = GlobalLock(h2);
>  
>   // Convert Unicode text to UTF8.
>   WideCharToMultiByte( CP_UTF8, 0, src, -1,
>         tmp, bytesNeeded, NULL, NULL);
>  
>   len = bytesNeeded;
>  
>   // Get the pointer to the byte array.
>   dst= (unsigned char *)byteArrayIndex + startIndex;
>  
>   while(len--)
>     if(((*tmp == 13) && (tmp[1] == 10)))
>       { /* RvL 17-04-1998
>            drop the line feed after a carriage return
>            but leave lone line feeds alone
>            may transfer less than 'len' bytes but who cares
>            i.e. if they use the clipboardSize there should
>            be no problem.*/
>  *dst = 13;
>  dst++;
>         tmp++;
>         tmp++;
>       }
>     else
>       { /* regular case: lookup translation */
>  *dst = *tmp;
>  dst++;
>  tmp++;
>       } 
>  
>   GlobalUnlock(h);
>   GlobalUnlock(h2);
>   CloseClipboard();
>   return bytesNeeded;
> }
>  
> The only thing is that in the image side you need a UTF8TextConverter 
> before sending text to the clipboard or getting from it...so, my unicode 
> clipboard interpreter has these methods...
>  
> fromSystemClipboard: aString
>  ^ aString convertFromWithConverter: (UTF8TextConverter new).
>  
> toSystemClipboard: aString
>  | result utfString |
> " aString isOctetString ifTrue: [^ aString asOctetString]."
>  utfString := aString convertToWithConverter: (UTF8TextConverter new).
>  result _ WriteStream on: (String new: utfString size).
>  utfString do: [:each | result nextPut: each].
>  ^ result contents.
>  
> I am pretty sure it will need some minor fixes...
> I'll post links to ready made builds of this version so others can try 
> it too, soon.
>  
> Any comments, suggestions, C-related fixes are most welcome...
>  
> Christos


More information about the Vm-dev mailing list