![]() |
|
|
|||||||
| Регистрация | << Правила форума >> | FAQ | Пользователи | Календарь | Поиск | Сообщения за сегодня | Все разделы прочитаны |
![]() |
|
|
Опции темы | Поиск в этой теме | Опции просмотра |
|
|
|
#1
|
|||
|
|||
|
Периодически в этом подфоруме возникают вопросы "Как перетащить в свое приложение файлы из Проводника Windows?". И я даже пару раз на них отвечал. Посколько мне сегодня с утра нечего делать, я решил написать развернутое пособие на эту тему, благо там ничего сложного нет. Просто обычно формат ответа на вопрос в форуме не подразумевает подробных пояснений, а я все же думаю, что всегда полезно понимать, почему это работает так, а не иначе, и понимать, что ты в данный момент делаешь.
Итак, сложного, как я сказал уже, ничего нет, но есть один нюанс. В большинстве примеров, которые я видел, рассматривается перенос файлов на форму, тогда как обычно в приложении за прием файлов отвечает не форма целиком, а какой-то конкретный элемент формы - TMemo, TListBox и т.п. Делается это потому, что для формы легко организовать перехват сообщения WM_DROPFILES, которым Windows информирует приложение о том, что на него осуществляется перенос файлов. В Delphi для этого существуют т.н. "методы сообщений". Вот тут я писал, как сделать прием файлов формой. Здесь я рассмотрю аналогичную форму, только вместо TMemo буду использовать TListBox. Принципиально это ни на что не влияет, просто TListBox мне в данном случае больше нравится. Как же сделать, чтобы файлы принимались отдельным элементом формы, и не принимались другими? На первый взгляд достаточно заменить вызов: Код:
DragAcceptFiles(Form1.Handle, True); Код:
DragAcceptFiles(ListBox1.Handle, True); То есть задача сводится к тому, чтобы перехватить WM_DROPFILES не в обработчике формы, а непосредственно в обработчике того элемента, который у нас отвечает за прием файлов. Хитрость тут вот чем. И TForm, и TMemo, и TListBox - все это так называемые "оконные" компоненты, т.е. они имеют дескриптор окна, который содержится в свойстве Handle и процедуру окна. Вот до этой процедуры окна нам и надо как-то добраться. Для этого мы напишем свою процедуру окна для ListBox1 и заменим ею стандартную. В WinAPI есть функция SetWindowLong: Код:
SetWindowLong(hWnd: HWND; nIndex: Integer; dwNewLong: Integer): Integer; Сама же процедура окна должна быть описана в виде функции такого вида: Код:
function NewWndProc(Handle: HWND; Msg, WParam, LParam: LongInt): LongInt; stdcall; Итак, чтобы заменить оконную процедуру мы вызываем SetWindowLong: Код:
OldListWndProc := Pointer(SetWindowLong(ListBox1.Handle, GWL_WNDPROC, Integer(@NewListWndProc))); Сама же новая процедура окна будет выглядеть так: Код:
function NewListWndProc(Handle: HWND; Msg, WParam,
LParam: LongInt): LongInt; stdcall;
//------------------------------------------------------------------------------
// Новая процедура для окна списка
//------------------------------------------------------------------------------
var
i, Count: Integer;
SFileName: Array [0..256] of Char;
begin
// Мы обрабатываем сообщение WM_DROPFILES
if Msg = WM_DROPFILES then begin
// Файлов может быть более одного. Чтобы узнать сколько их,
// вызываем функцию DragQueryFiles и вместо порядкового номера файла
// указываем $FFFFFFFF. Функция вернет количество файлов.
Count := DragQueryFile(WParam, $FFFFFFFF, SFilename, SizeOf(SFilename));
// Теперь когда знаем количество файлов, можем перебрать их в цикле
// и добавить в список
for i := 0 to Count - 1 do begin
// Сейчас нам нужно уже конкретное имя файла,
// поэтому мы указываем порядковый номер файла и получаем в
// переменной SFileName его имя.
DragQueryFile(WParam, i, SFileName, SizeOf(SFileName));
// Добавляем имя в список
MainForm.AddFileToList(MainForm.ListBox1.Items, SFileName);
end;
// Windows для переноса файлов выделяла память.
// Вызов DragFinish сообщает системе, что память можно освободить
DragFinish(WParam);
end;
// Вызываем старый обработчик сообщений ListBox
Result := CallWindowProc(OldListWndProc, Handle, Msg, WParam, LParam);
end;Собственно, на этом и все. Остается сделать, как описано выше, ListBox1 приемником файлов Код:
DragAcceptFiles(ListBox1.Handle, True); Код:
SetWindowLong(ListBox1.Handle, GWL_WNDPROC, Integer(OldListWndProc)); Код:
TMyForm = class(TForm) ... private procedure WndMethod(var Msg: TMessage); ... end; Всем, кто дочитал до этого места спасибо. Во вложении полный проект на D2007. |
|
#2
|
||||
|
||||
|
У меня не работает. ListBox даже такого сообщения не получает. Windows Vista.
|