Delphi 7: How to copy non-Latin text to the clipboard? (convert to unicode?)

I have code like this to copy some text to the clipboard.

uses Clipbrd;

var
  text: string;
begin
  text := 'Some non-latin text, for example Russian: !'

  Clipboard.AsText := text;
end;

Win7-8 OS, Russian locale (and format) installed in the OS area settings, Delphi 7.

The problem is that it only works when switching (shift + alt) to the Russian keyboard layout when copying. Otherwise, it will be inserted as "Ïðèâåò!"instead "!".

How can i fix this?

I think I need to somehow convert the text to Unicode and call the copy function of the Unicode clipboard from WinAPI? But how to do that?

+3
source share
2 answers

, . Delphi 7, WideString.

, UTF-16, , WideString, SetClipboardData, CF_UNICODETEXT. Delphi SetAsHandle Clipboard.

, :

uses
  Windows, Clipbrd;

procedure SetClipboardText(const Text: WideString);
var
  Count: Integer;
  Handle: HGLOBAL;
  Ptr: Pointer;
begin
  Count := (Length(Text)+1)*SizeOf(WideChar);
  Handle := GlobalAlloc(GMEM_MOVEABLE, Count);
  Try
    Win32Check(Handle<>0);
    Ptr := GlobalLock(Handle);
    Win32Check(Assigned(Ptr));
    Move(PWideChar(Text)^, Ptr^, Count);
    GlobalUnlock(Handle);
    Clipboard.SetAsHandle(CF_UNICODETEXT, Handle);
  Except
    GlobalFree(Handle);
    raise;
  End;
end;
+2

, , , WM_CLIPBOARDUPDATE - delphi, . . :

(N.B. tecnique Windows Vista , WinAPI, . -  http://delphidabbler.com/articles?article=9)

type
  TAddOrRemoveClipboardFormatListener = function (hWndNewViewer : HWND) : BOOL; stdcall;

var _isClipboardChangeRequired : boolean;
var _addClipboardFormatListener, _removeClipboardFormatListener : TAddOrRemoveClipboardFormatListener;

procedure TDM.DataModuleCreate(Sender: TObject);
begin
<...>
  _addClipboardFormatListener := GetProcAddress(GetModuleHandle('user32.dll'), 'AddClipboardFormatListener');
  _removeClipboardFormatListener := GetProcAddress(GetModuleHandle('user32.dll'), 'RemoveClipboardFormatListener');

  if (Assigned(_addClipboardFormatListener) AND NOT _addClipboardFormatListener(Application.Handle)) then
    begin
      _isClipboardChangeRequired := false;
      ShowMessage('      !        !' +
        sLineBreak + '  (' + IntToStr(GetLastError()) + '): ' + SysErrorMessage(GetLastError()));
    //      WriteLog([ssWarn], ClassName, '      !        !' +
    //      sLineBreak + '  (' + IntToStr(GetLastError()) + '): ' + SysErrorMessage(GetLastError()));
    end
    else
        _isClipboardChangeRequired := true;
<...>
end;

procedure TDM.DataModuleDestroy(Sender: TObject);
begin
    if Assigned(_removeClipboardFormatListener) then
    _removeClipboardFormatListener(Application.Handle);
end;

procedure TDM.ApplicationEvents_ClipboardChangeMessage(var Msg: tagMSG; var Handled: Boolean);
const
    // WM_CLIPBOARDUPDATE is not defined in the Messages unit of all supported
  // versions of Delphi, so we defined it here for safety.
  // ( : http://delphidabbler.com/articles?article=9)
  WM_CLIPBOARDUPDATE = $031D;
  MAX_CLIPBOARD_OPEN_ATTEMPTS = 3;
var
    textBuf : array[0..512] of WideChar;
  clipHandle : THandle;
  dataPtr: Pointer;
  dataSize : integer;
  str : string;
  attemptCount : integer;
  isClipboardOpened : boolean;
begin
  //        ,     
    if (NOT Assigned(_addClipboardFormatListener)) then
    begin
        ApplicationEvents_ClipboardChange.OnMessage := nil;
      Exit;
    end;
  if (Msg.message = WM_CLIPBOARDUPDATE) AND (Clipboard.HasFormat(CF_UNICODETEXT)) then
    if NOT _isClipboardChangeRequired then
        begin
            _isClipboardChangeRequired := true;
        Exit;
      end
    else
      begin
        attemptCount := 1;
        isClipboardOpened := false;
        repeat
          try
            Clipboard.Open();
            isClipboardOpened := true;
          except
            if (attemptCount >= MAX_CLIPBOARD_OPEN_ATTEMPTS) then
              begin
                OutputDebugString(PChar(':      -    !'));
                Exit;
              end
            else
              inc(attemptCount);
          end;
        until isClipboardOpened;
        clipHandle := Clipboard.GetAsHandle(CF_UNICODETEXT);
        dataPtr := GlobalLock(clipHandle);
        if (dataPtr <> nil) then
          try
            dataSize := GlobalSize(clipHandle);
            ZeroMemory(@textBuf, sizeof(textBuf));
            CopyMemory(@textBuf, dataPtr, dataSize);
            SetString(str, textBuf, dataSize);
            str := Trim(str);
            Clipboard.AsText := str;
            _isClipboardChangeRequired := false;
            OutputDebugString(PChar('Clipboard encoding converted!'));
          finally
            GlobalUnlock(clipHandle);
          end;
        Clipboard.Close();
      end;
end;
0

All Articles