Laptop Lenovo i niedziałający Bluetooth pod Windowsem 8.1

Czy można się zagapić, tworząc oprogramowanie do laptopa własnej produkcji na tyle, żeby zapomnieć o wsparciu urządzenia Bluetooth? Oczywiście, że można. Lenovo jest tego doskonałym przykładem. Historia jest krótka – parę miesięcy temu, przeniosłem się z Windowsa 7 na 8.1. Sterowniki zainstalowane, oprogramowanie również, wszystko działa. Wszystko działało do czasu, gdy potrzebowałem uruchomić funkcję Bluetooth. No i tu się pojawił problem. Windows o bluetooth nic nie wie, a przycisk do przełączania Wi-Fi/Bluetooth włącza tryb samolotowy, który mnie totalnie w tym momencie nie satysfakcjonuje.

Po przeglądnięciu internetów, znalazłem tylko jedno „rozwiązanie”, paskudnie określone mianem „workaround”. Otóż należało zainstalować „Lenovo Energy Management” w wersji dla Windowsa 7. W trakcie instalacji, Windows dosłownie błagał mnie na kolanach, żebym nie instalował wersji niezgodnej z systemem. Byłem nieugięty. Po instalacji okazało się, że jednak Bluetooth w komputerze mam i, co najlepsze, mogę go włączyć! Irytował mnie tylko fakt, że działałem na starej wersji, która faktycznie kiepsko zgrywała się z nowszym Windowsem. Więc postanowiłem pogrzebać na własną rękę i znaleźć lepsze rozwiązanie.

A wszystko to, bo Ciebie DLL

Czy wiecie czym są DLL’ki? To są takie fajne biblioteki z funkcjami, które można dołączać do programów. Zamiast kompilować program z wbudowaną biblioteką, można ją wydzielić właśnie w postaci pliku DLL. Taka biblioteka może zawierać zestaw pewnych, przydatnych narzędzi, które następnie wykorzystywane są przez programistów w aplikacjach. Czujecie do czego zmierzam? Gdzieś w głowie kołatała mi się myśl, że programiści z Lenovo również trzymają swoje API w jakiejś bibliotece, a potem wykorzystują to w różnych wersjach programu. Nie myliłem się.

W folderze programu Lenovo Energy Management, znalazłem bibliotekę o bardzo intrygującej nazwie – LenovoEmExpandedAPI. Jest akronim API, czyli jakieś funkcje. Robi się ciekawie. Żeby sprawdzić, jakie funkcje udostępnia biblioteka, można wykorzystać program DLL Export Viewer. Wczytujemy w nim powyższą bibliotekę i patrzymy co tam siedzi.

DLL Export Viewer

Wow! Ile tego jest! I same ciekawe rzeczy! Ale skupmy się na funkcji „SetBluetooth”. Wygląda na to, że wystarczy ją wywołać i Bluetooth powinien się włączyć. I tutaj pewnie wielu z Was zada dwa pytania:

  1. Jak ją wywołać?
  2. Jakie parametry?

Odpowiadając na pierwsze pytanie – jest kilka sposobów. Bardzo wygodny w tym przypadku był Python i biblioteka ctypes. Można również napisać program w C (albo innym języku), który będzie korzystał z tej biblioteki.

Co do drugiego pytania – trzeba się domyślić, chociaż nie zawsze to wystarcza. O ile w przypadku funkcji SetBluetooth, wystarczające było przekazanie w parametrze „0” albo „1” (czysto logiczne wnioskowanie), tak funkcja GetBluetoothStatus wcale nie zwraca statusu Bluetooth jak można przypuszczać. Ale o tym potem. Na razie trzeba Bluetooth włączyć i ja dokonałem tego przy użyciu Pythona. Otworzyłem konsolę Pythona w folderze z biblioteką i wpisywałem następujące instrukcje:

I już? Tak! Piękna Pythona nie można przedstawić w prostszy sposób. Jedyny minus jest taki, że w trakcie ładowania biblioteki, może pojawić się informacja, że LenovoEmExpandedAPI nie jest prawidłową aplikacją systemu Win32. Oznacza to, że wystąpiła niezgodność architektury Pythona i biblioteki. Nie można korzystać z 64-bitowej biblioteki na 32-bitowym Pythonie i na odwrót. Jedyne wyjście, to zainstalować dodatkową wersję Pythona ze zgodną architekturą.

W moim przypadku to wystarczyło – Bluetooth zaczął działać i mogłem zainstalować sterowniki.

Pozostała jeszcze kwestia sprawdzenia statusu Bluetooth. Nie jest to potrzebne, ale ciekawe. Tak jak mówiłem wcześniej – wywołanie funkcji GetBluetoothStatus nie zwraca tego, czego moglibyśmy po tej funkcji oczekiwać. Wynikiem jest zawsze 0, nawet gdy Bluetooth jest włączony. Wykorzystałem zatem dekompilator IDA, aby sprawdzić sygnaturę i kod funkcji.

Teraz doskonale widać, dlaczego funkcja zwracała 0. Był to po prostu kod wyjścia świadczący o powodzeniu. Właściwa informacja, dotycząca statusu Bluetooth, zapisywana jest do pierwszego parametru funkcji. W linijce 13, do zmiennej wskaźnikowej v2, kopiowany jest adres z parametru a1. Następnie, w linijce 34, pod adres z v2 zapisywana jest jakaś wartość. Czy jest to status? Zaraz się dowiemy.

Zgodnie z tym co widać powyżej, powinno wystarczyć przekazanie w pierwszym parametrze funkcji wskaźnika na zmienną DWORD. Tę operację również można wykonać w Pythonie. Jako drugi parametr można przekazać po prostu „0”, albo wcale go nie podawać. Zakładam, że bibliotekę macie wczytaną, więc wystarczy wpisywać po kolei:

W pierwszej linijce, tworzona jest zmienna ret_val, będąca typem int pochodzącym z biblioteki ctypes. Tak stworzoną zmienną, można następnie przekazać do funkcji jako wskaźnik. Do tego celu, służy funkcja byref().

Po ostatniej instrukcji, interpreter powinien wyświetlić „1”, co oznacza, że Bluetooth faktycznie jest włączony.

Powyższym sposobem, można odczytać również inne parametry:

Bluedentist

Bluedentist

Ponieważ włączanie Bluetooth przez interpreter Pythona jest tak samo wygodne jak włączanie światła poprzez zwieranie kabli, napisałem program, który wykorzystuje bibliotekę z Lenovo Energy Management. Program o bardzo wdzięcznej nazwie – Bluedentist – robi tylko to, co powinien, a o czym zapomnieli programiści Lenovo, czyli włącza lub wyłącza Bluetooth. Poniżej znajduje się link prowadzący do GitHub, gdzie znajduje się najnowsza wersja aplikacji. Należy wykorzystać wersję zgodną z architekturą systemu. Jeżeli włączy się niepoprawną, to program sam o tym poinformuje. Oprogramowanie Lenovo Energy Management musi być zainstalowane do prawidłowego działania aplikacji. O tym również program poinformuje.

Jeżeli wystąpią jakiekolwiek problemy z działaniem Bluedentist, piszcie śmiało w komentarzach. Po włączeniu Bluetooth należy oczywiście zainstalować sterowniki.

Pliki

[guest@itachi.pl:~]$

Dodaj komentarz

Twój adres email nie zostanie opublikowany. Pola, których wypełnienie jest wymagane, są oznaczone symbolem *