Модераторы: Poseidon, Snowy, bems, MetalFan
  

Поиск:

Ответ в темуСоздание новой темы Создание опроса
> ExtractAssociatedIcon - Ошибка в MSDN, привела к ошибкам в программах, даже в F 
:(
    Опции темы
Петрович
  Дата 14.7.2004, 20:36 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
***


Профиль
Группа: Участник Клуба
Сообщений: 1000
Регистрация: 2.12.2003
Где: Москва

Репутация: 25
Всего: 55



Для начала, попробую задать всем одну простейшею задачку:

Имеем форму Form1, а на ней мемку Memo1 и кнопку Button1. На обработчик OnClick кнопки "повешен" следующий обработчик:
Код
procedure TForm1.Button1Click(Sender: TObject);
var
 s1,s2 :String;
 i :Word;
begin
 s1 := 'c:\Вася\Петя\Лёша\Саша\Маша\Игорь\Дима';
 s1 := s1+'.lnk';
 s2 := s1;
 i := 0;
 ExtractAssociatedIcon(Application.Handle, PChar(s1), i);
 Memo1.Lines.Add(s1);
 Memo1.Lines.Add(s2);
end;


Теперь вопрос:
Что будет выведено в Memo1 после нажатия кнопки Button1?

Маленькое уточнение. На диске не должно быть файла'c:\Вася\Петя\Лёша\Саша\Маша\Игорь\Дима.lnk'

Первому, правильно ответившему, и пояснившему ответ, поставлю + в репутацию :yes:

Объяснения и свои комментарии, я напишу позже, если потребуется B)


--------------------
Все знать невозможно, но хочется
PM ICQ   Вверх
Vex
Дата 14.7.2004, 20:47 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


кацапосрачмученiкъ
****


Профиль
Группа: Экс. модератор
Сообщений: 3103
Регистрация: 28.3.2002
Где: strawberry fields

Репутация: 1
Всего: 88



''
c:\Вася\Петя\Лёша\Саша\Маша\Игорь\Дима.lnk

угадал? smile.gif


--------------------
Слава Україні.
PM   Вверх
Петрович
Дата 14.7.2004, 21:17 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
***


Профиль
Группа: Участник Клуба
Сообщений: 1000
Регистрация: 2.12.2003
Где: Москва

Репутация: 25
Всего: 55



Нет. если-бы все так просто, я бы и писать не стал. smile.gif


--------------------
Все знать невозможно, но хочется
PM ICQ   Вверх
<Spawn>
Дата 14.7.2004, 21:38 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Око кары:)
****


Профиль
Группа: Экс. модератор
Сообщений: 2776
Регистрация: 29.1.2003
Где: Екатеринбург

Репутация: 44
Всего: 64



Сейчас особенно нет времени разбираться, так как пора спать, но эффект весьма странный - выдирается иконка из shell32.dll. Причем такая, как если бы это был пустой ярлык, не ассоциированый с реальным файлом на диске. Возможно это и есть обьяснение ее логики работы, так как данного ярлыка не существуетsmile.gif
П.С. Спокойной ночиsmile.gif

Не - тут чего то не тоsmile.gif Завтра почитаю ответыsmile.gif

Это сообщение отредактировал(а) <Spawn> - 14.7.2004, 21:42


--------------------
"Для некоторых людей программирование является такой же внутренней потребностью, подобно тому, как коровы дают молоко, или писатели стремятся писать" - Николай Безруков.
PM MAIL ICQ   Вверх
AriX
Дата 14.7.2004, 22:40 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 311
Регистрация: 16.6.2003

Репутация: 5
Всего: 19



выводится два раза путь к shell32.dll
Цитата
C:\WINDOWS\system32\shell32.dll
C:\WINDOWS\system32\shell32.dll


предположение такое:

так как по-умолчанию типа String это AnsiString - то в s1 хранится не сама строка, а указатель.. дальше в s2 пихается этот же указатель ну ту же строку... потом мы pchar'им s1 - но PChar это тоже указатель на строку..
в итоге получается так что если файла не существует, то ExtractAssociatedIcon (вот тут могу ошибаться) наверное возвращает пустую иконку (типа для несуществующего файла) из стандартного набора иконок (shell32.dll), а в s1 (т.е. туда куда он указывает) пихает путь к файлу с этими иконками (он типа ассоциирован с не существующими файлами)... а так как s2 ссылается на ту же область что и s1, то вторая строка в мемо получается такой же

может плохо объяснил - но если на пальцах - то так smile.gif))

Это сообщение отредактировал(а) AriX - 14.7.2004, 22:59
PM MAIL   Вверх
Alex
Дата 14.7.2004, 22:41 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Экс. модератор
Сообщений: 4147
Регистрация: 25.3.2002
Где: Москва

Репутация: 80
Всего: 162



Ну а что тут объеснять в MSDN написано
Цитата
Pointer to a string that specifies the full path and file name of the file that contains the icon. The function extracts the icon handle from that file, or from an executable file associated with that file.
If the icon handle is obtained from an executable file, the function stores the full path and file name of that executable in the string pointed to by lpIconPath

Из чего следует, что вам вернули путь до файла, из которого вам взяли иконку. В данном случае к shell32.dll, в которой храниться иконка пустого файла.

Но на сколько я понимаю вас возмущает не это, а то, что в s2 тоже изменяется значение. Ну, вообще-то это очень странно, но объяснение этому есть т. к. это указатель на адрес памяти, где хранятся значения переменных, и когда вы пишите s2:= s1; то просто увеличивается счетчик ссылок на это значение. Соответственно когда изменяется значение переменной s1, то эти данные должны положиться по новому адресу чтобы значение s2 осталось неизменным, но Microsoft по необъяснимым причинам кладет их по старому адресу тем самым, затирая значения в s2.

Решение проблемы:
Код
s1 := 'c:\Вася\Петя\Лёша\Саша\Маша\Игорь\Дима';
s1 := s1+'.lnk';
SetString(s2, PChar(s1), length(s1));
i := 0;
ExtractAssociatedIcon(Application.Handle, PChar(s1), i);
Memo1.Lines.Add(s1);
Memo1.Lines.Add(s2);



--------------------
Написать можно все - главное четко представлять, что ты хочешь получить в конце. 
PM Skype   Вверх
AriX
Дата 14.7.2004, 23:00 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 311
Регистрация: 16.6.2003

Репутация: 5
Всего: 19



млин, пока изменял свой пост - уже ответили smile.gif
PM MAIL   Вверх
Петрович
Дата 14.7.2004, 23:21 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
***


Профиль
Группа: Участник Клуба
Сообщений: 1000
Регистрация: 2.12.2003
Где: Москва

Репутация: 25
Всего: 55



Про s1 и s2 все правильно рассказали.
Но, теперь, самое интересное:
попробуйте вместо:
Код
 s1 := 'c:\Вася\Петя\Лёша\Саша\Маша\Игорь\Дима';

написать:
Код
 s1 := 'c:\Вася';





--------------------
Все знать невозможно, но хочется
PM ICQ   Вверх
AriX
Дата 14.7.2004, 23:47 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 311
Регистрация: 16.6.2003

Репутация: 5
Всего: 19



ага точно - пробовал, там меньше чем c:\Вася\Петя\Лёша\Саша уже не напишешь
PM MAIL   Вверх
Girder
Дата 15.7.2004, 10:44 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Лентяй 2
***


Профиль
Группа: Участник Клуба
Сообщений: 1993
Регистрация: 12.5.2004

Репутация: 31
Всего: 155



Петрович просто все плохо sad.gif читают MSDN(я, не исключение biggrin.gif ).

Лови:
Код
procedure TForm1.Button1Click(Sender: TObject);
var
s1,s2 :String;
i :Word;
begin
s1 := 'c:\Вася\Петя\Лёша\Саша\Маша\Игорь\Дима';
s1 := s1+'.lnk';
s2 := s1;
setlength(s1,Max_Path);
i := 0;
ExtractAssociatedIcon(Application.Handle, PChar(s1), i);
Memo1.Lines.Add(s1);
Memo1.Lines.Add(s2);
end;

Кстати, приколись:
Код
procedure TForm1.Button1Click(Sender: TObject);
var
s1,s2 :String;
i :Word;
begin
s1 := 'c:\Вася\Петя\Лёша\Саша\Маша\Игорь\Дима.lnk';
s2 := s1;
i := 0;
ExtractAssociatedIcon(Application.Handle, PChar(s1), i);
Memo1.Lines.Add(s1);
Memo1.Lines.Add(s2);
end;
.



--------------------
Как слышим, так и пишим.
Истина где-то там...
PM   Вверх
Петрович
Дата 15.7.2004, 11:03 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
***


Профиль
Группа: Участник Клуба
Сообщений: 1000
Регистрация: 2.12.2003
Где: Москва

Репутация: 25
Всего: 55



Цитата
Кстати, приколись:

Если-бы я этого не знал, то разве стал-бы писать:
Код
s1 := s1+'.lnk';

Цитата
просто все плохо  читают MSDN

1. А где там написан размер буфера?
2. Поскольку ответ найден, теперь приведу свой вариант smile.gif.

Для начала, фрагмент описания ExtractAssociatedIcon из MSDN:
Цитата
...
HICON ExtractAssociatedIcon(
  HINSTANCE hInst,    // application instance handle
  LPTSTR lpIconPath,  // file name
  LPWORD lpiIcon      // icon index
);
Parameters
...
lpIconPath
[in] Pointer to a string that specifies the full path and file name of the file that contains the icon. The function extracts the icon handle from that file, or from an executable file associated with that file.
If the icon handle is obtained from an executable file, the function stores the full path and file name of that executable in the string pointed to by lpIconPath.
...

Красным выделил неувязочку в MSDN. Т.е. про параметр lpIconPath сказано что он только входной ([in]), а ниже сказано что в строку на которую он указывает, возвращается путь до файла содержащего икону.
Причем, нигде не сказанно, какого размера будет возвращаемая строка! Обычно, если API функция возвращает строку в буфер предоставляемый программой (как в данном случае) ей на вход, помимо указателя на буфер передают и его размер. Это для того, что-бы она не вышла за его границу. Здесь-же мы такого не видим. Можно было-бы предположить, что размер буфера определяется по размеру переданной в этом параметре строки. Но, это не так. Реально, Windows наглым образом копирует по переданному указателю столько байт, сколько им захочется! Т.е., легко переваливает за буфер! Именно поэтому, я и передаю такое длинное имя в первом примере - что-бы не было AV. Во втором варианте, передача короткого имени приводит к тому, что результирующая строка превышает размер выделенной под s1 памяти. Обычно это приводит к AV, причем иногда не сразу.

Теперь, посмотрим как используется данная функция в Delphi программах.
Например, из FAQ:
Код
Icon := ExtractAssociatedIcon(HInstance, PChar(edit1.text+ListBox1.Items[Index]), IconIndex)

Причем, подобное встречал и в других текстах.
Казалось-бы, в свете вышесказанного, это должно приводить к AV. Почему-же никто еще об это не споткнулся?
Да все очень просто. Обычно, к ExtractAssociatedIcon обращаются с именем существующего файла. А в этом случае, она возвращает именно это имя обратно - т.е. не выходит за "габариты" переданной строки.
Я же, наткнулся на это случайно. Просто из-за ошибки в своей программе, я передал туда имя несуществующего линка (просто без пути smile.gif). Ну и огреб по полной программе smile.gif.

Резюме.
Надо передавать в ExtractAssociatedIcon вторым параметром строку размещенную в буфере достаточного размера. Вопрос только какого. Поскольку в MSDN ничего об этом не сказано, можно лишь предложить что-то вроде MAX_PATH.
Соответственно, вот пример кода (функцианально похож на код приведенный Girderом):

Код
function ExtractAssociatedIcon_ (FileName :String) :HICON;
var
 i :Word;
 b :array[0..MAX_PATH] of char;
begin
 i := 0;
 Result := ExtractAssociatedIcon(Application.Handle, StrLCopy(b,PChar(FileName),SizeOf(b)-1),i);
end;


Он работает нормально. Проверено.

Просьба к Vitу - подправь пожалуйста в FAQ
Добавлено @ 11:05
Да, к стати:
Цитата

...
s2 := s1;
setlength(s1,Max_Path);
i := 0;
ExtractAssociatedIcon(Application.Handle, PChar(s1), i);
Memo1.Lines.Add(s1);
...

У меня тоже не проходит. Дело в том, что у меня setlength(s1,Max_Path); переносит завершающий #0 в новый конец строки. Поэтому, если передавать имя реально существующего имени файла, то он его все равно не находит smile.gif.


--------------------
Все знать невозможно, но хочется
PM ICQ   Вверх
Girder
Дата 15.7.2004, 13:11 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Лентяй 2
***


Профиль
Группа: Участник Клуба
Сообщений: 1993
Регистрация: 12.5.2004

Репутация: 31
Всего: 155



Цитата
У меня тоже не проходит. Дело в том...
Так значит мусор в новом месте был. Можно к примеру так:
Код
...
i:=Length(s1);
inc(i);
setlength(s1,Max_Path);
if (i<=Max_Path) then s1[i]:=#0;
i:=0;
...



--------------------
Как слышим, так и пишим.
Истина где-то там...
PM   Вверх
Петрович
Дата 15.7.2004, 16:52 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
***


Профиль
Группа: Участник Клуба
Сообщений: 1000
Регистрация: 2.12.2003
Где: Москва

Репутация: 25
Всего: 55



Ну да, можно и так.


--------------------
Все знать невозможно, но хочется
PM ICQ   Вверх
  
Ответ в темуСоздание новой темы Создание опроса
Правила форума "Delphi: Общие вопросы"
SnowyMetalFan
bemsPoseidon
Rrader

Запрещается!

1. Публиковать ссылки на вскрытые компоненты

2. Обсуждать взлом компонентов и делиться вскрытыми компонентами

  • Литературу по Дельфи обсуждаем здесь
  • Действия модераторов можно обсудить здесь
  • С просьбами о написании курсовой, реферата и т.п. обращаться сюда
  • Вопросы по реализации алгоритмов рассматриваются здесь
  • 90% ответов на свои вопросы можно найти в DRKB (Delphi Russian Knowledge Base) - крупнейшем в рунете сборнике материалов по Дельфи


Если Вам понравилась атмосфера форума, заходите к нам чаще! С уважением, Snowy, MetalFan, bems, Poseidon, Rrader.

 
0 Пользователей читают эту тему (0 Гостей и 0 Скрытых Пользователей)
0 Пользователей:
« Предыдущая тема | Delphi: Общие вопросы | Следующая тема »


 




[ Время генерации скрипта: 0.0597 ]   [ Использовано запросов: 22 ]   [ GZIP включён ]


Реклама на сайте     Информационное спонсорство

 
По вопросам размещения рекламы пишите на vladimir(sobaka)vingrad.ru
Отказ от ответственности     Powered by Invision Power Board(R) 1.3 © 2003  IPS, Inc.