Как сплагиатить удобную утилиту для показа зарядки ноутбука?

    Всё началось с того что я увидел утилиту от IBM/Lenovo для показа заряда батареи ноутбука в непривычном месте — в таскбаре/супербаре, но не в виде значка, а как панель(аналогичные используются для управления проигрывателями iTunes, WMP, Zune):



    Т.к. у меня ноутбуки другого производителя, а искать как выцарапать эту софтину у производителя мне было лень — я начал искать аналог, и, к преглубокому удивлению, ничего не нашел! (если я не прав — покажите носом, буду весьма благодарен!)

    Именно так я решил написать своё решение. Писать будем на C++. Я писал в Visual Studio 2010, можно использовать предыдущие версии. Главное — наличие установленного Windows SDK(ставится отдельно от студии, доступен бесплатно, скачать можно например тут)

    Вот что у меня получилось:

    Моя панелька

    Больше всего времени у меня занял поиск в интернете названия собственно того куда я хотел запихать отображение данных. Оно называется DeskBand, и что самое хорошее — в Windows SDK есть пример работы его! (у меня он по адресу C:\Program Files\Microsoft SDKs\Windows\v7.0\Samples\winui\shell\shellextensibility\deskbands).

    Далее дело стояло за малым — надо найти как получать информацию о заряде батареи. Поисковик в сочетании с MSDN навёл меня на полезную функцию — RegisterPowerSettingNotification. Её минус — она поддерживается только начиная с Windows Vista, но меня это не останавливало, т.к. я писал для себя и лично я уже везде пользуюсь Windows 7.

    Вот её синтакс:

    Copy Source | Copy HTML
    1. HPOWERNOTIFY WINAPI RegisterPowerSettingNotification(
    2. __in HANDLE hRecipient,
    3. __in LPCGUID PowerSettingGuid,
    4. __in DWORD Flags
    5. );
    6.  


    Эта функция поддерживает как работу в сервисах так и в обычных приложениях(чем мы и воспользуемся).

    Для начала я скопировал пример работы с DeskBand в отдельную папку и начал его править.

    Вызываю я её в обработчике события WM_CREATE вот так:

    Copy Source | Copy HTML
    1. h1 = RegisterPowerSettingNotification(pDeskBand->m_hwnd, &GUID_ACDC_POWER_SOURCE, DEVICE_NOTIFY_WINDOW_HANDLE);
    2. if (h1== 0) pDeskBand->CloseDW(1);
    3.  
    4. h2 = RegisterPowerSettingNotification(pDeskBand->m_hwnd, &GUID_BATTERY_PERCENTAGE_REMAINING, DEVICE_NOTIFY_WINDOW_HANDLE);
    5. if (h2== 0)
    6. {
    7. UnregisterPowerSettingNotification(h1);
    8. pDeskBand->CloseDW(1);
    9. }
    10.  
    11.  


    h1 и h2 — глобальные(ногами не бить!) переменные типа HPOWERNOTIFY, что есть те же HANDLE по сути своей.
    Так мы подписались на получение событий вставки/вынимания кабеля зарядки и изменения оставшегося процента батареи. Так же можно подписаться и на изменение схемы питания используя GUID_POWERSCHEME_PERSONALITY.
    Кстати, не забудьте в деструкторе например сделать UnregisterPowerSettingNotification для h1 и h2.

    Так же я завёл глобальные(только не по почкам!) переменные для хранения заряда батареи и статуса зарядки:
    Copy Source | Copy HTML
    1. bool isOnBattery=false;
    2. int charged=-1;
    3.  


    И в обработчике приходящего события WM_POWERBROADCAST:

    Copy Source | Copy HTML
    1. POWERBROADCAST_SETTING* pps = (POWERBROADCAST_SETTING*)lParam;
    2. if ( sizeof(int) == pps->DataLength && pps->PowerSetting == GUID_ACDC_POWER_SOURCE )
    3. {
    4. int nPowerSrc = *(int*)(DWORD_PTR) pps->Data;
    5. isOnBattery= ( 0 != nPowerSrc);
    6. }
    7. else if ( sizeof(int) == pps->DataLength && pps->PowerSetting == GUID_BATTERY_PERCENTAGE_REMAINING )
    8. {
    9. charged = *(int*)(DWORD_PTR) pps->Data;
    10. }
    11. pDeskBand->OnPaint(NULL);
    12.  


    Что сие делает? При получении события WM_POWERBROADCAST в lParam передается указатель на структуру POWERBROADCAST_SETTING, которую мы и получаем. Т.к. сама эта структура тоже в меру извращенная, то мы смотрим какому событию соответствует именно эта заполненная структура.

    Далее если это событие подключения зарядки — то мы смотрим что получилось. 0 — это батарея, 1 — зарядка, 2 — UPS(ни разу не видел чтобы сабж где-то засветился). Ну и сохраняем результат в переменную isOnBattery(true — если от батареи, false — иначе).

    Если же это событие изменения % зарядки батареи — то сохраняем уровень зарядки себе. Далее вызываем перерисовку.

    Для начала надо определиться что будем рисовать. Мне было лень искать красивые картинки батареек, поэтому я решил просто вывести красиво текст. Так что сначала я формирую строку:

    Copy Source | Copy HTML
    1. wchar_t* arr = (wchar_t*)malloc(1024); //не забудьте потом сделать free(arr);
    2. if (charged>=0)
    3. _itow(charged, arr,10);
    4. else
    5. wcscpy(arr,L"?");
    6. wcscat(arr,L"%");
    7. if (!isOnBattery) wcscat(arr,L" (+)");
    8.  


    Далее не забываю сказать, что я вообще-то перерисовываюсь…

    Copy Source | Copy HTML
    1. InvalidateRect(m_hwnd,&rc,true);
    2.  


    Далее два случая — включена композиция рабочего стола или нет. Т.к. я старой темой Windows не пользуюсь и предпочитаю Aero — то в случае отключенной композиции просто вывожу текст:

    Copy Source | Copy HTML
    1. SetBkColor(hdc, RGB(255, 255, 0));
    2. GetTextExtentPointW(hdc, arr, wcslen(arr), &size);
    3. TextOutW(hdc, (RECTWIDTH(rc) - size.cx) / 2, (RECTHEIGHT(rc) - size.cy) / 2, arr, wcslen(arr));


    В случае включенной композиции немного сложнее:

    Copy Source | Copy HTML
    1. DTTOPTS dttOpts = {sizeof(dttOpts)};
    2. dttOpts.dwFlags = DTT_COMPOSITED | DTT_TEXTCOLOR | DTT_GLOWSIZE;
    3. int red= 0;
    4. int green= 0;
    5. if (charged> 0)
    6. {
    7. if (charged>66) green = 255;
    8. else if (charged>33) green = red = 255;
    9. else red = 255;
    10. }
    11. dttOpts.crText = RGB(red, green,  0);
    12. dttOpts.iGlowSize = 10;
    13.  
    14. DrawThemeTextEx(hTheme, hdcPaint,  0,  0, arr, -1,  0, &rcText, &dttOpts);


    Собственно, тут я считаю, каким цветом рисовать зарядку(66-100% = зеленый, 33-66% = желтый, 0-33% = красный), и вывожу, соответственно, текст.

    Вот и собственно всё. Можно собирать проект.
    Хочу отметить, что тут я не указывал тот код, что был в примере, только тот, что изменялся или дописывался мной.
    После успешной сборки проекта я получил dll-ку.

    По опыту работы с COM-компонентами и подобной гадостью — я выполнил от админа следующую комманду в папке с полученной DLL-кой:
    regsvr32 DeskbandSDKSample.dll


    Далее я просто включил соответствующую панель через контекстное меню.

    Вот и всё.

    Вопросы?

    Similar posts

    Ads
    AdBlock has stolen the banner, but banners are not teeth — they will be back

    More

    Comments 40

      +2
      Внешне не очень красиво.
        +3
        Для меня важна информативность :)
        Допилить красивости для сабжа уже не очень сложно — непаханное поле для тех кому будет интересно тоже попробовать сабж сделать. Могу даже кому-либо подсказазать что/как, помочь делом/советом.
          +2
          мне наоборот понравилось! на черном фоне смотрится отлично!
            0
            Ага. Вроде просто, но симпатично :)
          0
          Статья полезная и интересная, разве что код бы подсветить…
            0
            Согласен. Подсветка кода важна. Так же не понял — либо тут не все картинки вставились, либо странный стиль описания. После «В перерисовке:» явно чего то не хватает.
            И если сами знаете что использовать глобальные переменные плохо, то зачем это делаете?
              0
              Странный стиль описания.

              Потому что пишу для себя, и хочется написать побыстрее, а не получше(я вообще не думал что потом буду статью на хабр писать, вначале писал просто с целью — в IBM смогли такое сделать, а чем я хуже? я тоже такую приблуду хочу!). Ну лень мне лезть в .h файл, создавать новую переменную-член класса, и потом к ней обращаться…
                +7
                Мой совет: Кирилл, забудьте слово лень! Навсегда. В программировании его вообще быть не должно. Ваше предложение может сыграть плохую роль в найме на работу — кто-нибудь посмотрит на ваше предложение и скажет — ага «быстро = некачественно» — не пойдет. В любом случае быстро нужно написать или небыстро — качественный код залог успеха, и с какого-то момента — качество даст и прирост в скорости. Не знаю работаете ли вы сейчас или нет, но мой совет — раз знаете как переписать, чтобы было хорошо — сделайте, а хороший код, где то хранящийся — всегда можно показывать как резюме.
                  +1
                  Застыдили :-[
                  Вообще я пишу нормально когда не для себя…
                  Эх, последую вашему совет, спасибо :)
                    +1
                    Я вам отвечу словами одного фрилансера (не знаю, его ли фраза, но очень по делу): «Быстро, качественно, недорого! Выбирайте любые два.»
              +1
              А где ссылка на готовую софтинку?
                0
                А надо? Я конечно могу готовую длл-ку выложить, сделаете себе regsvr32 для неё, но за последствия я не отвечаю %)
                Статья больше мануал/поиск советов чем «Я пиарюсь» :)
                  0
                  Я б тоже от такой софтинки под XP не отказался
                0
                Спасибо, довольно познавательно :)

                ps. встречают по одежке click-click
                  0
                  Спасибо, оформил :)
                  +2
                  Notebook Hardware Control (бывший Centrino Hardware Control) так умеет:
                    0
                    Спасибо! А он бесплатный?
                      0
                      Бесплатный. Правда, насколько я понял, проект более не развивается.
                      Гугл находит версию 2.0 за 2007 год на разных ресурсах, но оффсайта я так и не нашел.
                      Завтра попробую. Боюсь, что на современных буках некоторые фишки будут недоступны. А там много чего есть, судя по описанию.
                        0
                        Официальный сайт похоже сломался, хотя whois говорит, что домен оплачен до 2011 года.
                          0
                          У меня открылся, уже качаю софтинку )
                    +5
                    Не холивара ради, и не для оскорбления автора (автор действительно постарался), а для подтверждения истины и расширения кругозора Хабропользователей:

                    На сегодняшний день, лучшую реализацию чем в макбуках не видел.
                    Это харварная кнопочка с левого торца. При её нажатии — на линеечке из восьми диодов показывается уровень разряда аккумулятора. При этом состояние компьютера может быть выключено.

                    Ведь на самом деле не стОит хардваные функции выносить в софтверную реализацию. Аккумулятор — аппаратная часть компьютера и место его мониторингу — так же на корпусе, в виде аппаратного блока. Тут я с дизайнерами эпла согласен полностью.
                      0
                      Сзади на батарейках подобное давно есть. Сбоку — да, клёво. Если вы спонсируете мне макбук — я с радостью соглашусь что это здорово :) А пока что — попользуюсь софтом. :)
                        –5
                        1. лечить
                        2. это не апл придумала, такие же решения есть и у Dell и прочих
                        3. хардварное решение и софтверное имеет разные цели. Ты их путаешь

                        и да, у меня есть юни прошка, но мой разум не порабощен ху*ней.
                          +3
                          1. извините, не понял кого или что лечить.
                          2. я не писал что это придумала эпл. Я написал «лучшую реализацию чем в макбуках не видел». Я рад за делл. Кстати интересно кто это придумал.
                          3. Согласен про разнонаправленность целей. Не уверен что что то путаю.

                          Рад за ваш ноут. :)
                            –1
                            я все это написал к тому, что ваш коммент бессмысленен. Так же ты мог написать про датчик заряда на промышленых упсах. Предназначение у софтверного и хардверного индикаторов — разная, пусть и показывают одно и тоже. Софт: для рабочего состояния. Хард: для походного.

                            У IBM/Lenovo какой-то 5хх-ой красные индикаторы расположены сзади и отражаются от изогнутой глянцевой поверхности крышки монитора — тут и головой вертеть не надо, чтобы уровень увидеть.

                            мой ноут — не многим лучше моих предыдущих. А по сути отчасти уныл.
                          0
                          Ведь на самом деле не стОит хардваные функции выносить в софтверную реализацию. Аккумулятор — аппаратная часть компьютера и место его мониторингу — так же на корпусе, в виде аппаратного блока. Тут я с дизайнерами эпла согласен полностью.

                          То есть, по вашему, стоит снести любое ПО, вроде SpeedFan, HWMonitor, etc и по выносить хардварные тахометры и датчики температур?
                            0
                            У меня как раз макбук, и мне такая проверка % батареи не очень удобна, поскольку приходиться или наклоняться, или ноутбук поворачивать чтобы посмотреть заряд батареи, намного быстрее на мониторе посмотреть.
                            Это кнопочка удобна только когда ноут выключен, или в сумке лежит.
                            0
                            Чтож, с почином! Хотя во многом я присоединяюсь к комментариям outcoldman — совершенно верные мысли.
                              0
                              С почином? Ну это вроде не первая статья у меня уже… Ну да ладно))) Спасибо)
                                0
                                А я имел ввиду «с почином на сегодня», удачных тебе постов! Ж:-)
                              +1
                              Вот эта батарейка отдельно: osirisdevelopment.com
                              Есть бесплатная версия (в платной там изыски с расчетом времени автономной работы).
                                0
                                Симпатичненько! Спасибо большое, попробую сабж! :)
                                0
                                Попробуйте Notebook BatteryInfo:
                                  +3
                                  Извиняюсь за оффтоп, но только прочтя половину комментариев, заметил, что ник у автора не XaocCPS. Бес Аватар попутал…
                                    0
                                    Microsoft Tag в массы :)
                                    0
                                    osirisdevelopment.com/BatteryBar/
                                    разрядка:

                                    зарядка:
                                      0
                                      Скрины в jpeg. No way!
                                        0
                                        Возможно автору будет интересно посмотреть как Lenovo отрисовала свои утилиты под Windows7:

                                      Only users with full accounts can post comments. Log in, please.