Для управления ярлыками в Windows используется COM-класс ShellLink, имеющий идентификатор CLSID_ShellLink и реализующий два интерфейса: IShellLink, который позволяет получать и назначать свойства ярлыка, и IPersistFile, предназначенный (в данном случае) для чтения и записи файла ярлыка. Кроме этого, существует функция SHAddToRecentDocs, предназначенная для добавления в меню Start/Documents ярлыков на документы, которые пользователь открывал последними.
В действительности, существует две версии этого интерфейса: IShellLinkA и IShellLinkW, последний из которых доступен только под Windows NT/2000/XP; какая из версий будет использоваться зависит от того, в какой конфигурации компилируется приложение — ANSI или Unicode. Ниже перечислены методы данного интерфейса.
HRESULT GetPath(
LPTSTR pszDest,
int cchMax,
WIN32_FIND_DATA* pwfd,
DWORD fdwFlags
);
|
Копирует в буфер по адресу pszDest размером cchMax символов полное имя объекта, на который ссылается данный ярлык, и записывает в структуру, адресуемую параметром pwfd, атрибуты этого объекта. В качестве параметра fdwFlags может быть указана комбинация следующих флагов:
SLGP_SHORTPATH | вернуть имя в формате 8.3 |
---|---|
SLGP_UNCPRIORITY | вернуть имя в формате UNC (Universal Naming Convention) |
SLGP_RAWPATH | вернуть необработанное имя (оно, согласно MSDN, представляет собой „нечто, что может не существовать и может содержать имена переменных окружения, вместо которых необходимо подставить их значения“) |
Метод может вернуть одно из следующих значений:
NOERROR | успешное выполнение, в pszDest скопирован полный путь |
---|---|
S_FALSE | успешное выполнение, но в pszDest записана пустая строка (это происходит в том случае, когда объекту, на который ссылается ярлык, не соответствует реальный файл на диске — Recycle Bin, Control Panel, Printers) |
E_xxx | код ошибки OLE |
HRESULT SetPath( LPCTSTR pszSrc ); |
Назначает полное имя объекта, на который ссылается данный ярлык, в соответствии с параметром pszSrc. Метод возвращает значение NOERROR при успешном выполнении или код ошибки OLE — в противном случае.
HRESULT GetArguments(
LPTSTR pszDest,
int cchMax
);
|
Копирует в буфер по адресу pszDest размером cchMax символов аргументы, передаваемые объекту при его открытии (эти аргументы задаются в свойствах ярлыка на вкладке Shortcut в поле ввода Target вслед за именем объекта). Метод возвращает значение NOERROR при успешном выполнении или код ошибки OLE — в противном случае.
HRESULT SetArguments( LPCTSTR pszSrc ); |
Назначает аргументы, передаваемые объекту при его открытии, в соответствии со строкой pszSrc. Метод возвращает значение NOERROR при успешном выполнении или код ошибки OLE — в противном случае.
HRESULT GetWorkingDirectory(
LPTSTR pszDest,
int cchMax
);
|
Копирует в буфер по адресу pszDest размером cchMax символов имя папки, которая должна стать текущей для открытого объекта (это имя задается в свойствах ярлыка на вкладке Shortcut в поле ввода Start in). Метод возвращает значение NOERROR при успешном выполнении или код ошибки OLE — в противном случае.
HRESULT SetWorkingDirectory( LPCTSTR pszSrc ); |
Назначает имя папки, которая должна стать текущей для открытого объекта, в соответствии со строкой pszSrc. Метод возвращает значение NOERROR при успешном выполнении или код ошибки OLE — в противном случае.
HRESULT GetHotKey( WORD* pwDest ); |
Копирует в переменную по адресу pwDest „горячую клавишу“, используемую для открытия объекта (это сочетание клавиш задается в свойствах ярлыка на вкладке Shortcut в поле Shortcut key). Младший байт скопированного значения содержит виртуальный код основной клавиши (VK_xxx), а старший байт — комбинацию флагов, соответствующих клавишам-модификаторам:
HOTKEYF_CONTROL | клавиша Ctrl |
---|---|
HOTKEYF_SHIFT | клавиша Shift |
HOTKEYF_ALT | клавиша Alt |
Метод возвращает значение NOERROR при успешном выполнении или код ошибки OLE — в противном случае.
HRESULT SetHotKey( WORD wSrc ); |
Назначает „горячую клавишу“, используемую для открытия объекта. Младший байт параметра wSrc должен содержать виртуальный код основной клавиши, а старший — комбинацию флагов HOTKEYF_xxx, соответствующих клавишам-модификаторам, возможные значения которых приведены выше. Метод возвращает значение NOERROR при успешном выполнении или код ошибки OLE — в противном случае.
HRESULT GetShowCmd(
int* pnDest
);
|
Записывает в переменную по адресу pnDest команду показа главного окна объекта (вариант отображения главного окна выбирается в свойствах ярлыка на вкладке Shortcut из списка Run). Возможно одно из следующих значений:
SW_SHOWNORMAL | соответствует варианту Normal window |
---|---|
SW_SHOWMINNOACTIVE | соответствует варианту Minimized |
SW_SHOWMAXIMIZED | соответствует варианту Maximized |
Метод возвращает значение NOERROR при успешном выполнении или код ошибки OLE — в противном случае.
HRESULT SetShowCmd(
int nSrc
);
|
Назначает команду показа главного окна объекта в соответствии с параметром nSrc, возможные значения которого приведены выше. Метод возвращает значение NOERROR при успешном выполнении или код ошибки OLE — в противном случае.
HRESULT GetDescription(
LPTSTR pszDest,
int cchMax
);
|
Копирует в буфер по адресу pszDest размером cchMax символов описание ярлыка (под Windows 2000/XP оно задается в свойствах ярлыка на вкладке Shortcut в поле ввода Comment и отображается при наведении курсора мышки на ярлык). Метод возвращает значение NOERROR при успешном выполнении или код ошибки OLE — в противном случае.
HRESULT SetDescription( LPCTSTR pszSrc ); |
Назначает описание ярлыка в соответствии со строкой pszSrc. Метод возвращает значение NOERROR при успешном выполнении или код ошибки OLE — в противном случае.
HRESULT GetIconLocation( LPTSTR pszDest, int cchMax, int* pnIndex ); |
Копирует в буфер по адресу pszDest размером cchMax символов полное имя файла, содержащего иконку для данного ярлыка, а в переменную по адресу pnIndex — индекс иконки в этом файле, начиная с 0. Метод возвращает значение NOERROR при успешном выполнении или код ошибки OLE — в противном случае.
HRESULT SetIconLocation(
LPCTSTR pszSrc,
int nIndex
);
|
Назначает для данного ярлыка иконку, содержащуюся в файле с именем pszSrc и имеющую индекс nIndex. Метод возвращает значение NOERROR при успешном выполнении или код ошибки OLE — в противном случае.
HRESULT Resolve( HWND hWnd, DWORD fdwFlags ); |
Выполняет поиск объекта, на который ссылается данный ярлык. Параметр hWnd должен содержать дескриптор окна, поверх которого будут выводиться диалоговые окна для ввода дополнительной информации, если она понадобится системе. Через параметр fdwFlags передается набор флагов, определяющих параметры поиска:
SLR_NOSEARCH | не использовать эвристический поиск |
---|---|
SLR_UPDATE | если объект, на который ссылается ярлык был изменен, необходимо обновить его полное имя |
SLR_NOUPDATE | не обновлять ярлык в любом случае |
SLR_INVOKE_MSI | запустить Microsoft Windows Installer для восстановления объекта, на который ссылается ярлык, если это необходимо |
SLR_NO_UI | не запрашивать дополнительную информацию, если объект, на который ссылается ярлык, не может быть найден (если этот флаг установлен, старшее слово параметра fdwFlags может содержать максимальный интервал времени, в течение которого будет выполняться поиск; значение 0 соответствует интервалу по умолчанию, составляющему 3000 мс) |
Метод возвращает значение NOERROR при успешном выполнении или код ошибки OLE — в противном случае.
Этот интерфейс предоставляет методы, предназначенные для работы с дисковыми файлами.
HRESULT Load( LPCOLESTR pstrFileName, DWORD fdwMode ); |
Открывает файл с именем pstrFileName и инициализирует COM-объект данными из этого файла; параметр fdwMode определяет режим работы с файлом и может быть комбинацией следующих флагов:
STGM_READ | чтение данных |
---|---|
STGM_WRITE | запись данных |
STGM_READWRITE | чтение и запись данных |
STGM_SHARE_EXCLUSIVE | блокировать доступ других процессов к файлу |
STGM_SHARE_DENY_READ | блокировать чтение файла другими процессами |
STGM_SHARE_DENY_WRITE | блокировать запись в файл другими процессами |
STGM_SHARE_DENY_NONE | не блокировать другим процессам доступ к файлу |
Метод может возвращать одно из следующих значений:
S_OK | успешное выполнение |
---|---|
E_OUTOFMEMORY | для выполнения требуемой операции недостаточно памяти |
E_FAIL | произошла ошибка |
HRESULT Save( LPCOLESTR pstrFileName, BOOL fSetCurrent ); |
Записывает данные в файл с именем pstrFileName; если параметр fSetCurrent задан равным TRUE, то для записи данных в тот же самый файл при следующих вызовах метода параметр pstrFileName можно задавать равным NULL (значение параметра fSetCurrent при этом игнорируется). Рассмотрим простой пример:
IPersistFile* ppf; ... // обработка команды "Сохранить как..." ppf->Save(имя_файла, TRUE); ... // обработка команды "Сохранить" ppf->Save(NULL, FALSE); |
Метод Save возвращает значение S_OK при успешном выполнении или E_FAIL — в случае ошибки.
HRESULT GetCurFile( LPOLESTR* ppstrDest, ); |
Выделяет с помощью интерфейса IMalloc блок памяти, копирует в него полное имя файла, который COM-объект использует для чтения/записи данных, и записывает адрес выделенного блока в переменную по адресу ppstrDest. Освобождение этого блока памяти должно выполняться приложением-клиентом. Пример использования:
IPersistFile* ppf; IMalloc* pMalloc; ... // получили указатель на IPersistFile LPOLESTR pstrCurFile = NULL; ppf->GetCurFile(&pstrCurFile); ::MessageBoxW(NULL, pstrCurFile, L"Current File", MB_OK); // получаем указатель на IMalloc ::SHGetMalloc(&pMalloc); // освобождаем память pMalloc->Free(pstrCurFile); // IMalloc больше не нужен pMalloc->Release(); |
Метод GetCurFile возвращает одно из следующих значений:
S_OK | полное имя файла успешно скопировано |
---|---|
S_FALSE | файл не имеет имени и скопированная строка является шаблоном вида *.расширение |
E_OUTOFMEMORY | для выполнения требуемой операции недостаточно памяти |
E_FAIL | произошла ошибка |
HRESULT IsDirty(void);
|
Метод возвращает значение S_OK, если данные были изменены с момента последнего сохранения файла, или S_FALSE — в противном случае.
Для чтения (и возможно — изменения) свойств уже существующего ярлыка необходимо выполнить следующую последовательность действий:
В качестве примера перечисленных действий ниже приведен текст функции, которая принимает в качестве параметра имя ярлыка и выводит на консоль полное имя файла, на который этот ярлык ссылается.
void print_shortcut_target(LPCTSTR pszShortcut) { IPersistFile* ppf; IShellLink* pshl; WIN32_FIND_DATA wfd; // инициализируем COM-библиотеку ::CoInitialize(NULL); // создаем COM-объект и получаем указатель на IPersistFile ::CoCreateInstance(CLSID_ShellLink, NULL, CLSCTX_INPROC_SERVER, IID_IPersistFile, reinterpret_cast<void**>(&ppf)); // загружаем ярлык#if defined(_UNICODE) ppf->Load(pszShortcut, STGM_READ); #else LPWSTR pwszTemp = new WCHAR[_MAX_PATH]; mbstowcs(pwszTemp, pszShortcut, _MAX_PATH); ppf->Load(pwszTemp, STGM_READ); delete[] pwszTemp; #endif// получаем указатель на IShellLink ppf->QueryInterface(IID_IShellLink, reinterpret_cast<void**>(&pshl)); // ищем объект, на который ссылается ярлык pshl->Resolve(NULL, SLR_ANY_MATCH | SLR_NO_UI); // получаем имя объекта и выводим его на консоль LPTSTR pszTarget = new TCHAR[_MAX_PATH]; pshl->GetPath(pszTarget, _MAX_PATH, &wfd, 0); _putts(pszTarget); delete[] pszTarget; // убираем за собой pshl->Release(); ppf->Release(); // завершаем работу с COM-библиотекой ::CoFreeUnusedLibraries(); ::CoUninitialize(); } |
Для создания нового ярлыка необходимо выполнить следующие действия:
Возможный вариант реализации описанной последовательности действий содержится в методе OnButtonCreate класса CMainDialog из примера к данной статье.
void CMainDialog::OnButtonCreate(void) { USES_CONVERSION; HRESULT hr; IShellLink* pShLink; TCHAR szIconFile[_MAX_PATH]; int iIcon; IPersistFile* ppf; CString strName; if (UpdateData()) { // создаем ShellLink и получаем указатель на IShellLink hr = ::CoCreateInstance(CLSID_ShellLink, NULL, CLSCTX_INPROC_SERVER, IID_IShellLink, reinterpret_cast<void**>(&pShLink)); if (SUCCEEDED(hr)) { // назначаем иконку в соответствии с типом файла GetFileIcon(m_strTarget, szIconFile, &iIcon); if (::lstrlen(szIconFile) > 0) { pShLink->SetIconLocation(szIconFile, iIcon); } // назначаем поле "Target" pShLink->SetPath(m_strTarget); // назначаем поле "Start in" pShLink->SetWorkingDirectory(m_strStartIn); // назначаем поле "Run"staticint anShowCmds[] = { SW_SHOWNORMAL, SW_SHOWMINNOACTIVE, SW_SHOWMAXIMIZED }; pShLink->SetShowCmd(anShowCmds[m_iRun]); // получаем интерфейс IPersistFile hr = pShLink->QueryInterface(IID_IPersistFile, reinterpret_cast<void**>(&ppf)); if (SUCCEEDED(hr)) { // записываем файл ярлыка в заданную папку strName.Format(IDS_NAME_FORMAT, ::PathFindFileName(m_strTarget)); ppf->Save(T2CW(m_strLocation + _T('\\') + strName), FALSE); AfxMessageBox(IDS_SUCCEEDED, MB_ICONINFORMATION | MB_OK); // отпускаем IPersistFile ppf->Release(); } else { AfxMessageBox(IDS_SAVE_ERROR, MB_ICONSTOP | MB_OK); } // отпускаем IShellLink pShLink->Release(); } else { AfxMessageBox(IDS_CREATE_ERROR, MB_ICONSTOP | MB_OK); } } } |
Надеюсь, что теперь работа с ярлыками не будет вызывать у читателя сколько-нибудь серьезных трудностей. Но помните — «In Windows, there’s always a catch…»