1.9 Приложения — невидимки
Иногда желательно, чтобы приложение, которое постоянно выполняется на фоне выполнения других приложений, не отображалось в полосе задач (см. разд. 1.8) и не занимало там лишнего места. Один из путей создания подовного приложения — это задание перед созданием главной формы соответствующего стиля ее окна.
Стиль окна можно задать функцией SetWindowLongобъявленной в файлеWinUser.hследующим образом:
LONG SetWindowLong(IN HWND hWnd, IN int nIndex, IN LONG dwNewLong);
Параметр hWndявляется дескриптором окна. Если функция должна применяться к еще не созданному окну, в качестве параметраhWndможйо использовать дескриптор приложенияApplication->Handle. ПараметрnIndexзадает относительное смещение в переменной, определяющей стиль. В нашем случае для доступа к расширенному стилю надо задать значеййе,nIndexравнымGWL_EXSTYLE. ПараметрdwNewLongопределяет заменяемые составляющие стиля. Для наших целей надо задать значение (WS_EX_TOOLWINDOW. Это обеспечит отсутствие в полосе задач отображения данного окна и недостижимость приложения при нажатии пользователем. Клавиш Alt+Tab.
Все это может быть оформлено, включением в обработчик события формы OnCreateследующего оператора:
SetWindowLong (Application->Handle, GWL_EXSTYLE, WS_EX_TOOLWINDIW);
Имейте в виду, что если пользователь свернет окно вашего приложения, то:
приложение станет ему недоступным. Точнее, он сможет получить к нему доступ только только через диспетчер задач Windows, вызываемый кларйщймиCtrl+Alt+Del. Из окна диспетчера он сможет переключиться в данное Приложение или закрыть его. Если же вы хотите, чтобы приложение сразу не было видно пользователю и работало «за кадром», то не забудьте в свойстве формыWindowStateзадать значениеwsMinimized.
Возможен и иной вариант создания приложения-невидимки: вместо приведенного выше оператора записать:
Application->ShowMainForm = false;
Тем самым вы делаете главную форму приложения невидимой. Только надо проверить, установлено ли в ней свойство Visibleвfalse. Будьте осторожны! Если приложение работает под управлениемWindows2000\ХР, то приложение будет невидимым не только в полосе задач и по клавише табуляции. Его не будет видно и в диспетчере задачWindows. Запуская приложение в режиме отладки из средыC++Builder, его все-таки можно будет закрыть клавишамиCtrl+F2. Но при запуске просто изWindowsзакрыть это приложение будет невозможно (точнее, можно закрыть, только закрыв соответствующий процесс)! Так что при экспериментах примите меры против этого. Простейший вариант:
поставьте в приложение Timer, и через заданный в нем интервал времени закрывайте приложение методомClose, или хотя бы делайте его видимым методомShow.
Вообще, чтобы в некоторый момент, например, при щелчке на какой-то кнопке превратить ваше приложение в невидимку, достаточно выполнить операторы
Visible = false;
Application->ShowMainForm = false;
1.12 Панель Управления и ее апплеты:
свойства экрана, свойства системы и другие
Панель Управления реализована файлом Control.exe. Так что вызвать Панель Управления из своего приложения можно любой функцией, обеспечивающей вызов исполняемого файла:ShellExecute,WinExec,CreateProcess. Например, оператором:
ShellExecute(Handle, NULL, “Control.exe”, “”,NULL, SW_SHOWNORMAL);
или оператором
WinExec(“Control.exe”,SW_RESTORE);
В результате выполнения любого из этих операторов на экране появится окно Пааели Управления, в котором пользователь сможет выбрать нужную ему составляющую — апплет. Но можно .сразу из приложения вызывать соответствующий йпплет, применив для вызова те же функции и передав в них через командную строку имя файла апплета. Например:
ShellExecute(Handle, NULL, “Control.exe”, “AppletName”, NULL, SW_SHOWNORMAL);
ИЛИ
WinExec(“Control.exe AppletName”, SW_RESTORE);
Здесь AppletName—Строка с именем файла апплета. Ниже приведена таблица некоторых наиболее часто используемых апплетов вWindows2000\ХР. В других версияхWindowsнекоторые из этих апплетов отсутствуют, но такие основные, как Свойства экрана. Свойства системы и ряд других присутствует всегда.
Имя файла
Открывающееся окно
|
Имя файла |
Открывающееся окно |
|
Appwiz.cpl |
Установка и удаление программ |
|
Bdeadmin.cpl |
BDEАдминистратор |
|
Desk.cpl |
Свойства Экрана |
|
Hdwwiz.cpl |
Мастер установки оборудования |
|
Ibmgr.cpl |
InterbaseManager |
|
Inetcpl.cpl |
Свойства Интернет |
|
Intl.cpl |
Язык и региональные стандарты |
|
Mmsys.cpl |
Свойства: Звуки и аудиоустройства |
|
Ncpa.cpl |
Сетевые подключения |
|
Nusrmgr.cpl |
Учетные записи пользователей |
|
Odbcpp32.cpl |
Администратор источников данных ODBC |
|
Sysdm.cpl |
Свойства системы |
|
Timedate.cpl |
Свойства: Дата и время |
Например, вызов окна Свойства системы может иметь вид:
ShellExecute(Handle, NULL, “Control.exe”, “sysdm.cpl”, NULL, SW_SHOWNORMAL);
В ряде случаев возникает задача учесть в приложении результаты действий, предпринятых пользователем при работе с окном апплета. Наиболее простым способом реализации этого была бы задержка выполнения приложения до того момента, когда пользователь закончит работать с диалоговым окном апплета. Задержку выполнения приложения до завершения порожденного процесса обеспечивает в большинстве случаев сочетание функций CreateProcessиWaitForSingleObject(см. разд. 3.2). Но в данном случае это не проходит. Дело в том, что запускается процесс, связанный с файломControl.exe, и он завершается после того, как вызван апплет, а вовсе не после завершения работы с апплетом. Одним из вариантов, обеспечивающих обработку результатов работы пользователя с апплетом, является реализация обработчика событияWM_ACTIVATE. Это событие наступит, в частности, после того, как пользователь закроет диалоговое окно апплета, и управление вернется в окно приложения.
1.15 Даты и время в API Windows и С++Builder
1.15.1 Форматы представления дат и времени
Начнем с обзора форм представления дат и времени в C++Builderи в APIWindows. В С++Builderосновная форма хранения дат и времени — типTDateTime. Это действительное число» в целой части которого хранится дата, а в дробной — время в виде дробной части суток. Для 32-разрядных версий С++Builderза начало календаря принята дата 00 часов 30 декабря 1890 года. Прибавление к значению типаTDateTimeцелого числаDравносильно увеличению даты наDдней. Разность двух значений типаTDateTimeдает разность двух дат с точностью до долей дня. Для вычисления разности двух дат в годах могут использоваться функцииYearsBetweenиYearSpan, объявленные в файлеDateUtils.hpp:
int _fastcall YearsBetween(const System:: TdateTime ANow,
const System:: TdateTime Athen);
double _fastcall YearSpan(const System:: TdateTime ANow,
const System:: TdateTime Athen);
Функции возвращают число лет между двумя значениями даты и времени ANowиAThenтипаTDateTime. ФункцияYearsBetweenвозвращает число полных лет между двумя значениями. А функцияYearSpanвозвращает действительное число, содержащее дробную часть, отображающую неполный год.
Хотя годы (високосные и не високосные) имеют разную продолжительность, функции YearsBetweenиYearSpanэто не учитывают и исходят из усредненного значения 365.25 дней в, году.
Приведенный ниже оператор отображает возраст (полное число лет) человека, год рождения которого записан в переменной Вот:
Label1->Caption = IntToStr(YearsBetween(Date(), Born))
Функция YearsBetweenобъявлена в файлеDateUtils.hpp, который надо подключить к модулю:
#include <dateutils.hpp>
Впрочем, можно обойтись и без функции YearsBetween, определяя возраст оператором:
Label1->Caption = IntToStr((int) ((double) (Date() – Born) /365.25)));
Тогда и файл DateUtils.hppподключать не надо.
Иногда при необходимости высокой точности представления времени используется тип TTimeStamp, объявленный, в файлеDateUtils.hpp:
Struct TtimeStamp
{
intTime; // число миллисекунд с начала дня
intDate; // 1+ число дней с 1/1/1001
} ;
Этот тип используется в случаях, когда требуется повышенная Точность
отображения времени с учетом миллисекунд. Аналогичную точность дает тип
TSQLTimeStamp, объявленный в файлеSqlTimSt.hpp:
Struct TSQLTimeStamp
{
short Year;
Word Month;
Word Day;
Word Hour;
Word Minute;
Word Second;
Unsigned Fractions;
} ;
Поле Year— год, который может принимать значения от 1 до 9999. ПолеMonth— месяц (от 1 до 12). ПолеDay— день месяца (от 1 до 28, 29, 30 или 31 в зависимости от месяца). ПолеHour— час (от 0 до 23). ПоляMinuteиSecond— минуты и секунды (от 0 до 59). ПолеFractions—миллисекунды (от 0 до 999).
Для взаимного преобразования этих типов используются функции DateTimeToTimeStamp,TimestampToDateTime,DateTimeToSQLTimeStamp,SQLTimeStampToDateTime. Не будем на них останавливаться. Вы можете посмотреть их описания во встроенной справкеC++Builderили в справке [4]. \
В API Windowsиспользуются иные формы хранения дат и времени. ТипTSystemTime(_SYSTEMTIME) описывает структуру, поля которой содержат элементы даты и времени, начиная с года и до миллисекунды.
Непосредственное сложение или вычитание значений типа TSystemTimeне рекомендуется. В APIWindowsрекомендуется для подобных операций перевести сначала значение в форме _SYSTEMTIMEв структуру типа __FILETIME, которая будет описана далее, затем преобразовать ее в структуру типа _LARGE_INTEGER, а уже с этой структурой можно осуществлять арифметические операции. Однако вC++Builderимеется более простой способ— функцияSystemTimeToDateTime:
System::TdateTime _fastcall SystemTimeToDateTime(
Const _SYSTEMTIME &SystemTime);
Функция переводит значение и тип ТDateTime, к которому можно применять арифметические операции. ФункцияDateTimeToSystemTimeпереводит значение типаTDateTimeв типTSystemTime:
Void _fastcall DateTimeToSystemTime( const System:: TDateTime DateTime,
_SYSTEMTIME&SystemTime
Получить текущую дату и время в формате TSystemTimeможно с помощью функций
GetLocalTimeиGetSystemTime
Первая из них заносит в запись TSystemTimeинформацию о текущем локальном времени, а вторая заносит в запись информацию о стандартном времени — времени по Гринвичу.
Функции GetLocalTimeиGetSystemTimeпозволяют установить локальное и системное время на компьютере: .
Для отображения дат и времени, используемых в файловойсистеме (создание файла, его последнее открытие и изменение), а также в таймерах ожидания (см.разд. 3.6) используется тип TFileName(_FILENAME);
В структуре этого типа хранится время в сотнях наносекунд, отсчитываемое от 1 января 1601 г. Взаимный перевод типов TFileNameиTSystemTimeосуществляется функциямиTsystemTimeToTsystemTimeиTSystemTimeToTSystemTime:
Можно также написать собственную небольшую функцию, переводящую тип FILETIMEв одно 64-разрядное число:
__int64 FiletimeToint64(FILETIME F)
{
return Int64ShllMod32(F.dwHighDateTime, 32) | F.dwLowDateTime;
}
В этой функции использован вызов функции Int64ShllMod32, который сдвигает числоF.dwHighDateTimeв старшие разряды возвращаемого значения и добавляетF.dw.LowDateTimeв младшие разряды. Таким образом, функцияFiletimeToint64 возвращает в виде числа сотен наносекунд время, записанное в переданном в нее параметреF. А далее к таким числам можно применять любые арифметические операции.
Выше упоминалась структура _LARGE_INTEGER, в которую можно переводить данные, заданные структурами типа _SYSTEMTIMEи _FILETIME, чтобы осуществлять с ними арифметические действия. Указывалось также, что, работая с С++Ввд1аег, можно обойтись без этих преобразований. Тем не менее, некоторые функции API "УУтаоута требуют параметры именно типа _LARGE_INTEGER. Ниже приводится объявление этого типа:
typedef union _LARGE_INTEGER {
struct {
DWORD LowPart;
LONG HighPart;
};
LONGLONG QuadPart;
} LARGE_INTEGER;
Эта структура, хранящая время в сотнях наносекунд, является объединением, которое хранит данные или в 64-разрядном поле QuadPart, или, если компилятор не поддерживает 64 бита, то в поляхLowPartиHighPart. Эти поля эквивалентны полямdwHighDateTimeиdwLowDateTimeструктуры типаTFileTime(_FILETIME). Но в этих двух видах структур выравнивание осуществляется не одинаково. Так что явным образом приводить эти типы друг другу нельзя. Точнее — опасно: может сработает, а может и нет. При необходимости такого преобразования надо просто копировать соответствующие поля из одной структуры в другую.
Особым образом хранится информация о времени, связанном с файлами, в MSDOS. Для преобразования этого времени между форматовDOSиTfileTimeслужат функцииDosDateTimeToFileTimeиFileTimeToDosDateTime.
