|
Вопрос # 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] [Следующая »]
Чтобы оставлять сообщения в мини-форумах, Вы должны авторизироваться на сайте.
|