Конференция "WinAPI" » Ctrl+C - запрет ОС на копирование в буфер обмена [D7, WinXP]
 
  • allrussia (21.05.10 05:07) [0]
    перехватываю комбинацию в onkeydown контрола

    мне необходимо чтобы работала моя вставка в clipboard, а не системная

     if (ssCtrl in Shift) and (Key = Ord('C')) then
     begin
         Clipboard.Clear;
         MYPasteToClipBoard;
     end;



    такой код не фурычит

    в OnKeyUP  - работает - но нужно долго держать клавиши и отпускать в определенной последовательности, сначала 'С' затем Ctrl.

    С помощью таймера можно заставить работать но это блин смешно и криворуко.

    Существует ли корректный код для запрета CTRL+C (именно чтобы система не лезла в буфер)?
  • Leonid Troyanovsky © (21.05.10 07:31) [1]

    > allrussia   (21.05.10 05:07)  

    > перехватываю комбинацию в onkeydown контрола

    WM_COPY ?

    --
    Regards, LVT.
  • MKC © (21.05.10 09:34) [2]
    брось на форму edit
    положми в него текст потом
    Edit.Selettall.
    edit.copytoclipbord
    попробуй мож пойдет
  • MKC © (21.05.10 09:40) [3]
    тю ты чота я не о том :)
    если тебе нужно чтоб твои компоненты не реагировали на комбинацию клавишь, то key:=#0 в конце onkeydown
    ну а если не в твоем окне то только хук на систему вешать.
  • Riply © (21.05.10 13:21) [4]
    > [0] allrussia   (21.05.10 05:07)
    > перехватываю комбинацию в onkeydown контрола
    > мне необходимо чтобы работала моя вставка в clipboard, а не системная

    IMHO, достаточно перехватить две ф-ии: SetClipboardData, EmptyClipboard
    Во всяком случае, мне в похожей задачке этого хватило.
  • allrussia (21.05.10 16:25) [5]
    > Leonid Troyanovsky

    > WM_COPY ?


    Вы вопрос поняли? Мне нужно чтобы по нажатию Ctrl+C на любом контроле вистема не копировала содержимое в буфер обмена. (Это примерно то же самое что перехват Ctrl+Alt+Del, просто здесь библиотека не участвует) Как скопировать содержимое я знаю.

    MKC

    если тебе нужно чтоб твои компоненты не реагировали на комбинацию клавишь, то key:=#0 в конце onkeydown


    вы тоже особо не поняли видимо: #0 - Это тип Char, а не Word, во вторых - это все равно не поможет (сама система ОС Windows перехватывает CTRL+С, не делфи)

    Riply

    > IMHO, достаточно перехватить две ф-ии: SetClipboardData,
    >  EmptyClipboard
    > Во всяком случае, мне в похожей задачке этого хватило.


    Прекрасно - подскажите как или привдите рабочий пример

    достаточно будет нажать CTRL+C на TEdit или TMemo  и чтобы буфер обмена оказался пустым или с предыдущими данными
  • Riply © (21.05.10 16:42) [6]
    >  [5] allrussia   (21.05.10 16:25)
    > Riply
    > Прекрасно - подскажите как или привдите рабочий пример

    "Подсказать как" что ?
    Как перехватывать API ?
    Если да, то это хорошо расписано у Рихтера и даже с примерами :),
    а если нет, то что именно подсказать ?

    > достаточно будет нажать CTRL+C на TEdit или TMemo  
    > и чтобы буфер обмена оказался пустым или с предыдущими данными

    Эмн... а к чему эта фраза, да еще и выделенная ?
    Разве данные операции работают не через SetClipboardData, EmptyClipboard ?
  • han_malign (21.05.10 16:58) [7]

    > onkeydown
    > OnKeyUP

    ну - попробуй onkeypress до кучи
    if( key = ^c )then begin
      ...
      key: = #0;
    end;
  • allrussia (21.05.10 17:11) [8]

    > Эмн... а к чему эта фраза, да еще и выделенная ?
    > Разве данные операции работают не через SetClipboardData,
    >  EmptyClipboard ?


    спасибо, вот что удалось надыбать

    function NewMemoProc(wnd:HWND; uMsg:UINT; wParam:WPARAM; lParam:LPARAM):integer; stdcall;
    begin
    if (uMsg = WM_CUT) or (uMsg = WM_COPY) then uMsg := 0;
    result:=CallWindowProc(Pointer(GetWindowLong(wnd,GWL_USERDATA)),wnd,uMsg,wParam, lParam)
    end;

    procedure TForm1.FormCreate(Sender: TObject);
    begin
    SetWindowLong(Memo1.Handle,GWL_USERDATA,SetWindowLong(Memo1.Handle, GWL_WNDPROC, LPARAM(@NewMemoProc)))
    end;



    собственно вопрос:

    1. как сделать чтобы применялось для всех edit-, memo-, text-контролов?
    2. корректен ли этот код и можно ли избежать такой громоздкости?

    for i:= 0 to ComponentCount -1 do
    SetWindowLong(component[i].handle,GWL_USERDATA,SetWindowLong(component[i].handle , GWL_WNDPROC, LPARAM(@NewMemoProc)))
  • allrussia (21.05.10 17:22) [9]
    han_malign

    спасибо вариант хороший, но
    1 проблема: когда отпускаешь первым Ctrl начинают вводиться буквы  'C'

    2 придется русками везде  прописывать на всех контролах и ctrl +C и Ctrl+X (с отловом позиции курсора, а ведь есть еще ctrl+Ins и пр...) + проблема 1
  • Игорь Шевченко © (21.05.10 19:49) [10]
    тебе надо перехватывать WM_COPY.

    В древнем Китае желающим странного отрубали голову. Весьма эффективный метод, надо признать.
  • allrussia (21.05.10 19:54) [11]

    > Игорь Шевченко ©   (21.05.10 19:49) [10]
    >
    > тебе надо перехватывать WM_COPY.


    не тебе, а вам. спасибо за экскурс в историю

    а это что (21.05.10 17:11) [8],не перехват WM_COPY?
    Появились другие вопросы в [8] и [9].
  • Игорь Шевченко © (21.05.10 19:58) [12]
    allrussia   (21.05.10 19:54) [11]


    > не тебе, а вам


    а нам это нафиг не сдалось


    > корректен ли этот код и можно ли избежать такой громоздкости?


    Для решения тупой задачи вполне годится такой тупой код.

    Но гораздо проще надписать компоненты и в них заменять оконную процедуру на нужную (как это неоднократно демонстрируется в stdctrls.pas)
  • allrussia (21.05.10 20:04) [13]

    Игорь Шевченко
    > Для решения тупой задачи вполне годится такой тупой код.

    поясните, почему тупой... вы не пользуетесь CTRL+C,CTRL+V? :))

    в целом задача такова:
    корректное копирование русского текста в буфер при нажатии комбинации клавиш CTR+C, Ins в Vista, 7, 2008 из контролов Delphi, не поддерживающих юникод
  • Игорь Шевченко © (21.05.10 20:27) [14]
    allrussia   (21.05.10 20:04) [13]


    > в целом задача такова:
    > корректное копирование русского текста в буфер


    http://www.sql.ru/forum/actualthread.aspx?tid=244851
    http://www.delphikingdom.com/asp/viewitem.asp?catalogid=780

    тоже способ предлагают, без перехвата.
  • allrussia (21.05.10 20:32) [15]
    Игорь Шевченко

    > тоже способ предлагают, без перехвата.


    спасибо, но у меня оба эти линка постоянно открыты :) и не только эти, а еше как минимум 3 способа
    RUSClip - например ничего не дает и не обрабатывается
    вручную (например через попап меню) скопировать корректно текст не проблема

    основная проблема заключается в перехвате CTRL+C
  • Игорь Шевченко © (21.05.10 20:43) [16]
    allrussia   (21.05.10 20:32) [15]

    Проблема заключается в том, чтобы установить корректную кодовую страницу в Clipboard. Перехватывать кучу клавиатурных комбинаций - это не всегда и не совсем удобно.

    Можно конечно пробегаться по формам и переустанавливать оконные процедуры, но типов контролов много (кстати, сами формы (RTFS: Dialogs.TMessageForm) тоже могут быть скопированы по Ctrl+C, не только Edit-ы и их производные, и результаты копирования подчиняются тем же правилам кодовой страницы) и для каждого переопределять оконную процедуру, мягко говоря, не очень разумно.

    Если перехватывать, то лучше надписывать компоненты (можно по способу Geo http://www.interface.ru/home.asp?artId=16753)

    и в их обработчике WM_COPY, WM_CUT устанавливать нужную кодовую страницу.
  • Leonid Troyanovsky © (21.05.10 20:59) [17]

    > allrussia   (21.05.10 16:25) [5]

    > Вы вопрос поняли? Мне нужно чтобы по нажатию Ctrl+C на любом
    > контроле вистема не копировала содержимое в буфер обмена.
    >  (Это примерно то же самое что перехват Ctrl+Alt+Del, просто

    Вопрос мы поняли. Не надо - не копируй.
    Хотя, про любой - это, дейс-но, новость.

    Перехватом же Ctrl+Alt+Del мы и не заморачиваемся.

    --
    Regards, LVT.
  • allrussia (21.05.10 22:51) [18]
    Игорь Шевченко


    > Проблема заключается в том, чтобы установить корректную
    > кодовую страницу в Clipboard.


    Это я знаю и добиваюсь.

    Перехватывать кучу клавиатурных комбинаций - это не всегда и не совсем удобно.


    Неудобно. Но рука тянется к клавишам, а не ПКМ. Хочется нормальный русский текст по CTRL+C.


    > Если перехватывать, то лучше надписывать компоненты (можно
    > по способу Geo http://www.interface.ru/home.asp?artId=16753)
    >


    как "надписывание" поможет перехватить CTRL+С?

    вы можете показать хоть 1 рабочий пример, где происходит корректное копирование/вставка в/из Memo в/из буфер обмена с помощью системных комбинаций клавиш Ctrl,Shift,C,Ins?

    вот так?


    procedure TForm1.WndProc (var message: TMessage);
    begin
     if (message.Msg = WM_COPY) or (message.Msg = WM_CUT) then
       {????????}
     else
       inherited
    end;



    тишина
  • Игорь Шевченко © (21.05.10 23:16) [19]
    allrussia   (21.05.10 22:51) [18]


    > вы можете показать хоть 1 рабочий пример, где происходит
    > корректное копирование/вставка в/из Memo в/из буфер обмена
    > с помощью системных комбинаций клавиш Ctrl,Shift,C,Ins?


    Могу показать 1 пример:

     TForm1 = class(TForm)
       Edit1: TEdit;
       Memo1: TMemo;
     private
       FOldMemoWndProc: TWndMethod;
       FOldEditWndProc: TWndMethod;
       procedure MemoWndProc (var Message: TMessage);
       procedure EditWndProc (var Message: TMessage);
     end;

    var
     Form1: TForm1;

    implementation

    {$R *.dfm}

    procedure TForm1.FormCreate(Sender: TObject);
    begin
     FOldMemoWndProc := Memo1.WindowProc;
     Memo1.WindowProc := MemoWndProc;
     FOldEditWndProc := Edit1.WindowProc;
     Edit1.WindowProc := EditWndProc;
     Memo1.Lines.Text := 'Это русский текст';
    end;

    procedure TForm1.MemoWndProc(var Message: TMessage);
    var
     LKL: array [0..1023] of char;
    begin
     if Message.Msg = WM_COPY then
     begin
       GetKeyboardLayoutName(LKL);
       LoadKeyboardLayout('00000419',KLF_ACTIVATE);
     end;
     FOldMemoWndProc(Message);
     if Message.Msg = WM_COPY then
       LoadKeyboardLayout(LKL,KLF_ACTIVATE);
    end;

    procedure TForm1.EditWndProc(var Message: TMessage);
    var
     LKL: array [0..1023] of char;
    begin
     if Message.Msg = WM_COPY then
     begin
       GetKeyboardLayoutName(LKL);
       LoadKeyboardLayout('00000419',KLF_ACTIVATE);
     end;
     FOldEditWndProc(Message);
     if Message.Msg = WM_COPY then
       LoadKeyboardLayout(LKL,KLF_ACTIVATE);
    end;



    В случае надписанного же компонента в его обработчике сообщений
    WM_COPY/WM_CUT будет такая же операция мамбл-ванго, как в примере, вызов inherited для обработки сообщения родным контролом и восстановление раскладки.
  • Игорь Шевченко © (21.05.10 23:16) [20]
    копирование произоводится корректно, как при Ctrl+C, Ctrl+Ins там и при вызове из локального меню
  • allrussia (22.05.10 00:08) [21]
    Игорь Шевченко ©   (21.05.10 23:16) [20]

    копирование произоводится корректно, как при Ctrl+C, Ctrl+Ins там и при вызове из локального меню



    спасибо за пример - он безусловно пока самый рабочий. В принципе у меня он был немного в другом виде, но метод запомнить раскладку, сменить на русский и затем обратно я уже использовал.

    Я как раз ищу рабочий пример без смены раскладки.

    Во-вторых, вопрос к вам как к программисту: как поведет себя код при отсутствии русской раскладки?
    Я пробовал удалять раскладки и код работает, но все же, какие могут быть курьезы?

    И в-третьих, как же быть со вставкой? Основная проблема здесь:
    Открываем блокнот Windows. переключаем раскладку на русский. пишем текст. переключаем обратно на англ. копируем в буфер. вставляем в мемо в нашу программу (форма и мемо). результат: "?" и абракадабра...

    Здесь уже не моможет включение русской раскладки перед вставкой, т.к. русский текст был скопирован с некорректной кодовой страницей в Clipboard.
  • allrussia (22.05.10 00:25) [22]
    да, и еще вопрос, как это размножить на 100 мемо программно

    procedure TForm1.FormCreate(Sender: TObject);
    begin
    FOldMemoWndProc := Memo1.WindowProc;
    Memo1.WindowProc := MemoWndProc;
    FOldEditWndProc := Edit1.WindowProc;
    Edit1.WindowProc := EditWndProc;
    Memo1.Lines.Text := 'Это русский текст';
    end;

    procedure TForm1.MemoWndProc(var Message: TMessage);
    var
    LKL: array [0..1023] of char;
    begin
    if Message.Msg = WM_COPY then
    begin
      GetKeyboardLayoutName(LKL);
      LoadKeyboardLayout('00000419',KLF_ACTIVATE);
    end;
    FOldMemoWndProc(Message);
    if Message.Msg = WM_COPY then
      LoadKeyboardLayout(LKL,KLF_ACTIVATE);
    end;

  • Игорь Шевченко © (22.05.10 00:28) [23]
    allrussia   (22.05.10 00:08) [21]

    Мне, если честно, лень искать материалы по работе с Clipboard. Разумеется, переключение языка раскладки - это грубый (и не всегда полезный) метод. То, что при этом Clipboard устанавливает нужный формат - это побочный эффект от переключения, я уверен, что этого же эффекта можно добиться прямым путем.

    вот тут http://www.codeguru.com/cpp/w-p/clipboard/article.php/c3009
    есть неплохая программка, которая позволяет крутить данные в Clipboard под разным углом.

    Вот тут (http://msdn.microsoft.com/en-us/library/ms649013(VS.85).aspx
    ) есть описание, почему действует переключение клавиатуры:

    "The data is a handle to the locale identifier associated with text in the clipboard. When you close the clipboard, if it contains CF_TEXT data but no CF_LOCALE data, the system automatically sets the CF_LOCALE format to the current input language. You can use the CF_LOCALE format to associate a different locale with the clipboard text.
    An application that pastes text from the clipboard can retrieve this format to determine which character set was used to generate the text."

    Твори, выдумывай, пробуй.
  • Игорь Шевченко © (22.05.10 00:29) [24]
    allrussia   (22.05.10 00:25) [22]


    > да, и еще вопрос, как это размножить на 100 мемо программно


    Написать наследник от TMemo и использовать наследник. Заменять можно и в runtime
  • Германн © (22.05.10 01:07) [25]

    > Заменять можно и в runtime

    <offtop>
    Эх, если бы были механизмы/утилиты сделать подобное в designtime.
    </offtop>
  • allrussia (22.05.10 02:02) [26]
    спасибо, но со вставкой все равно непонятно в этом случае как быть

    Открываем блокнот Windows. переключаем раскладку на русский. пишем текст. переключаем обратно на англ. копируем в буфер. вставляем в мемо в нашу программу (форма и мемо). результат: "?" и абракадабра...

    здеть уже SetClipBoardData(CF_Locale,0419) не помогает..... ведь копирование было средствами ОС из чужой программы
  • allrussia (22.05.10 02:07) [27]
    вот тут http://www.codeguru.com/cpp/w-p/clipboard/article.php/c3009
    есть неплохая программка, которая позволяет крутить данные в Clipboard под разным углом.


    да а смысл? я сам могу "крутить" данные с помощью кнопок и мыши (вы сами мне давали функцию BufferToClipBoard)... Мне-то нужно перехватывать системную вставку-копирование..

    тем более прога под последними ОС не фурычит...
  • GrayFace © (22.05.10 22:20) [28]
    Вот как я это делел, без завязки на русский:
    procedure SendKeyboardLayout(Wnd, Msg:int; lParam:int=0; wParam:int=0);
    var a:HKL; s:string;
    begin
     SetLength(s,8);
     Win32Check(GetKeyboardLayoutName(ptr(s)));
     if s='00000409' then
     begin
       a:=ActivateKeyboardLayout(
            LoadKeyBoardLayout(ptr(intToHex(GetUserDefaultLangID,8)),0),0);
       if a=0 then RaiseLastOSError;
       SendMessage(Wnd, Msg, lParam, wParam);
       if ActivateKeyboardLayout(a,0)=0 then RaiseLastOSError;
     end else
       SendMessage(Wnd, Msg, lParam, wParam);
    end;

    procedure TForm1.Copy1Click(Sender: TObject);
    begin
     SendKeyboardLayout(GetFocus, WM_COPY);
    end;

    procedure TForm1.Cut1Click(Sender: TObject);
    begin
     SendKeyboardLayout(GetFocus, WM_CUT);
    end;

    procedure TForm1.Paste1Click(Sender: TObject);
    begin
     SendMessage(GetFocus, WM_PASTE, 0, 0);
    end;



    Это код для пунктов меню. Если кодировка английская, он устанавливает кодировку для языка пользователя.

    Перехват оконной процедуры у тебя нормальный, только не понятно, откуда ты нашел Handle у TComponent - он только у TWinControl.

    Игорь Шевченко ©   (21.05.10 19:58) [12]
    Но гораздо проще надписать компоненты и в них заменять оконную процедуру на нужную (как это неоднократно демонстрируется в stdctrls.pas)

    Не-не-не. Только лишняя морока. А этот метод еще можно продолжыть, отлавливая создание дочерних контролов.

    Игорь Шевченко ©   (22.05.10 0:28) [23]
    Спасибо, это интересно.
  • Игорь Шевченко © (23.05.10 00:39) [29]
    GrayFace ©   (22.05.10 22:20) [28]


    > Не-не-не. Только лишняя морока. А этот метод еще можно продолжыть,
    >  отлавливая создание дочерних контролов.


    Сказки не рассказывай, ладно ?


    > procedure SendKeyboardLayout(Wnd, Msg:int; lParam:int=0;
    >  wParam:int=0);


    Срочно читать Фаулера. Наизусть.

    Почему помогает смена языка клавиатуры - потому что ясным английским языком написано, что если при закрытии Clipboard locale не установлен, то он становится равным текущему языку ввода. Умные люди советуют передавать CF_UNICODETEXT и, соответственно, строку в Unicode (UCS-2), которая при вставке в Ansi-контрол должна быть преобразована в соотвествии с locale потока, а не языка ввода. А он по умолчанию равен языку локализации системы :)
  • allrussia (23.05.10 00:48) [30]
    GrayFace

    > Это код для пунктов меню.


    тема совсем не о пунктах меню.
    с пунктами меню проблем нет, причем приведены более удобные методы
    BufferToClipBoard

    кстати, вот это


    procedure TForm1.Paste1Click(Sender: TObject);
    begin
    SendMessage(GetFocus, WM_PASTE, 0, 0);
    end;



    у вас даже не сработает, если

    Открываем блокнот Windows. переключаем раскладку на русский. пишем текст. переключаем обратно на англ. копируем в буфер. вставляем в мемо в нашу программу (форма и мемо). результат: "?" и абракадабра...

    будет та же абракадабра... :))

    увы, ваш вариант не принимается :(

    просто с помощью меню никто не копирует это долго и нудно
    основная задача заменить операции стандартных комбинации клавиш на свои
  • Eraser © (23.05.10 00:51) [31]
    > allrussia

    не совсем вкурсе вопроса насчет раскладок и кодовых страниц клипбоарда, сам не сталкивался с этой проблемой в плане разработки, только слышал.

    но что если просто отслеживать буфер обмена (благо есть такие функции) и, в случае появления кривого, текста вручную подменять его, к примеру, на юникодовский вариант?
  • allrussia (23.05.10 01:23) [32]

    > и, в случае появления кривого, текста вручную подменять
    > его, к примеру, на юникодовский вариант?


    так для  этого и приведены ссылки в [14] И. Ш. и
    здесь А.P.: http://pda.delphimaster.net/?id=1271161706&n=0
  • Игорь Шевченко © (23.05.10 01:31) [33]
    Я сильно извиняюсь, а что, пользователей нельзя попросить вручную переключиться на русский язык перед копированием ? Мои пользователи и я научились.

    К тому же в последних версиях Delphi этой проблемы нет, так как юникод.

    Я к чему - конечно чистое искусство, это хорошо и красиво, но стоит ли овчинка выделки ? Если бы подобный механизм был бы действительно необходим и востребован, MS бы давно придумал нужный API для изменения поведения Clipboard в желаемую сторону.
  • Германн © (23.05.10 02:42) [34]

    > Я к чему - конечно чистое искусство, это хорошо и красиво,
    >  но стоит ли овчинка выделки ?

    +1
  • allrussia (23.05.10 18:10) [35]

    > Я сильно извиняюсь, а что, пользователей нельзя попросить
    > вручную переключиться на русский язык перед копированием
    > ? Мои пользователи и я научились.
    >


    Можно, просто у меня другой подход к созданию собственных программ. Просто я - админ, и мое кредо: для пользователей должно быть все прозрачно.
    Для меня - "кривые руки программиста" - это не "кривой" (пусть даже дебильный) для вас, программистов с большой буквы, код, а "кривая" работа программы, в данном случае, непродуманность в отношении буфера обмена Windows; в общих случаях, ка правило, это неюзабельный интерфейс, отсутствие горячих клавиш, многозадачности и многопоточности и пр.
    Меня красота кода не волнует. Поэтому и считаю, что хороший и талантливый программист, как правило, хреновый дизайнер и наоборот. Я из последних.
  • Дмитрий Белькевич (24.05.10 11:05) [36]

    > Просто я - админ, и мое кредо: для пользователей должно
    > быть все прозрачно.


    Переходи на Delphi 2009 и выше. На неюникодных версиях красивого решения, боюсь, нет.
  • QAZ (24.05.10 13:11) [37]

    >  непродуманность в отношении буфера обмена Windows


    > хороший и талантливый программист


    на самом деле все в буфере продумано,а вы видимо не такой талантливый, раз в этом сомневаетесь
    для начала стоит изучить первоисточники,типа msdn а не "самоучитель дельфи глава 7 TClipboard"

    так вот ,о чем это я
    1)чтобы "перехватить" Ctrl+с и тд нужно просто перерегистрировать данный хоткей в своей проге (невероятно ,правда?)
    2)буфер может хранить текст сразу в 3х кодировках дос,анси и уникод. Но! все почемуто используют тока одну (вот и зависимость от текущей клавы)
    что из этого следует...
    1)ловим нажатие хоткея в очереди главного окна
    2)смотрим какая кодировка в буфере и конвертируем в нужную или винда сделает это сама если в буфере установить нужный локаль(иначе возьмет текущую раскладку клавы)
    3)когда копируем из себя то,либо забиваем в буфер сразу в 3х кодировках, либо одну и в буфере установить нужный локаль(иначе возьмет текущую раскладку клавы)
    4)и естествено мы забиваем на всякие TClipboard ,а используем АПИ

    вот и вся теория...

    ps есть ищо варианты
  • QAZ (24.05.10 13:18) [38]

    > нужно просто перерегистрировать данный хоткей в своей проге

    правда придется еще чучуть доработать штоб работало во всей системе после етого ;)
  • allrussia (25.05.10 12:56) [39]
    Окончательный рабочий вариант


    var cl: string;
    ...

    procedure ClipboardCopy(const Text: String);
    var
    Len, wLen: Integer;
    hClip: THandle;
    pwStr: PWideChar;
    begin
    with Clipboard do
    begin
      Open;
      try
        if (Win32Platform = VER_PLATFORM_WIN32_NT) then
        begin
          Len := Length(Text) + 1;
          wLen := Len shl 1;
          hClip := GlobalAlloc(GMEM_MOVEABLE, wLen);
          try
            pwStr := PWideChar(GlobalLock(hClip));
            MultiByteToWideChar(CP_ACP, MB_PRECOMPOSED, PChar(Text), Len, pwStr, wLen);
            GlobalUnlock(hClip);
            SetAsHandle(CF_UNICODETEXT, hClip);
          except
            GlobalFree(hClip);
            raise;
          end;
        end else
          SetTextBuf(PChar(Text));
      finally
        Close;
      end;
    end;
    end;

    procedure ClipboardPaste(var Text: String);
    var
    Len, wLen: Integer;
    hClip: THandle;
    pwStr: PWideChar;
    begin
    Text := '';
    with Clipboard do
    try
      Open;
      if HasFormat(CF_TEXT) or HasFormat(CF_UNICODETEXT) then
      begin
        if (Win32Platform = VER_PLATFORM_WIN32_NT) then
        begin
          hClip := GetAsHandle(CF_UNICODETEXT);
          wlen := GlobalSize(hClip);
          pwStr := GlobalLock(hClip);
          try
            Len := (wLen div 2) - 1;
            SetLength(Text, Len);
            WideCharToMultiByte(CP_ACP, 0, pwStr, wlen, PChar(Text), Len, nil, nil);
          finally
            GlobalUnlock(hClip);
          end;
        end else
        begin
          hClip := GetAsHandle(CF_TEXT);
          Len := GlobalSize(hClip);
          SetLength(Text, Len);
          SetLength(Text, GetTextBuf(PChar(Text), Len));
        end;
      end;
    finally
      Close;
    end;
    end;

    function NewMemoProc(wnd:HWND; uMsg:UINT;
                        wParam:WPARAM; lParam:LPARAM):integer; stdcall;
    begin
     case uMsg of
     WM_COPY:
       begin
         uMsg:=0;
         ClipboardCopy(cl);
       end;
     WM_CUT:
       begin
         SendMessage(wnd,EM_REPLACESEL,1,cardinal(pchar('')));
         uMsg:=0;
         ClipboardCopy(cl);
       end;
     WM_PASTE:
       begin
         uMsg:=0;
         ClipboardPaste(cl);
       end;
     end;
     Result:= CallWindowProc(Pointer(GetWindowLong(wnd,GWL_USERDATA)),
                                              wnd,uMsg,wParam,lParam);
    end;

    form1.create
    procedure CreateOwnClipboard;
    var i: integer;
       h: hwnd;
       c: TComboBoxInfo;
    begin
    with form1 do
    for i :=0 to componentCount - 1 do
    begin
      if Components[i] is TEdit then
      begin
        h:= TEdit(Components[i]).Handle;
        SetWindowLong(h,GWL_USERDATA,SetWindowLong(h, GWL_WNDPROC, LPARAM(@NewMemoProc)))
      end;
      if Components[i] is TMemo then
      begin
        h:= TMemo(Components[i]).Handle;
        SetWindowLong(h,GWL_USERDATA,SetWindowLong(h, GWL_WNDPROC, LPARAM(@NewMemoProc)))
      end;
      if Components[i] is TComboBox then
      begin
        c.cbSize:= SizeOf(TCOMBOBOXINFO);
        GetComboBoxInfo(TComboBox(Components[i]).Handle,c);
        h:= c.hwndItem;
        SetWindowLong(h,GWL_USERDATA,SetWindowLong(h, GWL_WNDPROC, LPARAM(@NewMemoProc)))
      end;
    end;
    end;

    MemoKeyDown
    begin
     with TFlat(Sender) do
     begin
       if not ReadOnly then
       if ((Key = ord('V'))  and (ssCtrl  in Shift)) or
          ((Key = VK_INSERT) and (ssShift in Shift)) then
       begin
         SelText:=cl;
       end;
       if ((Key = ord('C'))   and (ssCtrl  in Shift)) or
          ((Key = VK_INSERT)  and (ssCtrl  in Shift)) or
          ((Key = ord('X'))   and (ssCtrl  in Shift)) or
          ((Key = VK_DELETE)  and (ssShift in Shift)) then
          cl:= SelText;
     end;
    end;

    так же по аналогии с EditOnKeyDown и ComboboxOnKeyDown

  • GrayFace © (26.05.10 10:34) [40]
    > allrussia   (23.05.10 00:48) [30]
    Мой код зато не завязан на русский язык. Твой финальный, вроде, тоже.
  • GrayFace © (27.05.10 13:54) [41]
    Игорь Шевченко ©   (23.05.10 0:39) [29]
    Сказки не рассказывай, ладно ?

    И так не рассказываю.

    Игорь Шевченко ©   (23.05.10 0:39) [29]
    Срочно читать Фаулера. Наизусть.

    Название функции плохое? А есть ссылка на Фаулера?
    Мартин Фаулер, Рефакторинг. Улучшение существующего кода?
  • имя (19.04.12 17:00) [42]
    Удалено модератором
  • имя (19.04.12 17:00) [43]
    Удалено модератором
  • имя (19.04.12 17:00) [44]
    Удалено модератором
  • имя (19.04.12 17:00) [45]
    Удалено модератором
  • имя (13.04.14 12:49) [46]
    Удалено модератором
 
Конференция "WinAPI" » Ctrl+C - запрет ОС на копирование в буфер обмена [D7, WinXP]
Есть новые Нет новых   [118461   +15][b:0][p:0.006]