Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
ОСиСП - методички / OS&SP_Lab_2.6(shell).doc
Скачиваний:
95
Добавлен:
18.05.2015
Размер:
1.12 Mб
Скачать

DragLeave()

DragLeave() вызывается, если пользователь утаскивает объект прочь от нашего целевого файла, не сбрасывая его. Этот метод не используется для меню Send To, но он вызывается, если у вас открыто окно проводника на каталоге Send To и вы перетаскиваете файлы в этот каталог. У нас нет никакой очистки, которую нужно было бы сделать (деструктор CString сам позаботиться об этом), поэтому все, что нам нужно сделать - это вернуть S_OK:

HRESULT CSendToShlExt::DragLeave()

{

return S_OK;

}

Drop()

Если пользователь выберет наш пункт из меню Send To, проводник вызывает метод Drop(), прототип которого:

HRESULT IDropTarget::Drop (

IDataObject* pDataObj,

DWORD grfKeyState,

POINTL pt,

DWORD* pdwEffect );

Первые три параметра такие же, как у DragEnter(). Drop() должен вернуть результат всей операции через параметр pdwEffect. Наша реализация Drop() создает диалог и передает ему список имен файлов. Диалог делает все работу, и, когда происходит возврат из DoModal(), мы устанавливаем результат сбрасывания:

HRESULT CSendToShlExt::Drop (

IDataObject* pDataObj,

DWORD grfKeyState,

POINTL pt,

DWORD* pdwEffect )

{

AFX_MANAGE_STATE(AfxGetStaticModuleState()); // init MFC

CSendToCloneDlg dlg ( &m_lsDroppedFiles );

dlg.DoModal();

*pdwEffect = DROPEFFECT_COPY;

return S_OK;

}

Диалог выглядит так:

Это достаточно прямолинейный MFC диалог, и вы можете найти исходники в файле SendToCloneDlg.cpp. Я делал копирование и перемещение используя класс CShellFileOp из моей статьи "CShellFileOp - Wrapper for SHFileOperation."

Подождите! А как мы сообщим проводнику о нашем обработчике сбрасывания? И как нам получить пункт в меню Send To? Я объясню, как это делается, в следующем разделе.

Регистрация расширения

Регистрация обработчика сбрасывания немного отличается от регистрации других типов расширений, т.к. требует создания новой ассоциации под ключом HKEY_CLASSES_ROOT. AppWizard генерирует RGS сценарий, показанный ниже. Часть, которую вы должны добавить или изменить выделена.

HKCR

{

.SendToClone = s 'CLSID\{B7F3240E-0E29-11D4-8D3B-80CD3621FB09}'

SendToClone.SendToShlExt.1 = s 'SendToShlExt Class'

{

CLSID = s '{B7F3240E-0E29-11D4-8D3B-80CD3621FB09}'

}

SendToClone.SendToShlExt = s 'SendToShlExt Class'

{

CLSID = s '{B7F3240E-0E29-11D4-8D3B-80CD3621FB09}'

CurVer = s 'SendToClone.SendToShlExt.1'

}

NoRemove CLSID

{

ForceRemove {B7F3240E-0E29-11D4-8D3B-80CD3621FB09} = s 'Send To Any Folder Clone'

{

ProgID = s 'SendToClone.SendToShlExt.1'

VersionIndependentProgID = s 'SendToClone.SendToShlExt'

ForceRemove 'Programmable'

InprocServer32 = s '%MODULE%'

{

val ThreadingModel = s 'Apartment'

}

'TypeLib' = s '{B7F32400-0E29-11D4-8D3B-80CD3621FB09}'

val NeverShowExt = s ''

DefaultIcon = s '%MODULE%,0'

shellex

{

DropHandler = s '{B7F3240E-0E29-11D4-8D3B-80CD3621FB09}'

}

}

}

}

Первая строка как раз и выполняет ассоциацию. Она создает новое расширение, .SendToClone, которое и будет использоваться нашей целью для сбрасывания. Заметим, что у значения по умолчанию ключа .SendToClone есть приставка "CLSID\". Это говорит проводнику, что данные, которые описывает ассоциация находятся в ключе под HKCR\CLSID, рядом с более стандартными ассоциациями, данные которых сохранены в ключе прямо под HKEY_CLASSES_ROOT (например, ключ .txt указывает на ключ txtfile), но это только кажется стандартным - сохранение ассоциации обработчика сбрасывания под своим CLSID ключом, чтобы держать все данные в одном месте.

Строка "Send To Any Folder Clone" - это описание типа файла, которая появляется в проводнике, если вы просматриваете каталог Send To. Значение NeverShowExt создано, чтобы сообщить проводнику, что не нужно показывать расширение ".SendToClone". DefaultIcon - ключ, указывающий размещение иконки, ассоциированной с файлами .SendToClone. Наконец, у нас есть знакомый ключ shellex с подключом DropHandler. Т.к. здесь может быть только один обработчик для данного типа файлов, GUID обработчика сохранен прямо в ключе DropHandler, вместо подключа под DropHandler.

Оставшаяся деталь - создать файл в каталоге Send To, чтобы там появился наш пункт в меню. Мы можем сделать это в DllRegisterServer() и удалить файл в DllUnregisterServer(). Вот код, создающий файл:

LPITEMIDLIST pidl;

TCHAR szSendtoPath [MAX_PATH];

HANDLE hFile;

LPMALLOC pMalloc;

if ( SUCCEEDED( SHGetSpecialFolderLocation ( NULL, CSIDL_SENDTO, &pidl )))

{

if ( SHGetPathFromIDList ( pidl, szSendtoPath ))

{

PathAppend ( szSendtoPath, _T("Some other folder.SendToClone") );

hFile = CreateFile ( szSendtoPath, GENERIC_WRITE, FILE_SHARE_READ,

NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL );

CloseHandle ( hFile );

}

if ( SUCCEEDED( SHGetMalloc ( &pMalloc )))

{

pMalloc->Free ( pidl );

pMalloc->Release();

}

}

Вот как выглядит новое меню Send To с нашим пунктом меню:

DllUnregisterServer() содержит простой код, который удаляет файл. Код, показанный выше, работает на всех версиях Windows (ну хорошо, на версиях 4 и выше). Если вы знаете, что ваш код будет запущен только в оболочке версии 4.71 и выше, вы можете использовать SHGetSpecialFolderPath() вместо SHGetSpecialFolderLocation().

Соседние файлы в папке ОСиСП - методички