Чтение онлайн

на главную - закладки

Жанры

Программирование на Visual C++. Архив рассылки

Jenter Алекс

Шрифт:

IShellLink* pISL;

IPersistFile* pIPF;

// 1. Инициализация библиотеки COM (заставляем Windows загрузить библиотеки DLL). Обычно

// вам нужно делать это в функции InitInstance или подобной ей. В MFC-приложениях

// можно также использовать функцию AfxOleInit.

CoInitialize(NULL);

// 2. Создание объекта COM с использованием CO-класса Shell Link, поставляемого оболочкой.

// 4-й параметр указывает на то, какой интерфейс нам нужен (IShellLink).

hr = CoCreateInstance(CLSID_ShellLink, NULL, CLSCTX_INPROC_SERVER, IID_IShellLink, (void**)&pISL);

if (SUCCEEDED(hr)) {

 // 3. Устанавливаем путь, на который будет указывать ярлык (к файлу "обоев").

 hr = pISL->SetPath(sWallpaper);

 if (SUCCEEDED(hr)) {

// 4. Получение второго интерфейса (IPersistFile) от объекта COM.

hr = pISL->QueryInterface(IID_IPersistFile, (void**)&pIPF);

if (SUCCEEDED(hr)) {

// 5. Вызов метода Save для сохранения
ярлыка в файл. Первый параметр

// является строкой Unicode.

hr = pIPF->Save(L"C:\\wallpaper.lnk", FALSE);

// 6a. Освобождение интерфейса IPersistFile.

pIPF->Release;

}

 }

 // 6b. Освобождение интерфейса IShellLink.

 pISL->Release;

}

// Где-то здесь должен быть код для обработки ошибок.

// 7. Разинициализация библиотеки COM. В приложениях MFC этого делать

// не нужно, т.к. MFC справляется с этим сама.

CoUninitialize;

Литература

Essential COM, Don Box, ISBN 0-201-63446-5.

MFC Internals, George Shepherd and Scot Wingo, ISBN 0-201-40721-3.

Beginning ATL 3 COM Programming, Richard Grimes, ISBN 1-861001-20-7.

ВОПРОС-ОТВЕТ 

Q. Как в Win9x и WinNT заблокировать клавиши WIN, Alt+Tab, Ctrl+Esc etc.?

Mike Krasnik 

A1 Например так – в конструкторе главного окна приложения зарегистрировать HotKey:

m_HK = GlobalAddAtom("alttab"); // DWORD m_HK;

RegisterHotKey(GetSafeHwnd, m_HK, MOD_ALT, VK_TAB);
 

а в деструкторе не забыть его разрегистрировать: 

UnregisterHotKey(GetSafeHwnd, m_HK);
 

так как никакого обработчика для этого HotKey мы не делаем, то соответственно и происходить по нажатию Alt-Tab ничего не будет.

Алексей Кирюшкин 

A2 По материалам http://msdn.microsoft.com/msdnmag/issues/0700/Win32/Win320700.asp

В WinNT (начиная с Windows NTR 4.0 Service Pack 3) существует возможность использовать "low-level" hook на клавиатуру WH_ KEYBOARD_LL для отключения комбинаций Ctrl+Esc, Alt+Tab, Alt+Esc.

Для данной данной функии установлен лимит времени: Система возвращается в нормальное состояние через промежуток времени определяемый параметром LowLevelHooksTimeout в HKEY_CURRENT_USER\Control Panel\Desktop время указывается в милисекундах.

Владимир Згурский 

A3 Это делается очень по-разному в различных системах от Microsoft.

В Windows 9x можно использовать трюк, опсанный в MSDN – вызвать функцию SystemParametersInfo с недокументированным параметром. В данном случае им можно пользоваться смело: Микрософт больше не будет вносить изменений в архитектуру Win9x. Чтобы отключить Alt+Tab, Ctrl+Alt+Del и т. д., нужно написать: 

int prev;

SystemParametersInfo(SPI_SCREENSAVERRUNNING, TRUE, &prev, 0);
 

Выполняя этот код, мы сообщаем системе, что работает скринсейвер. А когда он работает, переключение задач запрещено. Чтобы включить стандартные комбинации снова, используйте: 

int prev;

SystemParametersInfo(SPI_SCREENSAVERRUNNING, FALSE, &prev, 0);
 

Внимание: если этого не сделать, переключение задач будет невозможно даже после завершения работы вашего приложения! 

Перейдём к Windows NT/2000. Там трюк со скрин сейвером не работает, но зато есть низкоуровневые хуки для мыши и клавиатуры (обычные хуки не перехватывают системные комбинации клавиш). Установив глобальный низкоуровневый хук на клавиатуру, можно "съесть" все системные нажатия (кроме Ctrl+Alt+Del). Для этого в ответ на приход таких нажатий функция хука должна вернуть единицу. 

Как известно, хуки устанавливаются функцией SetWindowsHookEx. В нашем случае требуется глобальный хук, а значит, его код придётся размещать в DLL. DLL может выглядеть примерно так. 

#define _WIN32_WINNT 0x0500

#include <windows.h>

static HINSTANCE hInstance;

static HHOOK hHook;

BOOL APIENTRY DllMain(HANDLE hModule, DWORD ul_reason_for_call, LPVOID lpReserved) {

 hInstance = (HINSTANCE)hModule;

 return TRUE;

}

LRESULT CALLBACK KeyboardProc(INT nCode, WPARAM wParam, LPARAM lParam);

extern "C" __declspec(dllexport) void HookKeyboard {

 hHook = SetWindowsHookEx(WH_KEYBOARD_LL, (HOOKPROC)KeyboardProc, hInstance, 0);

}

extern "C" __declspec(dllexport) void UnhookKeyboard {

 UnhookWindowsHookEx(hHook);

}

LRESULT CALLBACK KeyboardProc(INT nCode, WPARAM wParam, LPARAM lParam) {

 KBDLLHOOKSTRUCT *pkbhs = (KBDLLHOOKSTRUCT*)lParam;

 BOOL bControlKeyDown = 0;

 if (nCode == HC_ACTION) {

bControlKeyDown = GetAsyncKeyState(VK_CONTROL) >> ((sizeof(SHORT) * 8) - 1);

// Проверяем CTRL+ESC

if (pkbhs->vkCode == VK_ESCAPE && bControlKeyDown) return 1;

// Проверяем ALT+TAB

if (pkbhs->vkCode == VK_TAB && pkbhs->flags & LLKHF_ALTDOWN) return 1;

// Проверяем ALT+ESC

if (pkbhs->vkCode == VK_ESCAPE && pkbhs->flags & LLKHF_ALTDOWN) return 1;

 }

 return CallNextHookEx(hHook, nCode, wParam, lParam);

}

Чтобы воспользоваться этой DLL, загрузите её любым способом, а затем вызывайте HookKeyboard, чтобы перехватывать комбинации клавиш, и UnhookKeyboard, чтобы прекратить перехват. 

В ранних версиях NT низкоуровневых хуков не было. В MSDN утверждается, что там от Alt+Tab там можно избавиться с помощью перерегистрации глобального акселератора

на ту же комбинацию (посредством RegisterHotKey), но испытать это средство мне не удалось (нет под рукой NT3.51 или NT4.0 с SP 2 и ниже). Ctrl+Esc там не блокируется. 

Для полноты картины упомяну ещё одно непровереное средство, с помощью которого можно обезвредить Ctrl+Alt+Del под Windows NT/2000. Для этого нужно написать собственную GINA DLL. Если кого-нибудь интересуют подробности, сделайте в MSDN поиск по строке "GINA".

Александр Шаргин 
ОБРАТНАЯ СВЯЗЬ 

Уважаемый Алекс.

Читая Вашу статью о DCOM я прочел:

"Строго говоря, COM не является спецификацией, привязанной к Win32. Теоретически, можно портировать ваши COM-объекты в Unix или любые другие ОС. Однако, я никогда не видел, чтобы COM применялась где-то за пределами сферы влияния Microsoft."

Могу подсказать ОС использующую COM/DCOM не из семейства Windows. Как ни странно это VxWorks, где COM/DCOM существует в виде одного из компонент ядра и обеспечивает все, что может быть положено на концепцию этой ОС.

Например из-за ограничений ОС (там по сути только один процесс с общей памятью, но со многими потоками-задачами) серверы могут быть только INPROC. Не поддержан (пока что) IDispatch, массивы в VARIANT. Зато теперь можно использовать DCOM-распределенные системы на основе смеси Windows и VxWorks, что очень удобно для управления realtime системами.

С уважением

Алексей Трошин 

На вопрос из выпуска №27 о пунктирной рамке вокруг кнопки: 

Предложенный Александром Шаргиным вариант с тулбаром врядли можно признать удовлетворительным. Диалог не получит сообщение от тулбара да и программное создание кнопки… Можно, конечно, но… :-( . Наиболее приемлемый выход – использование самопрорисовывающихся элементов управления. Достоинство этого метода – нарисовать можно всё, что угодно! :-))). А в вопросе Максима Чучуйко есть ещё подвопрос: А должна ли кнопка вообще получать фокус?.

В общем, плоскую кнопку, не получающую фокус совсем сделать достаточно просто:

1) Создаём класс

CFlatButton: public CButton;

2) Добавляем переменные:

protected:

 BOOL bMouseCaptured;

 CWnd* pOldFocus;

В конструкторе инициализируем:

 bMouseCaptured = FALSE;

 pOldFocus = NULL;

3) Добавляем методы:

protected:

 void CFlatButton::SetOldFocus {

// Закомментировать тело метода, если кнопка может получать фокус.

if (pOldFocus) pOldFocus->SetFocus;

pOldFocus =NULL;

}

Добавляем обработчики сообщений:

 void CFlatButton::OnSetFocus(CWnd* pOldWnd) {

CButton::OnSetFocus(pOldWnd);

if (!pOldFocus) // Дабы не было проблем с модальными окнами, вызываемыми по нажатию этой кнопки.

pOldFocus = pOldWnd;

 }

 void CFlatButton::OnLButtonUp(UINT nFlags, CPoint point) {

CButton::OnLButtonUp(nFlags, point);

CRect rectBtn;

GetClientRect(rectBtn);

if (rectBtn.PtInRect(point) && GetCapture != this) {

bMouseCaptured = TRUE;

SetCapture;

Invalidate(FALSE);

}

SetOldFocus;

 }

 void CFlatButton::OnMouseMove(UINT nFlags, CPoint point) {

CRect rectBtn;

GetClientRect(rectBtn);

if (rectBtn.PtInRect(point)) {

BOOL bNeedUpdate =FALSE;

if (!bMouseCaptured) bNeedUpdate = TRUE;

bMouseCaptured = TRUE;

SetCapture;

if (bNeedUpdate) Invalidate(FALSE);

} else {

bMouseCaptured = FALSE;

ReleaseCapture;

SetOldFocus;

Invalidate(FALSE);

}

CButton::OnMouseMove(nFlags, point);

 }

И, самое интересное… :-))) Перекрываем виртуальный метод:

void CFlatButton::DrawItem(LPDRAWITEMSTRUCT lpDIS) {

 // Test WS_TABSTOP

 ASSERT(!(GetStyle & WS_TABSTOP)); 

 CDC* pDC = CDC::FromHandle(lpDIS->hDC);

 CRect rectAll;

 GetClientRect(rectAll);

 CString text;

 GetWindowText(text);

 int save = pDC->SaveDC;

 CRect rectText(rectAll);

 rectText.DeflateRect(2,2);

 CBrush bkBr(GetSysColor(COLOR_3DFACE));

 pDC->FillRect(rectAll,&bkBr);

 UINT state = lpDIS->itemState;

 if (state & ODS_SELECTED) {

// Нажатое состояние

rectText.OffsetRect(1,1);

pDC->DrawEdge(rectAll, BDR_SUNKENOUTER, BF_RECT);

 } else {

if (bMouseCaptured) {

pDC->DrawEdge(rectAll, BDR_RAISEDINNER, BF_RECT);

}

 }

 pDC->DrawText(text, rectText, DT_SINGLELINE|DT_VCENTER|DT_CENTER|DT_TOP);

 pDC->RestoreDC(save);

}

Использование: очень просто. Ставим на шаблоне диалога кнопку, убираем стиль WS_TABSTOP, ставим стиль WS_OWNERDRAW. В ClassWizard'е сопоставляем ей переменную типа CButton, затем тип переменной вручную меняем на CFlatButton. И всё. Далее – как с обычной кнопкой. У меня (VC++ 5.0) – работает.

Дмитрий Сулима
В ПОИСКАХ ИСТИНЫ

Q. Как включать в проект незарегистрированный компонент ActiveX? Вернее он на моей машине зарегистрирован, а на другой нет, и в результате этого программа на той машине вообще не запускается.

Сергей Лобачев

Это все на сегодня. Удачи вам!

Алекс Jenter [email protected] Красноярск, 2000.

Программирование на Visual C++

Выпуск №30 от 28 января 2001 г.

Поделиться:
Популярные книги

Черный Маг Императора 6

Герда Александр
6. Черный маг императора
Фантастика:
юмористическое фэнтези
попаданцы
аниме
7.00
рейтинг книги
Черный Маг Императора 6

Оцифрованный. Том 1

Дорничев Дмитрий
1. Линкор Михаил
Фантастика:
боевая фантастика
попаданцы
аниме
5.00
рейтинг книги
Оцифрованный. Том 1

Кодекс Охотника. Книга XIV

Винокуров Юрий
14. Кодекс Охотника
Фантастика:
боевая фантастика
попаданцы
аниме
5.00
рейтинг книги
Кодекс Охотника. Книга XIV

Штуцер и тесак

Дроздов Анатолий Федорович
1. Штуцер и тесак
Фантастика:
боевая фантастика
альтернативная история
8.78
рейтинг книги
Штуцер и тесак

Я снова граф. Книга XI

Дрейк Сириус
11. Дорогой барон!
Фантастика:
боевая фантастика
попаданцы
аниме
5.00
рейтинг книги
Я снова граф. Книга XI

Болотник

Панченко Андрей Алексеевич
1. Болотник
Фантастика:
попаданцы
альтернативная история
6.50
рейтинг книги
Болотник

Кодекс Крови. Книга III

Борзых М.
3. РОС: Кодекс Крови
Фантастика:
фэнтези
попаданцы
аниме
5.00
рейтинг книги
Кодекс Крови. Книга III

Жестокая свадьба

Тоцка Тала
Любовные романы:
современные любовные романы
4.87
рейтинг книги
Жестокая свадьба

Стеллар. Трибут

Прокофьев Роман Юрьевич
2. Стеллар
Фантастика:
боевая фантастика
рпг
8.75
рейтинг книги
Стеллар. Трибут

Голодные игры

Коллинз Сьюзен
1. Голодные игры
Фантастика:
социально-философская фантастика
боевая фантастика
9.48
рейтинг книги
Голодные игры

Последняя Арена 8

Греков Сергей
8. Последняя Арена
Фантастика:
боевая фантастика
рпг
5.00
рейтинг книги
Последняя Арена 8

Черный маг императора 2

Герда Александр
2. Черный маг императора
Фантастика:
юмористическая фантастика
попаданцы
аниме
6.00
рейтинг книги
Черный маг императора 2

Последний Паладин

Саваровский Роман
1. Путь Паладина
Фантастика:
фэнтези
попаданцы
аниме
5.00
рейтинг книги
Последний Паладин

Измена. Свадьба дракона

Белова Екатерина
Любовные романы:
любовно-фантастические романы
эро литература
5.00
рейтинг книги
Измена. Свадьба дракона