Cyfroteka.pl

klikaj i czytaj online

Cyfro
Czytomierz
00417 005169 13074770 na godz. na dobę w sumie
USB. Praktyczne programowanie z Windows API w C++. Wydanie II - książka
USB. Praktyczne programowanie z Windows API w C++. Wydanie II - książka
Autor: Liczba stron: 424
Wydawca: Helion Język publikacji: polski
ISBN: 978-83-246-5539-7 Data wydania:
Lektor:
Kategoria: ebooki >> komputery i informatyka >> programowanie >> c++ - programowanie
Porównaj ceny (książka, ebook (-25%), audiobook).

USB dobre na wszystko - wykorzystaj jego moc!

Mniej więcej pod koniec lat 90. standard USB utrwalił się w świadomości użytkowników komputerów na całym świecie i stał się dla nich jednym z najwygodniejszych narzędzi zapewniających komunikację oraz wymianę danych między urządzeniami. Liczba gniazd USB, do których można podłączyć dosłownie wszystko - mysz, pendrive...a, dysk zewnętrzny czy kartę sieciową - stała się jednym z ważnych kryteriów przy zakupie nowego komputera, a czołowi wytwórcy ani myślą zastępować go czymkolwiek innym. Jednak USB ma także swoje wady. Zalicza się do nich konieczność używania bardziej złożonego sprzętu i oprogramowania w porównaniu ze starszymi protokołami transmisji danych. Te kłopoty pomoże Ci rozwiązać niniejsza książka, o ile nieobcy jest Ci język C/C++ w zakresie programowania strukturalnego i proceduralnego. Pokaże Ci ona całą architekturę standardu USB oraz implikacje jego stosowania dla różnych urządzeń. Dzięki niej poznasz także podstawy zasad programowania transmisji USB z wykorzystaniem zasobów systemów operacyjnych Windows oraz współistniejących bibliotek programistycznych. W dodatku autor tego wyczerpującego podręcznika nie poprzestaje na suchym wyliczeniu typów danych czy funkcji, lecz zamieszcza mnóstwo wskazówek dotyczących konkretnych, działających aplikacji. Jeśli myślisz o programowaniu transmisji danych w USB, nie znajdziesz nic lepszego!

Poznaj jeden z najpopularniejszych standardów wszech czasów!

Znajdź podobne książki Ostatnio czytane w tej kategorii

Darmowy fragment publikacji:

Wszelkie prawa zastrzeżone. Nieautoryzowane rozpowszechnianie całości lub fragmentu niniejszej publikacji w jakiejkolwiek postaci jest zabronione. Wykonywanie kopii metodą kserograficzną, fotograficzną, a także kopiowanie książki na nośniku filmowym, magnetycznym lub innym powoduje naruszenie praw autorskich niniejszej publikacji. Wszystkie znaki występujące w tekście są zastrzeżonymi znakami firmowymi bądź towarowymi ich właścicieli. Autor oraz Wydawnictwo HELION dołożyli wszelkich starań, by zawarte w tej książce informacje były kompletne i rzetelne. Nie biorą jednak żadnej odpowiedzialności ani za ich wykorzystanie, ani za związane z tym ewentualne naruszenie praw patentowych lub autorskich. Autor oraz Wydawnictwo HELION nie ponoszą również żadnej odpowiedzialności za ewentualne szkody wynikłe z wykorzystania informacji zawartych w książce. Redaktor prowadzący: Ewelina Burska Projekt okładki: Studio Gravite/Olsztyn Obarek, Pokoñski, Pazdrijowski, Zaprucki Materiały graficzne na okładce zostały wykorzystane za zgodą Shutterstock. Wydawnictwo HELION ul. Kościuszki 1c, 44-100 GLIWICE tel. 32 231 22 19, 32 230 98 63 e-mail: helion@helion.pl WWW: http://helion.pl (księgarnia internetowa, katalog książek) Kody źródłowe można znaleźć pod adresem: ftp://ftp.helion.pl/przyklady/usbpro.zip Drogi Czytelniku! Jeżeli chcesz ocenić tę książkę, zajrzyj pod adres http://helion.pl/user/opinie?usbpro Możesz tam wpisać swoje uwagi, spostrzeżenia, recenzję. ISBN: 978-83-246-5539-7 Copyright © Helion 2013 Printed in Poland. • Kup książkę • Poleć książkę • Oceń książkę • Księgarnia internetowa • Lubię to! » Nasza społeczność Spis treĈci Wstöp .............................................................................................. 7 Rozdziaä 1. Standard USB ................................................................................ 11 ĝrodowisko fizyczne i sygnaáowe USB .......................................................................... 13 USB 2.0 .................................................................................................................... 13 USB 3.0 .................................................................................................................... 15 Záącza Mini i Micro .................................................................................................. 19 Ramki i mikroramki ....................................................................................................... 24 Transfer danych .............................................................................................................. 24 Pakiety USB 2.0 ............................................................................................................. 28 Transakcje USB 2.0 ........................................................................................................ 33 Pakiety w trybie Super Speed ......................................................................................... 38 Operacje transakcyjne USB 3.0 ...................................................................................... 46 Porównanie standardów USB 2.0 oraz 3.0 ............................................................... 53 Wireless USB ................................................................................................................. 54 Podsumowanie ................................................................................................................ 56 Rozdziaä 2. Informacje o urzñdzeniach .............................................................. 57 Identyfikatory urządzenia ............................................................................................... 57 Identyfikatory sprzĊtu ............................................................................................... 58 Identyfikatory zgodnoĞci .......................................................................................... 58 Ocena i selekcja pakietów sterowników ................................................................... 58 Klasy instalacji urządzeĔ ................................................................................................ 58 MenedĪer urządzeĔ ......................................................................................................... 59 Rejestr systemowy .......................................................................................................... 63 Klucz tematyczny HKEY_LOCAL_MACHINE ..................................................... 64 Podklucz tematyczny \Class ..................................................................................... 65 Podklucz podklucza tematycznego \Class ................................................................ 66 Identyfikatory GUID ................................................................................................ 67 Pliki .inf .......................................................................................................................... 69 Podsumowanie ................................................................................................................ 71 Poleć książkęKup książkę 4 USB. Praktyczne programowanie z Windows API w C++ Rozdziaä 3. Wstöp do transmisji danych ............................................................ 73 Struktura systemu USB 2.0 ............................................................................................. 73 Warstwa funkcjonalna .............................................................................................. 73 Warstwa fizyczna ..................................................................................................... 74 Warstwa logiczna ..................................................................................................... 75 Struktura systemu USB 3.0 ............................................................................................. 76 Potoki danych ................................................................................................................. 77 Urządzenia i deskryptory urządzeĔ USB ........................................................................ 80 Koncentratory i deskryptory koncentratorów USB ......................................................... 84 Punkty koĔcowe i deskryptory punktu koĔcowego ........................................................ 89 Interfejsy i deskryptory interfejsów urządzeĔ USB ........................................................ 95 Konfiguracje i deskryptory konfiguracji ....................................................................... 100 Deskryptory tekstowe ................................................................................................... 104 Komunikacja programu uĪytkownika z urządzeniem ................................................... 104 Podsumowanie .............................................................................................................. 110 Rozdziaä 4. Urzñdzenia klasy HID .................................................................... 111 Deskryptor raportu ........................................................................................................ 111 Pozycje Collection i End Collection ....................................................................... 112 Rodzaje raportów ................................................................................................... 113 ZawartoĞü raportów ................................................................................................ 114 Format danych ........................................................................................................ 115 Zakresy wartoĞci danych ........................................................................................ 115 Jednostki miar ........................................................................................................ 115 Podstawowe funkcje urządzeĔ klasy HID .................................................................... 116 Funkcje rodziny HidD_Xxx() ................................................................................. 117 Funkcje rodziny HidP_Xxx() ................................................................................. 125 Biblioteka HID.dll ........................................................................................................ 144 Podsumowanie .............................................................................................................. 147 Rozdziaä 5. Detekcja i identyfikacja urzñdzeþ doäñczonych do magistrali USB .. 149 Podstawowe zasoby systemowe ................................................................................... 151 Funkcja SetupDiGetClassDevs() ............................................................................ 152 Funkcja SetupDiEnumDeviceInterfaces() .............................................................. 152 Struktura SP_DEVINFO_DATA ........................................................................... 153 Struktura SP_DEVICE_INTERFACE_DATA ...................................................... 154 Struktura SP_DEVICE_INTERFACE_DETAIL_DATA ...................................... 155 Funkcja SetupDiGetDeviceInterfaceDetail() .......................................................... 155 Funkcja SetupDiDestroyDeviceInfoList() .............................................................. 157 Detekcja interfejsów urządzeĔ ............................................................................... 157 Zliczanie interfejsów urządzeĔ ............................................................................... 161 Funkcja SetupDiGetDeviceRegistryProperty() ............................................................. 163 Struktury danych .......................................................................................................... 168 Moduá usbiodef.h .......................................................................................................... 174 Moduá cfgmgr32.h ........................................................................................................ 176 Biblioteka Setupapi ...................................................................................................... 182 Powiadamianie o doáączaniu i odáączaniu urządzeĔ ..................................................... 185 Podsumowanie .............................................................................................................. 189 Poleć książkęKup książkę Spis treĈci 5 Rozdziaä 6. Odblokowanie urzñdzenia do transmisji. Odczyt i zapis danych ....... 191 Odblokowanie urządzenia do transmisji ....................................................................... 191 Funkcja CreateFile() ............................................................................................... 192 Funkcja CloseHandle() ........................................................................................... 194 Przykáadowy program Ğrodowiska tekstowego ...................................................... 194 Odczyt danych w formie raportu .................................................................................. 198 Funkcja ReadFile() ................................................................................................. 199 Odczyt dáugoĞci bufora danych .............................................................................. 203 Funkcja HidD_GetInputReport() ............................................................................ 207 Odczyt wáasnoĞci przycisków ................................................................................ 208 Odczyt wáasnoĞci wartoĞci ..................................................................................... 213 Aplikacja Ğrodowiska graficznego .......................................................................... 218 Zapis danych w formie raportu ..................................................................................... 225 Funkcja WriteFile() ................................................................................................ 225 Funkcje HidD_SetOutputReport() oraz HidD_SetFeature() ................................... 226 Struktura OVERLAPPED ............................................................................................ 227 Funkcje xxxEx ....................................................................................................... 230 Struktura COMMTIMEOUTS ...................................................................................... 234 Funkcje GetCommTimeouts() i SetCommTimeouts() ........................................... 235 Funkcja DeviceIoControl() ........................................................................................... 236 Rozkazy z moduáu hidclass.h ................................................................................. 242 Rozkazy z moduáu usbioctl.h ........................................................................................ 245 Identyfikacja urządzeĔ przyáączonych do koncentratora USB ............................... 247 Struktura URB .............................................................................................................. 262 Funkcja UsbBuildGetDescriptorRequest() ............................................................. 267 Podsumowanie .............................................................................................................. 268 ûwiczenia ..................................................................................................................... 268 Rozdziaä 7. Biblioteki WinUSB oraz LibUSB ..................................................... 271 Biblioteka WinUSB ...................................................................................................... 271 Przygotowanie pakietu instalacyjnego ................................................................... 272 Funkcje eksportowe biblioteki WinUSB ................................................................ 277 Biblioteka LibUSB ....................................................................................................... 289 Funkcje jądra biblioteki .......................................................................................... 292 Funkcje do zarządzania urządzeniem libusb .......................................................... 293 Funkcje realizujące transfer masowy ..................................................................... 300 Funkcje realizujące transfer przerwaniowy ............................................................ 301 Funkcje asynchroniczne ......................................................................................... 301 Podsumowanie .............................................................................................................. 305 Rozdziaä 8. Programowanie obiektowe transmisji USB .................................... 307 ObiektowoĞü ................................................................................................................. 307 Wzorce projektowe ....................................................................................................... 314 Singleton ................................................................................................................ 314 Interfejsy ....................................................................................................................... 319 Zliczanie odwoáaĔ do interfejsu ............................................................................. 326 Identyfikator interfejsu ........................................................................................... 327 Komponenty wizualne .................................................................................................. 336 Podsumowanie .............................................................................................................. 340 ûwiczenia ..................................................................................................................... 340 Poleć książkęKup książkę 6 USB. Praktyczne programowanie z Windows API w C++ Rozdziaä 9. Wewnötrzne struktury danych ....................................................... 351 Program proceduralny .................................................................................................. 352 Program obiektowy ...................................................................................................... 359 Aplikacja Ğrodowiska graficznego ................................................................................ 366 Podsumowanie .............................................................................................................. 375 ûwiczenia ..................................................................................................................... 375 Rozdziaä 10. Programy wielowñtkowe ............................................................... 379 Wątki i procesy ............................................................................................................. 379 Funkcja CreateThread() ................................................................................................ 381 Klasa TThread .............................................................................................................. 389 Podsumowanie .............................................................................................................. 397 ûwiczenia ..................................................................................................................... 397 Rozdziaä 11. Adaptery USB .............................................................................. 401 Adaptery USB/RS 232C ............................................................................................... 401 WáaĞciwoĞci portu adaptera .................................................................................... 402 Adaptery USB/IEEE-488 ............................................................................................. 404 Adaptery USB/Bluetooth .............................................................................................. 405 Podsumowanie .............................................................................................................. 413 Literatura ..................................................................................... 415 Skorowidz .................................................................................... 417 Poleć książkęKup książkę Rozdziaä 5. Detekcja i identyfikacja urzñdzeþ doäñczonych do magistrali USB Urządzenia USB są automatycznie wykrywane przez system operacyjny po ich pod- áączeniu i wáączeniu zasilania. Kiedy w systemie pojawi siĊ nowy sprzĊt, aktywowane są procedury jego detekcji i identyfikacji. Zespóá tego typu operacji czĊsto jest okre- Ğlany jako wyliczanie lub enumeracja urządzeĔ (ang. enumeration). RozpoczĊcie pro- cesu enumeracji powoduje przejĞcie urządzenia miĊdzy podstawowymi stanami, jak pokazano na rysunku 5.1. Rysunek 5.1. Podstawowe stany urządzenia w trakcie enumeracji Poleć książkęKup książkę 150 USB. Praktyczne programowanie z Windows API w C++ Za poĞrednictwem kilkunastu czynnoĞci, z których najwaĪniejsze zostaáy przedstawio- ne poniĪej, system operacyjny wykonuje enumeracjĊ urządzenia w ramach poszcze- gólnych stanów. Rysunek 5.2. Szczegóáowy diagram czynnoĞci dla procesu enumeracji urządzeĔ doáączanych do magistrali USB  UĪytkownik przyáącza urządzenie do portu USB hosta (macierzystego komputera) lub huba (koncentratora) — urządzenie pozostaje w stanie przyáączenia (ang. attached state).  Po odblokowaniu linii zasilającej urządzenie przechodzi w stan zasilania (ang. powered state).  Po sprawdzeniu stanu linii zasilających oprogramowanie hosta przystĊpuje do konfigurowania nowego sprzĊtu.  Hub poprzez testowanie stanu linii sygnaáowych sprawdza, z jaką prĊdkoĞcią przesyáu danych urządzenie moĪe pracowaü. Informacja zostaje przekazana do hosta w odpowiedzi na wysáany przez niego rozkaz GET_STATUS.  Kiedy nowe urządzenie zostaje rozpoznane, kontroler hosta wysyáa do huba rozkaz SET_FEATURE. Port zostaje zresetowany (przez 10 ms linie sygnaáowe pozostają w niskim stanie logicznym).  Poprzez dalsze testowanie aktualnego stanu linii sygnaáowych host sprawdza, czy urządzenie pracujące z peáną szybkoĞcią przesyáu danych moĪe pracowaü teĪ z szybkoĞcią wysoką.  Ponownie wysyáając rozkaz GET_STATUS, host sprawdza, czy urządzenie pozostaje w stanie Reset. JeĪeli nie, zostaje utworzony potok zerowy przeznaczony do celów konfiguracji urządzenia. Urządzeniu zostaje przypisany domyĞlny adres 00h, po czym przechodzi ono do stanu domyĞlnego (ang. default state).  Host wysyáa rozkaz GET_DESCRIPTOR, aby otrzymaü informacje o maksymalnym rozmiarze pakietu danych, który moĪe byü transmitowany potokiem domyĞlnym. Rozkaz ten jest kierowany do zerowego punktu koĔcowego EP0 urządzenia. Oprogramowanie hosta moĪe identyfikowaü w danym czasie tylko jedno urządzenie, zatem tylko jedno urządzenie w danym czasie moĪe pozostawaü z adresem 00h. Poleć książkęKup książkę Rozdziaä 5. i Detekcja i identyfikacja urzñdzeþ doäñczonych do magistrali USB 151  W nastĊpnej kolejnoĞci za poĞrednictwem rozkazu SET_ADDRESS urządzeniu jest przypisywany unikatowy adres — urządzenie przechodzi do stanu adresowania (ang. addressed state). Nowy adres pozostaje aktualny, dopóki urządzenie jest przyáączone do portu USB. W momencie odáączenia urządzenia port jest resetowany.  W dalszej kolejnoĞci za poĞrednictwem na nowo adresowanego rozkazu GET_DESCRIPTOR oprogramowanie hosta pobiera kompletne deskryptory urządzenia (patrz rysunek 3.9).  Po odczytaniu deskryptorów urządzenia oprogramowanie hosta wyszukuje dla urządzenia najlepiej pasujący sterownik i zapisuje odpowiednie informacje (Vendor ID, Product ID, ...) w pliku .inf.  Sterownik urządzenia wysyáa rozkaz SET_CONFIGURATION w celu ostatecznego skonfigurowania nowego sprzĊtu. Od tego momentu urządzenie pozostaje w stanie skonfigurowania (ang. configured state)1. Podstawowe zasoby systemowe Kompilator C++ w module setupapi.h udostĊpnia szereg uĪytecznych funkcji i struk- tur, które w znakomity sposób umoĪliwiają samodzielne przeprowadzenie detekcji i identyfikacji ĞcieĪek dostĊpu do interfejsów oferowanych przez sterownik(i) urządzeĔ aktualnie doáączonych do magistrali USB. W tym podrozdziale zostaáy przedstawione najwaĪniejsze z nich. W dalszej czĊĞci ksiąĪki ze wzglĊdu na zwiĊzáoĞü sformuáowaĔ poprzez interfejs urzą- dzenia bĊdziemy rozumieli interfejs, jaki sterownik urządzenia udostĊpnia warstwie aplikacji. Windows Driver Kit jest w peäni kompatybilny jedynie z kompilatorami VC++. W de- finicjach struktur i funkcji WDK w sposób niejednolity uĔywa dla typów zmiennych rozszerzeþ IN lub __in w celu oznaczenia parametrów wejĈciowych, OUT lub __out dla oznaczenia parametrów wyjĈciowych lub __opt dla oznaczenia parametrów opcjonalnych. MoĔliwe jest równieĔ wystöpowanie oznaczeþ bödñcych kombinacjñ tych parametrów, np. __inout lub __in__opt. Niektóre kompilatory C++ mogñ zgäa- szaè bäödy w trakcie kompilacji moduäów zawierajñcych tego rodzaju oznaczenia w deklaracjach zmiennych. W przypadku napotkania przez kompilator problemów z uĔywanymi przez WDK rozszerzeniami naleĔy podjñè próbö zmiany ustawieþ opcji uĔywanego kompilatora C++; moĔna równieĔ bez jakiejkolwiek szkody dla oprogra- mowania opisane wyĔej elementy, które nie sñ rozpoznawane przez kompilator, sa- modzielnie usunñè z odpowiednich plików nagäówkowych. 1 JeĪeli w trakcie transmisji urządzenie USB 2.0 przez 3 ms nie wykrywa znacznika początku ramki danych SOF, przechodzi do stanu zawieszenia (ang. suspended state). Poleć książkęKup książkę 152 USB. Praktyczne programowanie z Windows API w C++ Funkcja SetupDiGetClassDevs() Funkcja zwraca identyfikator klasy podáączonych urządzeĔ, których lista i opis kon- figuracji znajduje siĊ w rejestrze systemowym w kluczu HKEY_LOCAL_MACHINE (patrz rozdziaá 2.). HDEVINFO SetupDiGetClassDevs( IN LPGUID ClassGuid, OPTIONAL IN PCTSTR Enumerator, OPTIONAL IN HWND hwndParent, OPTIONAL IN DWORD Flags ); Parametr ClassGuid wskazuje strukturĊ GUID klasy urządzeĔ. UĪycie tego parametru jest opcjonalne. Aplikacje uĪytkownika mogą pobieraü adres identyfikatora GUID dla klasy urządzeĔ HID za pomocą funkcji HidD_GetHidGuid(). WskaĨnik Enumerator wskazuje áaĔcuch znaków (zakoĔczony zerowym ogranicznikiem), przechowujący dane konkret- nych urządzeĔ (patrz rozdziaá 2., rysunek 2.4). UĪycie tego parametru w programie jest opcjonalne. JeĪeli wskaĨnikowi przypiszemy wartoĞü NULL, funkcja zwróci listĊ urządzeĔ typu PnP (ang. Plug and Play). Opcjonalnie wykorzystywany identyfikator hwndParent wskazuje okno odpowiedzialne za interakcjĊ z otrzymanym zestawem urzą- dzeĔ. Znacznik Flags przyjmuje postaü bitowej alternatywy wybranego zestawu nastĊ- pujących staáych symbolicznych:  DIGCF_ALLCLASSES — okreĞla listĊ wszystkich zainstalowanych w systemie urządzeĔ;  DIGCF_DEVICEINTERFACE — okreĞla listĊ zainstalowanych urządzeĔ z danym interfejsem;  DIGCF_DEFAULT — zwraca listĊ urządzeĔ z domyĞlnym interfejsem;  DIGCF_PRESENT — okreĞla urządzenia aktualnie dostĊpne w systemie;  DIGCF_PROFILE — okreĞla listĊ urządzeĔ bĊdących czĊĞcią aktualnego zestawu sprzĊtowego. JeĪeli wykonanie funkcji nie powiedzie siĊ, zwracana jest wartoĞü INVALID_HANDLE_VALUE. Kod ewentualnego báĊdu moĪna zdiagnozowaü za pomocą funkcji GetLastError(). Szczegóáowe kody báĊdów są dostĊpne na stronie http://msdn.microsoft.com/en-us/ library/windows/desktop/ms681382(v=vs.85).aspx. Funkcja SetupDiEnumDeviceInterfaces() Funkcja wyszukuje interfejsy urządzeĔ identyfikowanych przez wskaĨnik DeviceInfoSet zwracany przez funkcjĊ SetupDiGetClassDevs(). WINSETUPAPI BOOL WINAPI SetupDiEnumDeviceInterfaces( IN HDEVINFO DeviceInfoSet, Poleć książkęKup książkę Rozdziaä 5. i Detekcja i identyfikacja urzñdzeþ doäñczonych do magistrali USB 153 IN PSP_DEVINFO_DATA DeviceInfoData, OPTIONAL IN LPGUID InterfaceClassGuid, IN DWORD MemberIndex, OUT PSP_DEVICE_INTERFACE_DATA DeviceInterfaceData ); WskaĨnik DeviceInfoData wskazuje strukturĊ SP_DEVINFO_DATA (patrz tabela 5.1), co umoĪliwia ograniczenie przeszukiwaĔ istniejących urządzeĔ. Opcjonalnie funkcji moĪ- na przekazaü pusty wskaĨnik. W takim wypadku funkcjĊ naleĪy wywoáywaü cyklicz- nie, tak aby przeszukaáa wszystkie interfejsy udostĊpniane przez sterownik danego urządzenia. WskaĨnik InterfaceClassGuid wskazuje strukturĊ GUID. Parametr wej- Ğciowy MemberIndex jest numerem odpytywanego interfejsu. Jego wartoĞci zaczynają siĊ od 0 (zerowy indeks pierwszego interfejsu — interfejsu domyĞlnego). JeĪeli funk- cja jest wywoáywana w pĊtli cyklicznie, przy kaĪdym wywoáaniu naleĪy odpowiednio zwiĊkszyü wartoĞü MemberIndex. JeĪeli SetupDiEnumDeviceInterfaces() zwróci war- toĞü FALSE oraz funkcja GetLastError() zwróci ERROR_NO_MORE_ITEMS, oznacza to, Īe nie znaleziono interfejsu o podanym indeksie. WskaĨnik DeviceInterfaceData wska- zuje strukturĊ SP_DEVICE_INTERFACE_DATA (patrz tabela 5.2), której rozmiar naleĪy wpi- saü do pola cbSize: deviceInterfaceData.cbSize = sizeof(SP_DEVICE_INTERFACE_DATA); Struktura SP_DEVINFO_DATA W polach struktury są przechowywane informacje na temat egzemplarza urządzenia naleĪącego do klasy urządzeĔ USB. W tabeli 5.1 zamieszczono jej opis. Tabela 5.1. Specyfikacja struktury SP_DEVINFO_DATA Typ DWORD GUID DWORD Element struktury cbSize ClassGuid DevInst ULONG_PTR Reserved Znaczenie Rozmiar struktury w bajtach Identyfikator GUID klasy urządzeĔ Identyfikator wewnĊtrznej struktury opisującej urządzenie w systemie Zarezerwowane Windows Driver Kit (WDK) definiuje tĊ strukturĊ jako: typedef struct _SP_DEVINFO_DATA { DWORD cbSize; GUID ClassGuid; DWORD DevInst; ULONG_PTR Reserved; } SP_DEVINFO_DATA, *PSP_DEVINFO_DATA; Definicja ta tworzy dwa nowe sáowa kluczowe: SP_DEVINFO_DATA (struktura) i PSP_ DEVINFO_DATA (wskaĨnik do struktury). Poleć książkęKup książkę 154 USB. Praktyczne programowanie z Windows API w C++ Funkcje rodziny SetupDiXx(), uĔywajñc struktury SP_DEVINFO_DATA jako parametru, automatycznie sprawdzajñ poprawnoĈè okreĈlenia jej rozmiaru. Aktualny rozmiar struktury naleĔy wskazaè za pomocñ operatora sizeof() i wpisaè do pola cbSize. JeĔeli rozmiar struktury w ogóle nie zostanie okreĈlony lub zostanie okreĈlony nie- prawidäowo, to w przypadku uĔycia struktury jako parametru wejĈciowego IN zostanie wygenerowany bäñd ERROR_INVALID_PARAMETER, natomiast przy korzystaniu ze struk- tury jako parametru wyjĈciowego OUT zostanie wygenerowany bäñd ERROR_INVALID_ USER_BUFFER. Struktura SP_DEVICE_INTERFACE_DATA Zasoby struktury SP_DEVICE_INTERFACE_DATA zaprezentowane w tabeli 5.2 przechowu- ją dane interfejsu naleĪącego do klasy urządzeĔ USB. Tabela 5.2. Specyfikacja struktury SP_DEVICE_INTERFACE_DATA Typ DWORD GUID DWORD Element struktury cbSize InterfaceClassGuid Flags  ULONG_PTR Reserved Znaczenie Rozmiar struktury w bajtach Identyfikator GUID interfejsu klasy urządzeĔ Znaczniki interfejsu. WartoĞü SPINT_ACTIVE oznacza, Īe interfejs jest aktualnie dostĊpny. WartoĞü SPINT_DEFAULT oznacza domyĞlny interfejs dla klasy urządzeĔ. WartoĞü SPINT_REMOVED okreĞla usuniĊty interfejs Parametr zarezerwowany i aktualnie nieuĪywany WDK definiuje tĊ strukturĊ jako: typedef struct _SP_DEVICE_INTERFACE_DATA { DWORD cbSize; GUID InterfaceClassGuid; DWORD Flags; ULONG_PTR Reserved; } SP_DEVICE_INTERFACE_DATA, *PSP_DEVICE_INTERFACE_DATA; Definicja ta tworzy dwa nowe sáowa kluczowe: SP_DEVICE_INTERFACE_DATA (struktura) i PSP_DEVICE_INTERFACE_DATA (wskaĨnik do struktury). Funkcje zdefiniowane w module setupapi.h, uĔywajñc struktury SP_DEVICE_INTERFACE_ DATA jako parametru, automatycznie sprawdzajñ poprawnoĈè okreĈlenia jej rozmiaru. Aktualny rozmiar struktury naleĔy wskazaè za pomocñ operatora sizeof() i wpisaè do pola cbSize. JeĔeli rozmiar struktury w ogóle nie zostanie okreĈlony lub zostanie okreĈlony nieprawidäowo, system wygeneruje bäñd ERROR_INVALID_USER_BUFFER. Poleć książkęKup książkę Rozdziaä 5. i Detekcja i identyfikacja urzñdzeþ doäñczonych do magistrali USB 155 Struktura SP_DEVICE_INTERFACE_DETAIL_DATA Struktura SP_DEVICE_INTERFACE_DETAIL_DATA zawiera informacje o postaci ĞcieĪki do- stĊpu do interfejsu wybranego urządzenia USB. W tabeli 5.3 przedstawiono znaczenie poszczególnych pól tej struktury. Tabela 5.3. Specyfikacja struktury SP_DEVICE_INTERFACE_DETAIL_DATA Typ DWORD TCHAR Element struktury cbSize DevicePath[ANYSIZE_ARRAY] Znaczenie Rozmiar struktury w bajtach àaĔcuch znaków zakoĔczony zerowym ogranicznikiem (tzw. NULL — ang. terminated string), zawierający peáną nazwĊ symboliczną urządzenia (ĞcieĪkĊ dostĊpu do interfejsu udostĊpnianego przez sterownik urządzenia). Parametr ten jest wykorzystywany przez funkcjĊ CreateFile() WDK definiuje tĊ strukturĊ jako: typedef struct _SP_DEVICE_INTERFACE_DETAIL_DATA { DWORD cbSize; TCHAR DevicePath[ANYSIZE_ARRAY]; } SP_DEVICE_INTERFACE_DETAIL_DATA, *PSP_DEVICE_INTERFACE_DETAIL_DATA; Definicja ta tworzy dwa nowe sáowa kluczowe: SP_DEVICE_INTERFACE_DETAIL_DATA (struktura) i PSP_DEVICE_INTERFACE_DETAIL_DATA (wskaĨnik do struktury). Niekiedy ĈcieĔkö dostöpu do interfejsu urzñdzenia utoĔsamia siö z jego nazwñ sym- bolicznñ, którñ moĔna odczytaè z rejestru systemowego (patrz rozdziaä 2.). ChociaĔ te dwa äaþcuchy znaków majñ bardzo podobnñ postaè, to jednak mogñ siö róĔniè däugoĈciñ, dlatego w programach bezpieczniej jest posäugiwaè siö kompletnymi da- nymi zapisanymi w polu DevicePath struktury SP_DEVICE_INTERFACE_DETAIL_DATA. Funkcja SetupDiGetDeviceInterfaceDetail() Funkcja zwraca szczegóáowe informacje na temat interfejsu urządzenia. WINSETUPAPI BOOL WINAPI SetupDiGetDeviceInterfaceDetail( IN HDEVINFO DeviceInfoSet, IN PSP_DEVICE_INTERFACE_DATA DeviceInterfaceData, OUT PSP_DEVICE_INTERFACE_DETAIL_DATA DeviceInterfaceDetailData, OPTIONAL IN DWORD DeviceInterfaceDetailDataSize, OUT PDWORD RequiredSize, OPTIONAL OUT PSP_DEVINFO_DATA DeviceInfoData OPTIONAL ); Poleć książkęKup książkę 156 USB. Praktyczne programowanie z Windows API w C++ WskaĨnik DeviceInfoSet jest zwracany przez funkcjĊ SetupDiGetClassDevs(). Para- metr DeviceInterfaceData wskazuje strukturĊ SP_DEVICE_INTERFACE_DATA. WskaĨnik DeviceInterfaceDetailData wskazuje strukturĊ SP_DEVICE_INTERFACE_DETAIL_DATA (patrz tabela 5.3); opcjonalnie zamiast niego do funkcji moĪe byü przekazana wartoĞü NULL. W przypadku jawnego wskazania struktury SP_DEVICE_INTERFACE_DETAIL_DATA wskaĨnik powinien byü poprawnie zainicjowany, a jej pole cbSize musi byü prawi- dáowo okreĞlone. W przeciwnym razie kompilator zgáosi báĊdy naruszenia pamiĊci, podobnie jak na rysunkach 5.3 i 5.4. Rysunek 5.3. Báąd naruszenia pamiĊci dla nieprawidáowo zainicjowanego wskaĨnika do struktury SP_DEVICE_INTERFACE_DETAIL_DATA Rysunek 5.4. Báąd naruszenia pamiĊci dla nieprawidáowo okreĞlonego rozmiaru pola cbSize struktury SP_DEVICE_INTERFACE_DETAIL_DATA Argument DeviceInterfaceDetailDataSize funkcji SetupDiGetDeviceInterfaceDetail() ma wartoĞü zerową, jeĪeli DeviceInterfaceDetailData=NULL; w przeciwnym razie okre- Ğla rozmiar bufora: (offsetof(SP_DEVICE_INTERFACE_DETAIL_DATA, DevicePath) + sizeof(TCHAR)). Parametr RequiredSize jest wskaĨnikiem do danej typu DWORD, której przypisuje siĊ Īądany rozmiar bufora wskazywanego przez DeviceInterfaceDetailData. Parametr DeviceInfoData jest wskaĨnikiem do bufora danych przechowującego infor- macje na temat interfejsu udostĊpnianego przez sterownik urządzenia. JeĪeli wskaĨ- nikowi nie przypisano wartoĞci NULL, rozmiar danych powinien zostaü okreĞlony za pomocą operatora sizeof(): DeviceInfoData.cbSize=sizeof(SP_DEVINFO_DATA). Poleć książkęKup książkę Rozdziaä 5. i Detekcja i identyfikacja urzñdzeþ doäñczonych do magistrali USB 157 Funkcja SetupDiDestroyDeviceInfoList() Funkcja usuwa wszystkie zaalokowane zasoby zawierające informacje o urządzeniu i zwalnia przydzieloną im pamiĊü. Kolejne urządzenia podáączane do systemu mogą korzystaü ze zwolnionych zasobów. WINSETUPAPI BOOL WINAPI SetupDiDestroyDeviceInfoList( IN HDEVINFO DeviceInfoSet ); WskaĨnik DeviceInfoSet jest zwracany przez funkcjĊ SetupDiGetClassDevs(). W przy- padku prawidáowego zwolnienia zasobów funkcja zwraca wartoĞü TRUE, w przeciwnym razie wartoĞü FALSE. Kod wystąpienia báĊdu jest zwracany przez funkcjĊ GetLastError(). Detekcja interfejsów urzñdzeþ Na rysunku 5.5 w postaci diagramu czynnoĞci przedstawiono ogólną sieü dziaáaĔ, za pomocą których moĪna programowo samodzielnie wykonaü procedurĊ detekcji urzą- dzeĔ klasy HID aktualnie podáączonych do systemu, co w efekcie powinno skutkowaü odzyskaniem peánych nazw symbolicznych (peánych ĞcieĪek dostĊpu do interfejsów) urządzeĔ zapisanych w polu DevicePath struktury SP_DEVICE_INTERFACE_DETAIL_DATA. Rysunek 5.5. Ogólny diagram czynnoĞci dla operacji wstĊpnej enumeracji urządzeĔ klasy HID Poleć książkęKup książkę 158 USB. Praktyczne programowanie z Windows API w C++ CzynnoĈci (w znaczeniu nadawanym przez UML) mogñ byè interpretowane w zaleĔ- noĈci od wybranej perspektywy: jako zestaw pojedynczych metod (z perspektywy projektowej) lub jako zadanie do wykonania, i to zarówno przez czäowieka, jak i przez komputer (z perspektywy pojöciowej). Diagramów czynnoĈci moĔna uĔywaè do opi- su metod rozwiñzywania problemów wyraĔonych w postaci skoþczonej sekwencji kroków — to jest ich cel. Obsäugujñ one wszystkie standardowe konstrukcje stero- wania wymagane do opisania algorytmów [14]. W pierwszej kolejnoĞci naleĪy odczytaü postaü identyfikatora GUID interfejsu klasy urządzeĔ wystĊpujących w systemie. WskaĨnik deviceInfoSet wskaĪe dane zawiera- jące informacje na temat wszystkich zainstalowanych i aktualnie dostĊpnych (przyáą- czonych) urządzeĔ danej klasy. NastĊpnie wyszukiwane są interfejsy poszczególnych urządzeĔ. Poprzez odczytanie zawartoĞci pola DevicePath struktury SP_DEVICE_INTERFACE_ DETAIL_DATA wydobywana jest peána ĞcieĪka dostĊpu DevicePath do interfejsu istniejące- go urządzenia USB. Na koniec dotychczas uĪywane przez program zasoby są zwalniane. Niektóre z dostöpnych kompilatorów jözyka C++ mogñ niewäaĈciwie obliczaè rozmiar struktur (za pomocñ operatora sizeof()). Bäödne obliczenie rozmiaru którejkolwiek z uĔywanych struktur bödzie niezmiennie skutkowaè bäödami w trakcie uruchamia- nia programu. W takich sytuacjach naleĔy zadbaè o wäaĈciwe ustalenie opcji kompi- latora na podstawie jego dokumentacji. Stosowana tu konstrukcja: #pragma option push -a1 //... #pragma option pop odpowiada opisanej sytuacji. Inne przykäady rozwiñzania tego typu problemów moĔ- na znaleĒè w artykule dostöpnym pod adresem: http://support.codegear.com/ article/35751. Na listingu 5.1 zamieszczono kod moduáu projektu bĊdącego uszczegóáowioną imple- mentacją diagramu z rysunku 5.5. Listing 5.1. Kod moduáu usb_R5_1.cpp jako przykáad zaprogramowania wstĊpnej enumeracji urządzeĔ na podstawie identyfikatora GUID klasy urządzeĔ #include windows #pragma option push -a1 #include setupapi #pragma option pop #include assert #include iostream using namespace std; void displayError(const char* msg){ cout msg endl; system( PAUSE ); exit(0); }; //--------------------------------------------------------- template class T Poleć książkęKup książkę Rozdziaä 5. i Detekcja i identyfikacja urzñdzeþ doäñczonych do magistrali USB 159 inline void releaseMemory(T x) { assert(x != NULL); delete [] x; x = NULL; } //--------------------------------------------------------- GUID classGuid; HMODULE hHidLib; DWORD /* unsigned long lub ULONG */ memberIndex = 0; DWORD deviceInterfaceDetailDataSize; DWORD requiredSize; HDEVINFO deviceInfoSet; SP_DEVICE_INTERFACE_DATA deviceInterfaceData; PSP_DEVICE_INTERFACE_DETAIL_DATA deviceInterfaceDetailData = NULL; int main(){ //Odwzorowanie identyfikatora biblioteki HID.dll w przestrzeni //adresowej gïównego procesu hHidLib = LoadLibrary( C:\\Windows\\system32\\HID.DLL ); if (!hHidLib) displayError( BïÈd doïÈczenia biblioteki HID.DLL. ); //Pobranie adresu funkcji eksportowej HidD_GetHidGuid() void (__stdcall *HidD_GetHidGuid)(OUT LPGUID HidGuid); /*(void __stdcall*/(FARPROC ) HidD_GetHidGuid = GetProcAddress(hHidLib, HidD_GetHidGuid ); if (!HidD_GetHidGuid){ FreeLibrary(hHidLib); displayError( Nie znaleziono identyfikatora GUID. ); } //Wywoïanie funkcji HidD_GetHidGuid() HidD_GetHidGuid( classGuid); //Procedury enumeracji urzÈdzeñ deviceInfoSet = SetupDiGetClassDevs( classGuid, NULL, NULL, DIGCF_PRESENT | DIGCF_INTERFACEDEVICE); if (deviceInfoSet == INVALID_HANDLE_VALUE) displayError( Nie zidentyfikowano podïÈczonych urzÈdzeñ.\n ); deviceInterfaceData.cbSize = sizeof(SP_DEVICE_INTERFACE_DATA); while(SetupDiEnumDeviceInterfaces(deviceInfoSet, NULL, classGuid, memberIndex, deviceInterfaceData)){ memberIndex++; //inkrementacja numeru interfejsu SetupDiGetDeviceInterfaceDetail(deviceInfoSet, deviceInterfaceData, NULL, 0, deviceInterfaceDetailDataSize, NULL); deviceInterfaceDetailData = (PSP_DEVICE_INTERFACE_DETAIL_DATA) new DWORD[deviceInterfaceDetailDataSize]; deviceInterfaceDetailData- cbSize=sizeof(SP_DEVICE_INTERFACE_DETAIL_DATA); if (!SetupDiGetDeviceInterfaceDetail(deviceInfoSet, deviceInterfaceData, deviceInterfaceDetailData, deviceInterfaceDetailDataSize, requiredSize, NULL)){ releaseMemory(deviceInterfaceDetailData); Poleć książkęKup książkę 160 USB. Praktyczne programowanie z Windows API w C++ //SetupDiDestroyDeviceInfoList(deviceInfoSet); //displayError( Nie moĝna pobraÊ informacji o interfejsie.\n ); } // deviceInterfaceDetailData- DevicePath jest ïÈczem symbolicznym // do interfejsu urzÈdzenia cout deviceInterfaceDetailData- DevicePath endl; releaseMemory(deviceInterfaceDetailData); }; //koniec while SetupDiDestroyDeviceInfoList(deviceInfoSet); FreeLibrary(hHidLib); cout endl; system( PAUSE ); return 0; } //--------------------------------------------------------- RóĔne odmiany wskaĒnika do funkcji FARPROC sñ zdefiniowane w module windef.h. W Linuksie FARPROC naleĔy zastñpiè wskaĒnikiem ogólnym void*. Windows Driver Kit stosuje konwencjö __stdcall, co zapewnia, Ĕe funkcja zostanie wywoäana zgod- nie z wymogami systemu operacyjnego. Oznacza to, Ĕe w funkcji wywoäujñcej liczba i typ argumentów muszñ byè poprawne. Funkcje i typy danych definiowane w zaso- bach WDK API czösto korzystajñ z nastöpujñcych makrodefinicji: #define DDKAPI __stdcall lub #define DDKAPI_PTR __stdcall* W tego typu konwencjach deklaracja wskaĒnika do funkcji moĔe zostaè zapisana na jeden z dwóch sposobów: void (DDKAPI *HidD_GetHidGuid)(OUT LPGUID HidGuid); lub void (DDKAPI_PTR HidD_GetHidGuid)(OUT LPGUID HidGuid); Na rysunku 5.6 przedstawiono dziaáający program z listingu 5.1. Wynik dziaáania progra- mu naleĪy porównaü z odpowiednimi zapisami w edytorze rejestrów (patrz rysunek 2.5). Rysunek 5.6. Aplikacja proj_USB_R5_1 w trakcie dziaáania Odczytane ĞcieĪki dostĊpu (áącza symboliczne) do poszczególnych interfejsów urządzeĔ klasy HID mogą byü przekazane do funkcji CreateFile() w celu otrzymania identyfi- katora pliku sterownika urządzenia wykonawczego USB, które jest aktualnie dostĊpne w systemie. Poleć książkęKup książkę Rozdziaä 5. i Detekcja i identyfikacja urzñdzeþ doäñczonych do magistrali USB 161 Zliczanie interfejsów urzñdzeþ Dokonując niewielkiej modyfikacji poprzednio prezentowanego algorytmu, moĪna zbudowaü uniwersalną funkcjĊ searchInterfaceHidDevices(), która dodatkowo zlicza interfejsy aktualnie podáączonych do systemu urządzeĔ klasy HID. Listing 5.2 zawiera odpowiedni przykáad bĊdący modyfikacją kodu z listingu 5.1. Listing 5.2. Kod moduáu usb_R5_2.cpp #include windows #pragma option push -a1 #include setupapi #pragma option pop #include assert #include iostream using namespace std; void displayError(const char* msg){ cout msg endl; system( PAUSE ); exit(0); }; //--------------------------------------------------------- template class T inline void releaseMemory(T x) { assert(x != NULL); delete [] x; x = NULL; } //--------------------------------------------------------- int searchInterfaceHidDevices() { HMODULE hHidLib; HDEVINFO deviceInfoSet; SP_INTERFACE_DEVICE_DATA deviceInterfaceData; DWORD memberIndex = 0; GUID classGuid; PSP_DEVICE_INTERFACE_DETAIL_DATA deviceInterfaceDetailData = NULL; DWORD requiredSize = 0; DWORD deviceInterfaceDetailDataSize = 0; DWORD searchMaxDevice = 100; bool done = false; void (__stdcall *HidD_GetHidGuid)(OUT LPGUID HidGuid); hHidLib = LoadLibrary( C:\\Windows\\system32\\HID.DLL ); if (!hHidLib) displayError( BïÈd doïÈczenia biblioteki HID.DLL. ); (FARPROC ) HidD_GetHidGuid = GetProcAddress(hHidLib, HidD_GetHidGuid ); if (!HidD_GetHidGuid){ FreeLibrary(hHidLib); Poleć książkęKup książkę 162 USB. Praktyczne programowanie z Windows API w C++ displayError( Nie znaleziono identyfikatora GUID. ); } HidD_GetHidGuid ( classGuid); deviceInfoSet = SetupDiGetClassDevs( classGuid, NULL, NULL, (DIGCF_PRESENT | DIGCF_DEVICEINTERFACE)); deviceInterfaceData.cbSize = sizeof(SP_INTERFACE_DEVICE_DATA); while(!done) { for(; memberIndex searchMaxDevice; memberIndex++) { if(SetupDiEnumDeviceInterfaces(deviceInfoSet,0, classGuid, memberIndex, deviceInterfaceData)) { SetupDiGetDeviceInterfaceDetail(deviceInfoSet, deviceInterfaceData, NULL,0, deviceInterfaceDetailDataSize, NULL); requiredSize = deviceInterfaceDetailDataSize; deviceInterfaceDetailData = (PSP_DEVICE_INTERFACE_DETAIL_DATA)\ new DWORD[deviceInterfaceDetailDataSize]; if(deviceInterfaceDetailData) { deviceInterfaceDetailData- cbSize=\ sizeof(SP_INTERFACE_DEVICE_DETAIL_DATA); } else { SetupDiDestroyDeviceInfoList(deviceInfoSet); releaseMemory(deviceInterfaceDetailData); return 0; } if(!SetupDiGetDeviceInterfaceDetail(deviceInfoSet, deviceInterfaceData,deviceInterfaceDetailData, requiredSize, deviceInterfaceDetailDataSize,NULL)){ SetupDiDestroyDeviceInfoList(deviceInfoSet); releaseMemory(deviceInterfaceDetailData); return 0; } } else { if(ERROR_NO_MORE_ITEMS == GetLastError()){ done = TRUE; break; } } cout deviceInterfaceDetailData- DevicePath endl; releaseMemory(deviceInterfaceDetailData); } } SetupDiDestroyDeviceInfoList(deviceInfoSet); FreeLibrary(hHidLib); return memberIndex; } //--------------------------------------------------------- int main(){ cout \nLiczba interfejsów urzÈdzeñ klasy HID w systemie = \ searchInterfaceHidDevices() endl; cout endl; Poleć książkęKup książkę Rozdziaä 5. i Detekcja i identyfikacja urzñdzeþ doäñczonych do magistrali USB 163 system( PAUSE ); return 0; } //--------------------------------------------------------- Funkcja SetupDiGetDeviceRegistryProperty() Zdefiniowana w module setupapi.h funkcja SetupDiGetDeviceRegistryProperty() wy- dobywa wáaĞciwoĞci zainstalowanych urządzeĔ PnP. WáaĞciwoĞci te moĪna równieĪ odczytaü za pomocą edytora rejestru (patrz rozdziaá 2., rysunki 2.4 i 2.5). WINSETUPAPI BOOL WINAPI SetupDiGetDeviceRegistryProperty( IN HDEVINFO DeviceInfoSet, IN PSP_DEVINFO_DATA DeviceInfoData, IN DWORD Property, OUT PDWORD PropertyRegDataType, OPTIONAL OUT PBYTE PropertyBuffer, IN DWORD PropertyBufferSize, OUT PDWORD RequiredSize OPTIONAL ); WskaĨnik DeviceInfoSet jest zwracany przez funkcjĊ SetupDiGetClassDevs(). Parametr DeviceInfoData wskazuje strukturĊ SP_DEVINFO_DATA. Parametr Property identyfikuje wáaĞciwoĞü urządzenia PnP, którą aktualnie chcemy odczytaü. Jest on reprezentowany przez odpowiednie staáe symboliczne, których podzbiór zostaá wykorzystany w kodzie z listingu 5.3. Kompletny zestaw predefiniowanych staáych symbolicznych moĪna odna- leĨü w plikach pomocy. Opcjonalnie uĪywany wskaĨnik PropertyRegDataType wskazu- je typ danej zawierającej wáaĞciwoĞü urządzenia. Parametr PropertyBuffer wskazuje bufor danych, poprzez który odczytamy wáaĞciwoĞci urządzenia. JeĪeli PropertyBuffer przypiszemy wartoĞü NULL, a parametrowi PropertyBufferSize wartoĞü zero, funkcja zwróci Īądany rozmiar bufora danych przechowywany w zmiennej RequiredSize. Pa- rametr PropertyBufferSize okreĞla w bajtach rozmiar bufora wskazywanego przez PropertyBuffer. Listing 5.3. Kod moduáu usb_R5_3.cpp #include windows #pragma option push -a1 #include setupapi #pragma option pop #include assert #include iostream #include cstring using namespace std; void displayError(const char* msg){ Poleć książkęKup książkę 164 USB. Praktyczne programowanie z Windows API w C++ cout msg endl; system( PAUSE ); exit(0); }; //--------------------------------------------------------- template class T inline void releaseMemory(T x) { assert(x != NULL); delete [] x; x = NULL; } //--------------------------------------------------------- GUID classGuid; HMODULE hHidLib; DWORD /*unsigned long*/ memberIndex = 0; DWORD deviceInterfaceDetailDataSize; DWORD requiredSize; HDEVINFO deviceInfoSet; SP_DEVICE_INTERFACE_DATA deviceInterfaceData; PSP_DEVICE_INTERFACE_DETAIL_DATA deviceInterfaceDetailData = NULL; SP_DEVINFO_DATA deviceInfoData; //--------------------------------------------------------- string getRegistryPropertyString(HDEVINFO deviceInfoSet, PSP_DEVINFO_DATA deviceInfoData, DWORD property) { DWORD propertyBufferSize = 0; //DWORD propertyRegDataType = 0; char *propertyBuffer = NULL; SetupDiGetDeviceRegistryProperty(deviceInfoSet, deviceInfoData, property, /* propertyRegDataType*/NULL, NULL, 0, propertyBufferSize); //alokowanie pamiÚci dla bufora danych propertyBuffer = new char[(propertyBufferSize * sizeof(TCHAR))]; bool result=SetupDiGetDeviceRegistryProperty(deviceInfoSet, deviceInfoData, property,/* propertyRegDataType*/NULL, propertyBuffer, propertyBufferSize, NULL); if(!result) releaseMemory(propertyBuffer); return propertyBuffer; } //--------------------------------------------------------- int main(){ void (__stdcall *HidD_GetHidGuid)(OUT LPGUID HidGuid); hHidLib = LoadLibrary( C:\\Windows\\system32\\HID.DLL ); if (!hHidLib) displayError( BïÈd doïÈczenia biblioteki HID.DLL. ); (FARPROC ) HidD_GetHidGuid = GetProcAddress(hHidLib, HidD_GetHidGuid ); if (!HidD_GetHidGuid){ Poleć książkęKup książkę Rozdziaä 5. i Detekcja i identyfikacja urzñdzeþ doäñczonych do magistrali USB 165 FreeLibrary(hHidLib); displayError( Nie znaleziono identyfikatora GUID. ); } HidD_GetHidGuid( classGuid); deviceInfoSet = SetupDiGetClassDevs( classGuid, NULL, NULL, DIGCF_PRESENT | DIGCF_INTERFACEDEVICE); if (deviceInfoSet == INVALID_HANDLE_VALUE) displayError( Nie zidentyfikowano podïÈczonych urzÈdzeñ.\n ); deviceInterfaceData.cbSize = sizeof(SP_DEVICE_INTERFACE_DATA); while(SetupDiEnumDeviceInterfaces(deviceInfoSet, NULL, classGuid, memberIndex, deviceInterfaceData)){ memberIndex++; //inkrementacja numeru interfejsu SetupDiGetDeviceInterfaceDetail(deviceInfoSet, deviceInterfaceData, NULL, 0, deviceInterfaceDetailDataSize, NULL); deviceInterfaceDetailData = (PSP_DEVICE_INTERFACE_DETAIL_DATA) new DWORD[deviceInterfaceDetailDataSize]; deviceInterfaceDetailData- cbSize=sizeof(SP_DEVICE_INTERFACE_DETAIL_DATA); deviceInfoData.cbSize = sizeof(SP_DEVINFO_DATA); if (!SetupDiGetDeviceInterfaceDetail(deviceInfoSet, deviceInterfaceData, deviceInterfaceDetailData, deviceInterfaceDetailDataSize, requiredSize, deviceInfoData)){ releaseMemory(deviceInterfaceDetailData); SetupDiDestroyDeviceInfoList(deviceInfoSet); //displayError ( Nie moĝna pobraÊ informacji o interfejsie.\n ); } //cout deviceInterfaceDetailData- DevicePath endl; cout \nClassDescr: getRegistryPropertyString(deviceInfoSet, deviceInfoData, SPDRP_CLASS); cout \nClassGUID: getRegistryPropertyString(deviceInfoSet, deviceInfoData, SPDRP_CLASSGUID); cout \nCompatibileIDs: getRegistryPropertyString(deviceInfoSet, deviceInfoData, SPDRP_COMPATIBLEIDS); cout \nConfigFlags: getRegistryPropertyString(deviceInfoSet, deviceInfoData, SPDRP_CONFIGFLAGS); cout \nDeviceDescr: getRegistryPropertyString(deviceInfoSet, deviceInfoData, SPDRP_DEVICEDESC); cout \nDriver: getRegistryPropertyString(deviceInfoSet, deviceInfoData, SPDRP_DRIVER); //cout \nFriendlyName: getRegistryPropertyString(deviceInfoSet, // deviceInfoData, SPDRP_FRIENDLYNAME); cout \nHardwareID: getRegistryPropertyString(deviceInfoSet, deviceInfoData, SPDRP_HARDWAREID); cout \nMfg: getRegistryPropertyString(deviceInfoSet, deviceInfoData, SPDRP_MFG); cout \nEnumeratorName: getRegistryPropertyString(deviceInfoSet, deviceInfoData, SPDRP_ENUMERATOR_NAME); cout \nPhysDevObjName: getRegistryPropertyString(deviceInfoSet, deviceInfoData, SPDRP_PHYSICAL_DEVICE_OBJECT_NAME); Poleć książkęKup książkę 166 USB. Praktyczne programowanie z Windows API w C++ cout endl; releaseMemory(deviceInterfaceDetailData); }; //koniec while SetupDiDestroyDeviceInfoList(deviceInfoSet); FreeLibrary(hHidLib); cout endl; system( PAUSE ); return 0; } //--------------------------------------------------------- UĪywanie funkcji SetupDiGetDeviceRegistryProperty() z reguáy nie ogranicza siĊ do pojedynczego wywoáania. W pierwszym wywoáaniu okreĞlamy wymagany rozmiar bufora danych, a w nastĊpnym odczytujemy Īądane wáaĞciwoĞci zainstalowanego w systemie urządzenia PnP. Pokazano to na listingu 5.3 w ciele przykáadowej funkcji getRegistryPropertyString() wydobywającej niektóre wáaĞciwoĞci áaĔcuchowe sprzĊ- tu zgodnego z klasą HID. Rysunek 5.7 przedstawia wynik dziaáania programu cyklicz- nie wywoáującego funkcjĊ getRegistryPropertyString() w celu odczytania wybranych wáaĞciwoĞci áaĔcuchowych urządzeĔ zainstalowanych w systemie. Rysunek 5.7. Aplikacja proj_USB_R5_3 w trakcie dziaáania Poleć książkęKup książkę Rozdziaä 5. i Detekcja i identyfikacja urzñdzeþ doäñczonych do magistrali USB 167 W rejestrze systemowym elementami podkluczy tematycznych są dwa typy danych: áaĔcuchowe (oznaczone jako REG_SZ lub REG_MULTI_SZ) i liczbowe (oznaczone jako REG_DWORD). Testując kod z listingu 5.3, moĪemy zauwaĪyü, Īe funkcja getRegistryPropertyString() wydobywa jedynie wáaĞciwoĞci áaĔcuchowe urządzenia. Aby odzyskaü wáaĞciwoĞü liczbową, naleĪy zmodyfikowaü tĊ funkcjĊ lub, co jest duĪo bardziej poĪyteczne, zbu- dowaü jej odmianĊ, która bĊdzie zwracaáa dane typu DWORD. Na listingu 5.4 zamiesz- czono odpowiedni przykáad funkcji getRegistryPropertyDWORD(), wydobywającej wáa- ĞciwoĞci liczbowe urządzenia zapisane w rejestrze systemowym. Listing 5.4. Kod funkcji getRegistryPropertyDWORD() wraz z jej przykáadowym wywoáaniem //... SP_DEVINFO_DATA deviceInfoData; //--------------------------------------------------------- DWORD getRegistryPropertyDWORD(HDEVINFO deviceInfoSet, PSP_DEVINFO_DATA deviceInfoData, DWORD property) { DWORD propertyBufferSize = 0; DWORD propertyRegDataType = 0; DWORD *propertyBuffer = 0; bool result; SetupDiGetDeviceRegistryProperty(deviceInfoSet, deviceInfoData, property, propertyRegDataType, NULL, 0, propertyBufferSize); //alokowanie pamiÚci dla bufora danych propertyBuffer = new DWORD[(propertyBufferSize * sizeof(DWORD))]; result = SetupDiGetDeviceRegistryProperty(deviceInfoSet, deviceInfoData, property, propertyRegDataType, (char*)propertyBuffer, sizeof(propertyBuffer), NULL); if(!result) releaseMemory(propertyBuffer); return *propertyBuffer; } //--------------------------------------------------------- int main(){ //... cout \nCapabilities getRegistryPropertyDWORD(deviceInfoSet, deviceInfoData, SPDRP_CAPABILITIES); //... } //--------------------------------------------------------- Poleć książkęKup książkę 168 USB. Praktyczne programowanie z Windows API w C++ Struktury danych Elementy opisu urządzeĔ USB, które są dostĊpne w systemie, są czĊsto przechowywa- ne w polach odpowiednio skonstruowanych struktur danych znajdujących siĊ w jednej przestrzeni nazw. Na listingu 5.4 pokazano przykáadową strukturĊ DEVICE_DATA: typedef struct _DEVICE_DATA { TCHAR *HardwareId; //identyfikator sprzÚtu TCHAR *Path; //ïÈcze symboliczne DWORD DeviceInstance; } DEVICE_DATA, *PDEVICE_DATA; //--------------------------------------------------------- Jej pola przechowują przykáadowe dane zawierające identyfikator sprzĊtu (HardwareId), ĞcieĪkĊ dostĊpu do interfejsu urządzenia (Path) oraz DeviceInstance, który bĊdzie lo- kalizowaá element DevInst struktury USB_DEFINFO_DATA. ZawartoĞü struktury DEVICE_ DATA pozwala wstĊpnie zidentyfikowaü urządzenie. Aby w peáni wykorzystaü tak skonstruowany typ danych, naleĪy zadeklarowaü tablicĊ wskaĨników do struktur o rozmiarze nie mniejszym niĪ rzeczywista liczba interfejsów urządzeĔ USB w systemie: PDEVICE_DATA deviceList; //... deviceList = (PDEVICE_DATA)new \ DEVICE_DATA[((memberIndex+1)*sizeof(DEVICE_DATA))]; Warto pamiĊtaü, Īe w przypadku báĊdnego zaalokowania pamiĊci dla tablicy struktur kompilator zgáosi báąd naruszenia pamiĊci. Po prawidáowym zaalokowaniu tablicy struktur okreĞlamy za pomocą funkcji strlen() aktualną dáugoĞü ĞcieĪki dostĊpu do interfejsu urządzenia: size_t nLen = strlen(deviceInterfaceDetailData- DevicePath) + 1; oraz tworzymy tablicĊ ĞcieĪek: deviceList[memberIndex].Path = new TCHAR[(nLen*sizeof(TCHAR))]; ĝcieĪka dostĊpu do interfejsu urządzenia zostaje przekopiowana za pomocą funkcji strncpy() do pola Path elementu (o indeksie memberIndex) tablicy struktur DEVICE_DATA. strncpy(deviceList[memberIndex].Path, deviceInterfaceDetailData- DevicePath, nLen); Od tego momentu program dysponuje indeksowaną ĞcieĪką dostĊpu do interfejsu urzą- dzenia, którą moĪna wykorzystaü na przykáad w funkcji uzyskującej dostĊp do pliku sterownika urządzenia: CreateFile(deviceList[2].Path, ...); Sposoby wypeániania pozostaáych elementów struktury DEVICE_DATA zaprezentowano w kodzie z listingu 5.5, zawierającym funkcjĊ setGetHidDeviceData(). Na rysunku 5.8 pokazano wynik dziaáania omawianego programu. Poleć książkęKup książkę Rozdziaä 5. i Detekcja i identyfikacja urzñdzeþ doäñczonych do magistrali USB 169 Listing 5.5. Kod moduáu usb_R5_4.cpp #include windows #pragma option push -a1 #include setupapi #pragma option pop #include assert #include iostream #include cstring using namespace std; void displayError(const char* msg){ cout msg endl; system( PAUSE ); exit(0); }; //--------------------------------------------------------- template class T inline void releaseMemory(T x) { assert(x != NULL); delete [] x; x = NULL; } //--------------------------------------------------------- typedef struct _DEVICE_DATA { TCHAR *HardwareId; TCHAR *Path; //ïÈcze symboliczne DWORD DeviceInstance; } DEVICE_DATA, *PDEVICE_DATA; //--------------------------------------------------------- int setGetHidDeviceData() { PDEVICE_DATA deviceList; DWORD propertyBufferSize = 0; char *propertyBuffer = NULL; SP_DEVINFO_DATA deviceInfoData; HMODULE hHidLib; HDEVINFO deviceInfoSet; SP_INTERFACE_DEVICE_DATA deviceInterfaceData; DWORD memberIndex = 0; GUID classGuid; PSP_DEVICE_INTERFACE_DETAIL_DATA deviceInterfaceDetailData = NULL; DWORD requiredSize = 0; DWORD deviceInterfaceDetailDataSize = 0; DWORD searchMaxDevice = 100; //maksymalna liczba interfejsów urzÈdzeñ bool done = false; void (__stdcall *HidD_GetHidGuid)(OUT LPGUID HidGuid); hHidLib = LoadLibrary( C:\\Windows\\system32\\HID.DLL ); if (!hHidLib) displayError( BïÈd doïÈczenia biblioteki HID.DLL. ); (FARPROC ) HidD_GetHidGuid = GetProcAddress(hHidLib, HidD_GetHidGuid ); Poleć książkęKup książkę 170 USB. Praktyczne programowanie z Windows API w C++ if (!HidD_GetHidGuid){ FreeLibrary(hHidLib); displayError( Nie znaleziono identyfikatora GUID. ); } HidD_GetHidGuid ( classGuid); deviceInfoSet = SetupDiGetClassDevs( classGuid, NULL, NULL, (DIGCF_PRESENT | DIGCF_DEVICEINTERFACE)); deviceInterfaceData.cbSize = sizeof(SP_INTERFACE_DEVICE_DATA); while(!done) { deviceList = new DEVICE_DATA[((memberIndex+1)*sizeof(DEVICE_DATA))]; for(; memberIndex searchMaxDevice; memberIndex++) { if(SetupDiEnumDeviceInterfaces(deviceInfoSet,0, classGuid, memberIndex, deviceInterfaceData)) { SetupDiGetDeviceInterfaceDetail(deviceInfoSet, deviceInterfaceData, NULL,0, deviceInterfaceDetailDataSize, NULL); requiredSize = deviceInterfaceDetailDataSize; deviceInterfaceDetailData = (PSP_DEVICE_INTERFACE_DETAIL_DATA)\ new DWORD[deviceInterfaceDetailDataSize]; if(deviceInterfaceDetailData) { deviceInterfaceDetailData- cbSize=\ sizeof(SP_INTERFACE_DEVICE_DETAIL_DATA); } else { SetupDiDestroyDeviceInfoList(deviceInfoSet); releaseMemory(deviceInterfaceDetailData); return 0; } deviceInfoData.cbSize = sizeof(SP_DEVINFO_DATA); if (!SetupDiGetDeviceInterfaceDetail(deviceInfoSet, deviceInterfaceData, deviceInterfaceDetailData, deviceInterfaceDetailDataSize, requiredSize, deviceInfoData)) { SetupDiDestroyDeviceInfoList(deviceInfoSet); releaseMemory(deviceInterfaceDetailData); return 0; } size_t nLen = strlen(deviceInterfaceDetailData- DevicePath) + 1; deviceList[memberIndex].Path = new TCHAR[(nLen*sizeof(TCHAR))]; strncpy(deviceList[memberIndex].Path, deviceInterfaceDetailData- DevicePath, nLen); cout \nDeviceList[ memberIndex ].Path: \n deviceList[memberIndex].Path endl; deviceList[memberIndex].DeviceInstance = deviceInfoData.DevInst; SetupDiGetDeviceRegistryProperty(deviceInfoSet, deviceInfoData, SPDRP_HARDWAREID, NULL, NULL, 0, propertyBufferSize); Poleć książkęKup książkę Rozdziaä 5. i Detekcja i identyfikacja urzñdzeþ doäñczonych do magistrali USB 171 //alokowanie pamiÚci dla bufora danych propertyBuffer = new char[(propertyBufferSize*sizeof(TCHAR))]; SetupDiGetDeviceRegistryProperty(deviceInfoSet, deviceInfoData, SPDRP_HARDWAREID,NULL, propertyBuffer, propertyBufferSize, NULL); deviceList[memberIndex].HardwareId = propertyBuffer; cout
Pobierz darmowy fragment (pdf)

Gdzie kupić całą publikację:

USB. Praktyczne programowanie z Windows API w C++. Wydanie II
Autor:

Opinie na temat publikacji:


Inne popularne pozycje z tej kategorii:


Czytaj również:


Prowadzisz stronę lub blog? Wstaw link do fragmentu tej książki i współpracuj z Cyfroteką: