Collectives™ on Stack Overflow
Find centralized, trusted content and collaborate around the technologies you use most.
Learn more about Collectives
Teams
Q&A for work
Connect and share knowledge within a single location that is structured and easy to search.
Learn more about Teams
Win7-8 OS, Russian locale (and format) set in OS Region settings, Delphi 7.
The problem is that it works only when I switch (shift+alt) to Russian
keyboard layout
when copying. Otherwise it will be pasted as
"Ïðèâåò!"
instead of
"Привет!"
.
How can I fix that?
I think that I need somehow convert text to Unicode and call Unicode clipboard copy function from WinAPI? But how to do that?
–
–
Convert the text to Unicode by whatever means you see fit. In Delphi 7 that typically involves using
WideString
.
Once you have the text encoded as UTF-16, for instance in a
WideString
, you need to call
SetClipboardData
using the
CF_UNICODETEXT
clipboard format. This is wrapped by Delphi as the
SetAsHandle
method of the global
Clipboard
object.
I've not tested it, but this function should set you on the way:
Windows, Clipbrd;
procedure SetClipboardText(const Text: WideString);
Count: Integer;
Handle: HGLOBAL;
Ptr: Pointer;
begin
Count := (Length(Text)+1)*SizeOf(WideChar);
Handle := GlobalAlloc(GMEM_MOVEABLE, Count);
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;
–
–
–
Thank you very much, by thees means you can also convert Encoding in the clipboard if you catch WM_CLIPBOARDUPDATE message - very usefull with old versions of delphi, e.g. for Russian Language.
Here is a full working code:
(N.B. This buffer listening tecnique will only work for Windows Vista and newer OS, that's why I use dynamic WinAPI linking, see this article -
http://delphidabbler.com/articles?article=9
)
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()));
_isClipboardChangeRequired := true;
procedure TDM.DataModuleDestroy(Sender: TObject);
begin
if Assigned(_removeClipboardFormatListener) then
_removeClipboardFormatListener(Application.Handle);
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;
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;
if (Msg.message = WM_CLIPBOARDUPDATE) AND (Clipboard.HasFormat(CF_UNICODETEXT)) then
if NOT _isClipboardChangeRequired then
begin
_isClipboardChangeRequired := true;
Exit;
begin
attemptCount := 1;
isClipboardOpened := false;
repeat
Clipboard.Open();
isClipboardOpened := true;
except
if (attemptCount >= MAX_CLIPBOARD_OPEN_ATTEMPTS) then
begin
OutputDebugString(PChar('Внимание: Нет доступа к буферу обмена - невозможно изменить его кодировку!'));
Exit;
inc(attemptCount);
until isClipboardOpened;
clipHandle := Clipboard.GetAsHandle(CF_UNICODETEXT);
dataPtr := GlobalLock(clipHandle);
if (dataPtr <> nil) then
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);
Clipboard.Close();
Thanks for contributing an answer to Stack Overflow!
-
Please be sure to
answer the question
. Provide details and share your research!
But
avoid
…
-
Asking for help, clarification, or responding to other answers.
-
Making statements based on opinion; back them up with references or personal experience.
To learn more, see our
tips on writing great answers
.