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

Chris Petsos chrispetsos at sch.gr
Fri Jun 1 20:03:09 UTC 2007


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
-------------- next part --------------
An HTML attachment was scrubbed...
URL: http://lists.squeakfoundation.org/pipermail/vm-dev/attachments/20070601/15685f9f/attachment.htm


More information about the Vm-dev mailing list