| 
| 
 | Вопрос # 2 485/ вопрос открыт / | 
 |  Доброго времени суток, уважаемые эксперты!Помогите, пожалуйста, с "переводом" данной функции под Delphi 2009. Пробовал по-разному менять преобразование строковых типов, пересчёт длины через SizeOf - так и не получилось, в буфере обмена кракозябры всё время.
 P.S. Использование модуля Clipbrd не предлагать - у него есть проблемы, потому и намеренно отказался от него. Аналогичную функцию для получения текста из буфера адаптировать под D2009 удалось.
 Приложение:Переключить в обычный режим function SetClipboardText(Wnd: HWND; Value: string): Boolean;var  hData: HGlobal;  pData: pointer;  Len: integer;begin  Result := True;  if OpenClipboard(Wnd) then  begin    try      Len := Length(Value) + 1;      hData := GlobalAlloc(GMEM_MOVEABLE or GMEM_DDESHARE, Len);      try        pData := GlobalLock(hData);        try          Move(PChar(Value)^, pData^, Len);          EmptyClipboard;          SetClipboardData(CF_Text, hData);        finally          GlobalUnlock(hData);        end;      except        GlobalFree(hData);        raise      end;    finally      CloseClipboard;    end;  end  else    Result := False;end;
|  |   Вопрос задал: Sunshine (статус: Посетитель)Вопрос отправлен: 6 марта 2009, 09:48
 Состояние вопроса: открыт, ответов: 0.
 |  
 Мини-форум вопросаВсего сообщений: 21; последнее сообщение — 6 марта 2009, 16:20; участников в обсуждении: 2. Страницы: [1] [2] [Следующая »]  
|   | Вадим К (статус: Академик), 6 марта 2009, 11:37 [#1]:Нравиться мне это "функция имеет ошибку, не предлагать". Я склонен полагать, что то, как Вы используете эту функцию имеет ошибку  Дальше, сколько писать, что sizeof для строки в случае юникода надо очень аккуратно применять. ведь теперь один символ - это два байта. Но не только это. наиболее правильно и совместимо будет запись вида
 length(s)*sizeof(char) - это будет выдавать длину строки в байтах для любой делфи.
 Галочка "подтверждения прочтения" - вселенское зло. |  
|   | Вадим К (статус: Академик), 6 марта 2009, 11:37 [#2]:неправильно добавляет только русский текст, или с английским также есть проблемы? Галочка "подтверждения прочтения" - вселенское зло. |  
|   | Sunshine (статус: Посетитель), 6 марта 2009, 11:42 [#3]:Вадим, вопрос не в проблемах модуля Clipbrd, а в том, как заставить эту функцию корректно рботать на D2009. Если интересно - при активной работе с буфером постоянно выскакивает "Cannot open clipboard". Практически через раз. В инете подобная проблема известна, но решения кроме try..expert никто не знает. А это решение не подходит, т.к. работа программа кардинально из-за этого нарушается. Та функция получения текста, что я нашёл, работает безотказно. Так что проблема именно в модуле. <quote>Дальше, сколько писать, что sizeof для строки в случае юникода надо очень аккуратно применять. ведь теперь один символ - это два байта. Но не только это. наиболее правильно и совместимо будет запись вида
 length(s)*sizeof(char) - это будет выдавать длину строки в байтах для любой делфи. </quote>
 Я вообще-то в вопросе написал, что экспериментировал с разными вариантами. И Len*SizeOf(Value[1]) тоже пробовал, поверьте.
 <quote>неправильно добавляет только русский текст, или с английским также есть проблемы? </quote>
 Проблемы с любыми буквами, и даже с цифрами.
 |  
|   | Вадим К (статус: Академик), 6 марта 2009, 11:54 [#4]:Если проблемы с любыми буквами - значит неверно копируются данные в буфер - то есть, указатель левый, вот и попадает мусор. 
 Сколько использовал Clipbrd - никогда не видел с ним проблем. Всегда хорошо работает. Правда предполагаю, что если в системе есть программы, которые перехватывают работу с буфером (например, главный вредитель для всех программистов - пунтосвитчер), то вполне возможны разнообразные глюки.
 
 Поехали дальше. Как минимум одну серьезную ошибку в коде я вижу. Когда выделяется буфер под строку, там выделяется на один байт больше чем длина. вроде норм, но! длина строки в два раза больше на самом деле... и так как она юникодная, надо как минимум два байта в конец добавлять - то есть Вы выделяете память только на пол строки на самом деле, но и копируете туда пол строки. А так как она юникодная, неведомо какой будет конец у неё.
 И ещё, последний символ (для юникода - два последних байта) надо в обязательном порядке ЗАНУЛИТЬ! Иначе бедная винда не будет знать, где конец строки....
 Начните с этого, а там увидим.
 Галочка "подтверждения прочтения" - вселенское зло. |  
|   | Sunshine (статус: Посетитель), 6 марта 2009, 12:07 [#5]:function SetClipboardText(Wnd: HWND; Value: string): Boolean; var
 hData: HGlobal;
 pData: pointer;
 Len: integer;
 begin
 Result := True;
 if OpenClipboard(Wnd) then
 begin
 try
 Len := Length(Value) + 1;
 //showmessage(inttostr(Len*SizeOf(Char)));
 hData := GlobalAlloc(GMEM_MOVEABLE or GMEM_DDESHARE, Len*SizeOf(Char));
 try
 pData := GlobalLock(hData);
 try
 Move(PChar(Value)^, pData^, Len*SizeOf(Char));
 EmptyClipboard;
 SetClipboardData(CF_Text, hData);
 finally
 GlobalUnlock(hData);
 end;
 except
 GlobalFree(hData);
 raise
 end;
 finally
 CloseClipboard;
 end;
 end
 else
 Result := False;
 end;
 
 SetClipboardText(Handle,'Hello, world!'+#0);
 
 Кракозябров нет, но в буфер помещается только первый символ строки (в данном случае "H").
 |  
|   | Вадим К (статус: Академик), 6 марта 2009, 12:24 [#6]:Во первых, зануления я не увидел. Я увидел только жалкую попытку сделать обходной маневр. Если так и в коде пишете, то я не удивляюсь, что то работает, то нет. Во вторых, Len*SizeOf(Char) можно выделить в отдельную переменную.
 В третих, возможно копирование мусора.  Это связано с первым пунктом. Что бы не мучиться с занулениме последнего символа, сделаейте просто обнуление всего массива. GlobalAlloc вроде имеет флаг, когда данные будут занулены автоматом, поищите.
 и на последок, а кто сказал, что PChar(s)^ даст указатель на строку? Никто и не обещал.
 должно работать что то в стиле (@s[1])^
 Галочка "подтверждения прочтения" - вселенское зло. |  
|   | Sunshine (статус: Посетитель), 6 марта 2009, 12:34 [#7]:1 - с этой целью единица к длине и прибавляется, я полагаю, чтобы в конце был нулевой символ. 2 - сейчас это не принципиально. Когда будет работать, тогда можно будет сделать оптимизацию.
 3 - да, есть такой флаг.
 4 - никто не обещал, но обычно так и бывает.
 Тем не менее:
 
 function SetClipboardText(Wnd: HWND; Value: string): Boolean;
 var
 hData: HGlobal;
 pData: pointer;
 Len,M: integer;
 begin
 Result := True;
 if OpenClipboard(Wnd) then
 begin
 try
 Len := Length(Value) + 1;
 M:=Len*SizeOf(Char);
 hData := GlobalAlloc(GMEM_MOVEABLE or GMEM_DDESHARE or GMEM_ZEROINIT, M);
 try
 pData := GlobalLock(hData);
 try
 Move((@Value[1])^, pData^, M);
 EmptyClipboard;
 SetClipboardData(CF_Text, hData);
 finally
 GlobalUnlock(hData);
 end;
 except
 GlobalFree(hData);
 raise
 end;
 finally
 CloseClipboard;
 end;
 end
 else
 Result := False;
 end;
 
 Снова копируется только первый символ. Куда деваются остальные - неясно.
 |  
|   | Вадим К (статус: Академик), 6 марта 2009, 12:50 [#8]:как минимум я бы написал так Len := Length(Value);
 M:=Len*SizeOf(Char);
 hData := GlobalAlloc(GMEM_MOVEABLE or GMEM_DDESHARE or GMEM_ZEROINIT, M + 2);
 
 Именно так. И не следует к строке добавлять #0.
 А теперь об отладке. Установите точку останова на EmptyClipboard;
 и во время комирования посмотрите, что в  pData^
 Если всё нормально, то должны увидеть свою строку, только через один будут идти нули (если латинские символы).
 Попробуйте добавить в буфер строку с только русскими символами.
 Кажеться, я знаю, в чем проблема
   Галочка "подтверждения прочтения" - вселенское зло. |  
|   | Sunshine (статус: Посетитель), 6 марта 2009, 13:19 [#9]:Это странно, но значения у pData^ нет. Сначала его нельзя было посмотреть по причине включенной оптимизации, а после её отключения pData^ = (no value). Сама pData некоторый адрес всё же  содержит. |  
|   | Вадим К (статус: Академик), 6 марта 2009, 13:31 [#10]:после выключения оптимизации надо сделать полную перекомпиляцию (build all). Содержимое не отображает, так как не знает, как.
 Если добавить эту переменную в Watch list, то там можно выставить Memory Dump - вот там и будет видно
 Галочка "подтверждения прочтения" - вселенское зло. |  
|   | Sunshine (статус: Посетитель), 6 марта 2009, 13:45 [#11]:Показывает просто " 'Hello' " без нулей в середине. |  
|   | Вадим К (статус: Академик), 6 марта 2009, 14:01 [#12]:Значит либо строка не юникодная, либо смотрите не дамп памяти. Галочка "подтверждения прочтения" - вселенское зло. |  
|   | Sunshine (статус: Посетитель), 6 марта 2009, 14:07 [#13]:AddWatch: Expression - pData^
 [X] Memory Dump
 
 При выполнении:
 Watch Name - pData^
 Value - (no value)
 
 pData = $162768
 |  
|   | Вадим К (статус: Академик), 6 марта 2009, 14:29 [#14]:значение адреса указателя мне ничем не поможет. строка с русских символов нормально вставляется?
 Галочка "подтверждения прочтения" - вселенское зло. |  
|   | Sunshine (статус: Посетитель), 6 марта 2009, 14:39 [#15]:Вставляется куда? P.S. Я так понимаю, у вас Delphi вообще нет под рукой?
 |  
|   | Вадим К (статус: Академик), 6 марта 2009, 14:45 [#16]:У меня есть 7 делфи прям сейчас. 2009 только дома.
 Я имею ввиду, если использовать вышеприверённую функцию для вставки в буффер обмена полностью русскоязычной строки, то как результат - один символ/иероглифы/вообще ничего/другой вариант.
 Галочка "подтверждения прочтения" - вселенское зло. |  
|   | Sunshine (статус: Посетитель), 6 марта 2009, 14:49 [#17]:"привет" переходит в "?@825B" и после каждого из этих символов "квадратик". Остальное (латинские буквы, цифры) - попадает только первый символ.
 |  
|   | Вадим К (статус: Академик), 6 марта 2009, 14:58 [#18]:Тогда мое предположение верно. Буфер по ходу "неюникодный". В случае латиской строки он натыкается на первый 0, который будет гарантированое вторым байтом (подумайте почему) и считает это концом строки. Вот поэтому и один символ. В случае русскоязычной строки, ноль есть только в конце. Но как отобразит промежуточные символы - неизвестно.
 Попробуем по простому. Надо задать правильный флаг, что бы бедная виндовс поняла, что он неё хотят. Нужен такой флаг
 CF_UNICODETEXT вместо CF_Text,
 А может и такой CF_UNICODETEXT or CF_Text.
 Галочка "подтверждения прочтения" - вселенское зло. |  
|   | Sunshine (статус: Посетитель), 6 марта 2009, 16:08 [#19]:Ура! CF_UNICODETEXT решило все проблемы. Вадим, огромное спасибо! Всё работает!
 |  
|   | Вадим К (статус: Академик), 6 марта 2009, 16:18 [#20]:Вот если бы ещё оставили рабочий код, что бы другие, найдя поиском вопрос, могли и решение увидеть, вообще было бы замечательно. Галочка "подтверждения прочтения" - вселенское зло. |  Страницы: [1] [2] [Следующая »]  Чтобы оставлять сообщения в мини-форумах, Вы должны авторизироваться на сайте. |