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

Пример 1 «Добавление пунктов в контекстное меню для отдельных расширений файлов»

Далее в качестве примера создадим и запустим расширение, которое просто выводит сообщение о том, что оно загружено и работает. Мы привяжем его к TXT-файлам, так что наше расширение будет вызываться, когда пользователь щелкнет правой кнопкой мыши на текстовом файле.

Использование AppWizard.

Я еще не рассказал вам, как использовать интерфейсы расширений оболочки? Не беспокойтесь, я объясню, когда дойду до этого. Это лучше усвоится, если будет сопровождаться примерами. Я объясню понятия и буду сопровождать их кодом примера. Можно было-бы объяснить все сначала, а затем дать код, но я нахожу, что это тяжелее для понимания.

В любом случае запускайте MS VC и мы начнем.

Запустите AppWizard и создайте новый ATL COM проект. Назовем его SimpleExt. Сохраните все установки по-умолчанию и нажмите "Finish". Теперь у нас есть пустой ATL- проект, из которого будет создана DLL, но нам необходимо добавить в него наш COM объект - расширение оболочки.

В дереве ClassView щелкните правой кнопкой на пункте SimpleExt Classes и выберите "New ATL Object". В "ATL Object" - мастере на первой странице уже отмечено "Simple Object", поэтому просто идите дальше. На второй панели введите SimpleShlExt в поле Short Name и щелкните OK. (Други редактируемые поля на панели будут заполнены автоматически). Созданный класс CSimpleShlExt содержит основной код COM - объекта. Мы добавим наш код к этому классу.

Интерфейс инициализации

Когда наше расширение загружается, проводник вызывает функцию QueryInterface(), чтобы получить указатель на интерфейс IShellExtInit. Этот интерфейс имеет только один метод, Initialize():

HRESULT IShellExtInit::Initialize (

LPCITEMIDLIST pidlFolder,

LPDATAOBJECT pDataObj,

HKEY hProgID );

Проводник использует этот метод, чтобы давать нам различную информацию. pidlFolder - это PIDL (pointer to an ID list) папки, содержащей активизированные файлы. (PIDL - это структура данных, которая однозначно идентифицирует любой объект в оболочке, независимо от того, объект это файловой системы или нет). pDataOdj - указатель на интерфейс IDataObject, с помощью которого мы извлекаем имена активизированных файлов. hProgID открывает HKEY, который мы используем, чтобы получить доступ к ключу реестра, содержащему регистрационные данные нашей DLL. Для нашего расширения необходимо использовать параметр pDataObj.

Чтобы добавить IShellExtInit к нашему проекту, откройте SimpleShExt.h и введите выделенные строки:

#include <shlobj.h>

#include <comdef.h>

class ATL_NO_VTABLE CSimpleShlExt :

public CComObjectRootEx<CComSingleThreadModel>,

public CComCoClass<CSimpleShlExt, &CLSID_SimpleShlExt>,

public IDispatchImpl<ISimpleShlExt, &IID_ISimpleShlExt, &LIBID_SIMPLEEXTLib>,

public IShellExtInit

{

BEGIN_COM_MAP(CSimpleShlExt)

COM_INTERFACE_ENTRY(ISimpleShlExt)

COM_INTERFACE_ENTRY(IDispatch)

COM_INTERFACE_ENTRY(IShellExtInit)

END_COM_MAP()

COM_MAP- это то, как ATL осуществляет QueryInterface().

Затем в декларации класса добавьте прототип Initialize(). Нам также необходим буфер, чтобы сохранить имя файла:

protected:

TCHAR m_szFile [MAX_PATH];

public:

// IShellExtInit

STDMETHOD(Initialize)(LPCITEMIDLIST, LPDATAOBJECT, HKEY);

В SimpleShlExt.cpp добавьте определение функции:

HRESULT CSimpleShlExt::Initialize (

LPCITEMIDLIST pidlFolder,

LPDATAOBJECT pDataObj,

HKEY hProgID )

В ней мы получим имя файла, отмеченного правым щелчком мыши, и покажем его в выводимом сообщении. Если файлов больше одного, мы могли бы получить доступ к ним ко всем через указатель pDataObj, но, поскольку мы хотим упростить работу мы получим только имя первого из них.

Имя файла сохранено в том же самом формате, в каком оно использовалось, когда вы переносили файл, используя стиль WS_EX_ACCEPTFILES. Это означает, что мы можем получить имена файлов используя то же API - DragQueryFile(). Начнем писать функцию, получающую доступ к данным, содержащимся в IDataObject:

{

FORMATETC fmt = { CF_HDROP, NULL, DVASPECT_CONTENT, -1, TYMED_HGLOBAL };

STGMEDIUM stg = { TYMED_HGLOBAL };

HDROP hDrop;

// Look for CF_HDROP data in the data object.

if ( FAILED( pDataObj->GetData ( &fmt, &stg )))

{

// Nope! Return an "invalid argument" error back to Explorer.

return E_INVALIDARG;

}

// Get a pointer to the actual data.

hDrop = (HDROP) GlobalLock ( stg.hGlobal );

// Make sure it worked.

if ( NULL == hDrop )

{

return E_INVALIDARG;

}

Заметим, что крайне важно избежать любых ошибок, особенно с указателями. поскольку наше расширение запускается в пространстве процесса проводника, и, если мы ошибемся, то разрушим проводник. В Win 9х такая ошибка приводит к необходимости перезагружать компьютер.

Теперь, когда мы имеем дескриптор HDROP, мы можем получить нужное имя файла:

// Sanity check – make sure there is at least one filename.

UINT uNumFiles = DragQueryFile ( hDrop, 0xFFFFFFFF, NULL, 0 );

if ( 0 == uNumFiles )

{

GlobalUnlock ( stg.hGlobal );

ReleaseStgMedium ( &stg );

return E_INVALIDARG;

}

HRESULT hr = S_OK;

// Get the name of the first file and store it in our member variable m_szFile.

if ( 0 == DragQueryFile ( hDrop, 0, m_szFile, MAX_PATH ))

{

hr = E_INVALIDARG;

}

GlobalUnlock ( stg.hGlobal );

ReleaseStgMedium ( &stg );

return hr;

}

Если мы возвратим E_INVALIDARG, проводник не вызовет наше расширение повторно при правом щелчке мыши. Если мы возвратим S_OK, проводник вызовет QueryInterface() еще раз и получит указатель на другой интерфейс, который мы добавим - IContextMenu.

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