W komentarzach do ostatniego postu została mi zwrócona uwaga (całkiem słusznie zresztą), że ostatnio nie wrzucam nic technicznego - w zasadzie same ogłoszenia o DS/Programiście/książce/książce Xa/CTFach/etc. Więc, zgodnie z życzeniem czytelników, będzie to post częściowo techniczny. A częściowo rant, na to, że najwyraźniej trzeba być osobą techniczną, żeby można sobie spokojnie pograć w gry komputerowe (i to nie z winy gier)...

W zasadzie sprawa ma związek z dwoma problemami, na które się chcąc nie chcąc natknąłem. Najpierw Starcraft 2 odmówił mi posłuszeństwa (w ogóle nie chciał się włączyć), a potem (dzisiaj) Battlefield 4 zaczął wyskakiwać na pulpit jak przypadkowo nacisnąłem Caps Lock - postaram się po kolei opisać czym się objawiały, oraz jak udało mi się dojść do rozwiązań problemów (a nuż komuś się przyda). Dodam, że nie chciałem korzystać z klasycznego Windowsowego rozwiązania pt. reboot, ponieważ używany przeze mnie Windows 7 jest dużo stabilniejszym systemem niż poprzednie Windowsy (uptime po 50 dni nie jest już niczym dziwnym) i można na nim naprawić naprawdę sporo rzeczy runtime. W takim wypadku reboot brzmi trochę jak złożenie broni, więc... nie chciałem iść w tą stronę ;>

Zaczynając od SC2, objaw był następujący: SC2 się nie włącza. OK, przyznaję, że to nie jest za dużo informacji, więc doprecyzuje to co jest: "nie włączanie" objawiało się absolutnym brakiem widocznej reakcji na dwuklik ikony SC2, czy nawet ręcznej próby uruchomienia launchera Battle.net.exe (najwyraźniej od niedawna SC2 włącza się przez aplikację od Battle.netu).

Pierwszym krokiem było znalezienie logów, co też zrobiłem korzystając z Process Monitor (filtrowanie po Image Name is Battle.net.exe). Chwilę scrollowania i trafiłem na następujący wpis:

23:49:14,0355641 Battle.net.exe 12800 CreateFile C:\Users\gynvael\AppData\Local\Battle.net\Logs NAME COLLISION Desired Access: Read Data/List Directory, Synchronize, Disposition: Create, Options: Directory, Synchronous IO Non-Alert, Open Reparse Point, Attributes: N, ShareMode: Read, Write, AllocationSize: 0

Po otwarciu najnowszych logów znalazłem następujące wpisy:

I ... [IPC] {} Opening IPC shared memory. queueName=User:gynvael:Battle.net App IPC ShMem mode=client
I ... [Main] {} Leaving because another instance of battle.net is running
D ... [Main] {} Shutting down Backend
D ... [Main] {} Closing IPC Service
D ... [IPC] {} IPCService is shutting down
D ... [Main] {} Shutting down callback queue


OK, pojawiła się więc pewna hipoteza - być może jak kiedyś wcześniej Battle.net.exe z jakiegoś powodu nie do końca wyszedł (tj. złapał się w jakiegoś deadlocka przy dealokacjach/etc), a teraz nie mogę uruchomić nowej instancji, ponieważ poprzednia nadal wisi. Oczywiście łatwo to było przetestować - zabiłem wiszący Battle.net.exe i spróbowałem uruchomić go jeszcze raz... niestety, z takim samym skutkiem, tj. nic widocznego się nie stało, żadne okno się nie pojawiło, nic. Natomiast pojawił się nowy proces Battle.net.exe, który zużywał dość niewiele pamięci (nie pamiętam już dokładnie ile, ale były to raczej setki kilobajtów niż "normalne" megabajty, których bym się spodziewał), czyli wpis w logach prawdopodobnie powstał po moim szaleńczym klikaniu na ikonkę SC2 kilka chwil wcześniej.

Skoro jest proces, ale zużywa niewiele pamięci, to prawdopodobnie na czymś wisi - pytanie na czym? Odpaliłem więc Process Explorer, znalazłem proces na liście, potem RMB→Properties, zakładka Threads i zacząłem dwuklikać po różnych wątkach żeby zobaczyć ich callstacki. Okazało się, że jeden z wątków wisi na jakichś funkcjach z jakiejś DLLki Wacoma (pewnie załadowanej via AppInit_DLLs or sth).

Urządzenia Wacoma miałem przy tej maszynie dwa: tablet Bamboo starszej serii i monitor Wacoma. Tablet był w zasadzie nieużywany, więc stwierdziłem, że zacznę od odinstalowania jego sterownika (wraz z towarzyszącymi appkami). Chwilę później grałem w Starcrafta.

TL;DR: Żeby grać w SC2 musiałem odinstalować sterownik od tabletu - sponsored by LOGIC!

Jeśli chodzi natomiast o Battlefield 4, to objaw był następujący: będąc w grze, po naciśnięciu Caps Lock gra się minimalizowała, a ja byłem wyrzucany na pulpit. Chwila szukania w sieci zdradziła, że może chodzić o powiadomienie o zmianie stanu Caps/Num/Scroll Lock, które pojawia się na pulpicie - post na forum był co prawda o jakichś driverach firmy Widcomm od Bluetooth (no idea, nie miałem żadnych urządzeń tej firmy, chyba, że któreś z tych co miałem było na licencji tej firmy - to w końcu dość częste). Natomiast po kliknięciu parę razy Caps Lock okazało się, że powiadomienie w prawym dolnym rogu ekranu faktycznie się pojawia.

Pytanie zasadnicze - jaka aplikacja jest właścicielem tego okna (pod Windowsem nawet prosty napis na pulpicie jest formalnie "oknem")? Kiedyś do ustalenia takich rzeczy używałem Spy++ z pakietu Microsoft Visual Studio, ale teraz najwyraźniej używa się wspomniany wcześniej Process Explorer. Działa to w następujący sposób - robi się cokolwiek, żeby okno się pojawiło (w tym wypadku cokolwiek == kliknięcie Caps Lock), po czym przeciąga się ikonkę celownika z Process Explorera na wybrane okno. Process Explorer następnie pokazuje jaka aplikacja jest właścicielem danego okna - w moim przypadku właścicielem okazało się niejakie TosBtKbd.exe.

TosBtKbd.exe okazało się być jedną z aplikacji towarzyszących driverowi od Bluetooth firmy Toshiba, więc zacząłem szukać po ustawieniach tego pakietu czy można jakoś wyłączyć powiadomienia. Nic nie znalazłem, na sieci też nic nie pisali ciekawego, więc TosBtKbd.exe wylądowała w IDA Pro.

Szybki rzut okiem na stringi (shift+F12) pokazał mi kilka kluczy w rejestrze:

.data:0040A08C 00000025 C SOFTWARE\\Toshiba\\BluetoothStack\\V1.0
.data:0040A258 00000032 C Software\\Toshiba\\BluetoothStack\\V1.0\\HID\\Keyboard


Odnalazłem powyższe klucze w rejestrze i zobaczyłem kilka wartości (Notifications, Caps, Num, Scroll) w wartościami wartości (ekhem...) ustawionymi na DWORD 0. Szybka zmiana wartości na cokolwiek innego nic nie dała. Usunięcie klucza "Keyboard" również - po prostu został stworzony na nowo po restarcie aplikacji. Nadszedł więc czas analizy kodu - metodą po-sznurku-do-kłębka (aka xref) dotarłem do następującej funkcji:

signed int __thiscall ReadRegs(void *this, LPBYTE lpData)
{
 void *v2; // esi@1
 signed int result; // eax@3
 HKEY phkResult; // [sp+Ch] [bp-Ch]@1
 DWORD cbData; // [sp+10h] [bp-8h]@4
 DWORD Type; // [sp+14h] [bp-4h]@4

 v2 = this;
 if ( RegOpenKeyExA(HKEY_CURRENT_USER, aSoftwareToshib, 0, 0x20019u, &phkResult)
   && (CreateKeysInReg(v2), RegOpenKeyExA(HKEY_CURRENT_USER, aSoftwareToshib, 0, 0x20019u, &phkResult)) )
 {
   result = 0;
 }
 else
 {
   cbData = 4;
   if ( RegQueryValueExA(phkResult, aNotifications, 0, &Type, lpData, &cbData) )
   {
     RegCloseKey(phkResult);
     result = 0;
   }
   else
   {
     cbData = 4;
     if ( RegQueryValueExA(phkResult, aCaps, 0, &Type, lpData + 4, &cbData) )
     {
       RegCloseKey(phkResult);
       result = 0;
     }
     else
     {
       cbData = 4;
       if ( RegQueryValueExA(phkResult, aNum, 0, &Type, lpData + 8, &cbData) )
       {
         RegCloseKey(phkResult);
         result = 0;
       }
       else
       {
         cbData = 4;
         if ( RegQueryValueExA(phkResult, aScroll, 0, &Type, lpData + 12, &cbData) )
         {
           RegCloseKey(phkResult);
           result = 0;
         }
         else
         {
           cbData = 4;
           RegCloseKey(phkResult);
           result = 1;
         }
       }
     }
   }
 }
 return result;
}

Funkcja ta była wywoływana w jednym miejscu (0x402436) i jeśli zwróciła 0, to aplikacja niszczyła okno powiadomień i wychodziła (co brzmiało bardzo dobrze). Jeśli chodzi o samą logikę funkcji, to była następująco: jeśli klucz nie istnieje, stwórz nowy. Jeśli istnieje, odczytaj wartości. Jeśli nie uda się odczytać jednej z nich, wyjdź i nigdy nie wracaj. To ostatnie brzmiało bardzo dobrze, więc usunąłem jedną z wartości i, po restarcie aplikacji, problem z wyrzucających-na-pulpit powiadomień się rozwiązał.

TL;DR: Jeśli grasz full-screen i naciśniesz Caps-Lock, to sterowniki Toshiby koniecznie chcą ci o tym powiedzieć na pulpicie.



Nie wiem czy jest jakieś sensowne podsumowanie, które mogę napisać. Chyba tylko: plz test your drivers, k? Thx!

I tyle.

Comments:

2015-02-06 09:56:31 = mzgreen
{
Kiedy premiera książki? Może jakiś leak? ;)
}
2015-02-06 13:34:17 = Westen
{
Śniadanie - checked.
Kawa - checked.
Zacny artykuł - checked.

No to czytamy!
}
2015-02-06 17:29:14 = Gynvael Coldwind
{
@mzgreen
Trochę się przesunie niestety (wolniej idzie niż liczyłem), więc raczej dopiero pod koniec roku się pojawi.

@Westen
;)
}
2015-02-06 17:47:39 = PiotrB
{
Tylko, że ZU prawdopodbnie zrobi reboot, bo tego się już nauczył ;).
Kiedyś rozwiązaniem tego były po prostu konsolę, wkładałeś plytę/cartridge i grałeś (teraz konsole też wymagają pewnej wiedzy).
}
2015-02-06 23:12:53 = Bartosz Wójcik
{
W czasach Windows XP fajnym eksperymentem było odpalenie Bounds Checkera, który monitorował m.in. błędne zachowanie driverów i rzeczy, których nie powinny robić, każdy błąd aktywował SoftICE, z takim włączonym monitoringiem praktycznie nie dało się korzystać z komputera, bo błędy wyskakiwały co kilka sekund, zwykle dla jakichś lipnych driverów, więc jeśli takie podejście mieli programiści driverów to co dopiero ludzie klepiący komponenty userlandowe, zwłaszcza te syfne laptopowe badziewia, którymi faszerują każdego nowego laptopa :)
}
2015-02-07 20:06:41 = Look
{
Miło mi ,że mogłem się małym stopniu przyczynić do nowego technicznego posta ;) Świetnie opisałeś swój tok rozumowania podczas szukania odpowiedzi.

PS. Gynvael, nie masz wrażenia ,że Twoje całe życie to CTF'y ? ;) Ten post udowadnia ,że jesteś uzależniony od rozwiązywania zagadek!
}
2015-02-07 22:04:44 = Mrowqa
{
Przyznaję, że zaskoczyłeś mnie treścią tego postu i równocześnie zainspirowałeś! :) Gdy zacząłem czytać o Battlefieldzie 4, to przypomniało mi się, że gdy próbowałem grać w trybie coopa z kolegą w Battlefieldzie 3 to zawsze był problem z uruchomieniem gry, tj. gra się wyłączała podczas ładowania (widoczne czarne okno, czasem nawet coś więcej się załadowało). Zazwyczaj rozwiązaniem było uruchamianie gry do skutku (po połowie godziny czasem się udawało), ale następnym razem będzie inaczej! :D (o ile będzie następny raz)
}

Add a comment:

Nick:
URL (optional):
Math captcha: 4 ∗ 4 + 6 =