BITS Manager v1.02.005
- Refactored General page layout.
- Refactored Aux page layout.
- Refactored Proxy settings dialog layout.
- Added proxy authentication support.
- Added HTTP authentication support.
- Program size and distribution size are reduced.
Очередная версия BITS Manager. Окно Job profile обзавелось еще одной закладкой. Правильно работает сортировка по полям-перечислениям. Улучшена обработка ошибок. Заголовки полей ввода реагируют на изменение содержимого.
Кстати, размер инсталлятора приближается к психологическому
барьеру в 10 мегабайт. Где дальше выкладывать это дело - пока непонятно.
Download BITS Manager v1.02.0004
Next version: BITS Manager v1.02.005.
Очередная версия BITS Manager. Окно Job profile опять пострадало
- появились закладки с разными частями профиля задачи. Исправил несколько ошибок. Заголовок списка задач обзавелся менюхой и возможностями по группировке, сортировке и т.д. Появилась возможность менять настройки безопасности HTTP, а также устанавливать дополнительные HTTP заголовки.
Download BITS Manager v1.02.0003
Next version: BITS Manager v1.02.0004.
Очередная версия BITS Manager. Список задач пополнился двумя колонками - Created и Modified/Completed. Окно Job profile также пострадало
- добавились поля Created и Modified, изменилось расположение элементов управления. Появились информативные подсказки. Реализована функциональность Take Ownership (кнопка TO), а также полноценный редактор настроек proxy!
Download BITS Manager v1.02.0002
Next version: BITS Manager v1.02.0003.
Очередная версия BITS Manager. Теперь с возможностью посмотреть список файлов задачи. Добавил Caption Bar, в котором сейчас отображается версия службы Background Intelligent Transfer Service.
Download BITS Manager v1.02.0001
Next version: BITS Manager v1.02.0002.
Очередная версия BITS Manager. Теперь с возможностью посмотреть профиль задачи, изменять некоторые параметры и характеристики задачи, закреплять задачи
. Также визуальное барахло - иконки, тултипы. Список файлов задачи пока что не отображается. Заблокированы некоторые элементы управления в окене Job profile. To be continued, короче. Забыл, добавлена обработка ошибок!
Download BITS Manager v1.02.0000
Next version: BITS Manager v1.02.0001.
В рамках моего мини-проекта
BITS Manager решил сделать удобный и красивый диалог. Основная изюминка - заголовки элементов управления, которые меняют свой внешний вид в зависимости от движения фокуса. Если конкретнее - меняется шрифт у заголовка активного элемента:
В процессе воникла проблема - как перехватить все события от фокуса дочерних элементов управления в одном месте? Добавлять по обработчику на каждый контрол - не очень хорошая идея. Тем более, что код, модифицирующий внешний вид заголовков, вполне обобщенный.
Я увидел следующие решения данной проблемы:
WM_SETFOCUS
и WM_KILLFOCUS
.
Проверять принадлежность целевого окна интересующему диалогу и, соответственно, обрабатывать нужным образом.
Ловушка WH_CBT
с кодом HCBT_SETFOCUS
позволяет отловить момент, когда система собирается установить фокус на окно. Это хорошо, но пришлось бы сохранять и обновлять идентификатор окна, которое будет терять фокус. Можно использовать и другие ловушки для перехвата сообщений WM_SETFOCUS
и WM_KILLFOCUS
.
***_SETFOCUS
и ***_KILLFOCUS
.Я остановился на 3-м варианте, первые два мне показались черезчур сложными для такой задачи.
Пришлось слегка
почитать документацию и покопаться в коде MFC. Итак, есть два типа элементов управления. Первый тип использует сообщение WM_NOTIFY
для уведомления родителя, второй тип использует WM_COMMAND
. Оказалось, MFC в любом случае вызывает виртуальный метод BOOL OnCmdMsg(UINT nID, int nCode, void *pExtra, AFX_CMDHANDLERINFO *pHandlerInfo)
. После медитаций у меня получился такой код:
BOOL CJobProfileDlg::OnCmdMsg(UINT nID, int nCode, void *pExtra, AFX_CMDHANDLERINFO *pHandlerInfo) { const MSG &lastSentMsg = AfxGetThreadState()->m_lastSentMsg; LPCTSTR szEditClass = _T("EDIT"); LPCTSTR szComboBoxClass = _T("COMBOBOX"); LPCTSTR szListBoxClass = _T("LISTBOX"); if ( ((nCode == EN_KILLFOCUS) && Utility::CompareWindowClass(reinterpret_cast<HWND>(lastSentMsg.lParam), szEditClass)) || ((nCode == CBN_KILLFOCUS) && Utility::CompareWindowClass(reinterpret_cast<HWND>(lastSentMsg.lParam), szComboBoxClass)) || ((nCode == LBN_KILLFOCUS) && Utility::CompareWindowClass(reinterpret_cast<HWND>(lastSentMsg.lParam), szListBoxClass)) || ((HIWORD(nCode) == WM_NOTIFY)) && (LOWORD(nCode) == LOWORD(NM_KILLFOCUS))) { OnControlLostFocus(nID); } if (((nCode == EN_SETFOCUS) && Utility::CompareWindowClass(reinterpret_cast<HWND>(lastSentMsg.lParam), szEditClass)) || ((nCode == CBN_SETFOCUS) && Utility::CompareWindowClass(reinterpret_cast<HWND>(lastSentMsg.lParam), szComboBoxClass)) || ((nCode == LBN_SETFOCUS) && Utility::CompareWindowClass(reinterpret_cast<HWND>(lastSentMsg.lParam), szListBoxClass)) || ((HIWORD(nCode) == WM_NOTIFY) && (LOWORD(nCode) == LOWORD(NM_SETFOCUS)))) { OnControlGotFocus(nID); } return(__super::OnCmdMsg(nID, nCode, pExtra, pHandlerInfo)); }
Здесь я долго пытался понять, почему иногда не работает, и в результате боролся с двумя проблемами:
#define CBN_KILLFOCUS 4 #define LBN_SETFOCUS 4
В итоге пришлось добавить еще код проверки класса окна.
#define NM_FIRST (0U- 0U) // generic to all controls #define NM_SETFOCUS (NM_FIRST-7) #define NM_KILLFOCUS (NM_FIRST-8)
MFC пакует два значения в одно с помощью MAKELONG
, в результате чего отрицательные значения NM_***
после извлечения теряют старшее слово. Нужно при сравнении обрезать оба операнда.
Приведу весь код для потомков:
bool Utility::CompareWindowClass(HWND hwnd, LPCTSTR pszWindowClass) { const int cch = _tcslen(pszWindowClass) + 1; LPTSTR pszClassName = reinterpret_cast<LPTSTR>(_alloca(sizeof(TCHAR) * cch)); if (GetClassName(hwnd, pszClassName, cch)) { if (_tcsncicmp(pszClassName, pszWindowClass, -1) == 0) return(true); } return(false); } void CJobProfileDlg::OnControlGotFocus(UINT nID) { CWnd *pStatic = GetDlgItem(nID)->GetNextWindow(GW_HWNDPREV); if (pStatic && Utility::CompareWindowClass(pStatic->m_hWnd, _T("STATIC"))) pStatic->SetFont(&m_fntStaticActive); } void CJobProfileDlg::OnControlLostFocus(UINT nID) { CWnd *pStatic = GetDlgItem(nID)->GetNextWindow(GW_HWNDPREV); if (pStatic && Utility::CompareWindowClass(pStatic->m_hWnd, _T("STATIC"))) pStatic->SetFont(&m_fntStatic); }
Предполагается, что порядок обхода задан таким образом, что заголовок элемента управления предшествует ему.
Новая версия BITS Manager. Позволяет управлять состоянием задач, а также менять их приоритеты. Появился простенький About.
Download BITS Manager v1.01.000
InstallShield, как обычно, радует - upgrade с предыдущей версии не работает. Нужно ее вручную удалить. Также нежелательно запускать инсталлятор прямо из архива.
Next version: BITS Manager v1.02.0000.
Представляю вашему вниманию первую версию утилиты по управлению службой Background Intelligent Transfer Service (BITS).
Программа отображает активное состояние очереди задач. Управлять задачами пока еще нельзя. Скачать установщик можно здесь.
Программа, кстати, отображает список задач всех пользователей, если ее запустить из-под администратора.