1. 程式人生 > >創建線程消息循環服務於動態連接庫

創建線程消息循環服務於動態連接庫

define rep 處理 col hang 應用 作用 erro pos

因為動態連接庫需要對DBT_DEVICEARRIVAL、DBT_DEVICEREMOVECOMPLETE等消息的處理,所以拿一個不太理想的usb-hid的dll來說明,不多說直接上代碼


 1 // 下列 ifdef 塊是創建使從 DLL 導出更簡單的
 2 // 宏的標準方法。此 DLL 中的所有文件都是用命令行上定義的 WIN32USB_EXPORTS
 3 // 符號編譯的。在使用此 DLL 的
 4 // 任何其他項目上不應定義此符號。這樣,源文件中包含此文件的任何其他項目都會將
 5 // WIN32USB_API 函數視為是從 DLL 導入的,而此 DLL 則將用此宏定義的
 6 // 符號視為是被導出的。
7 #ifdef WIN32USB_EXPORTS 8 #define WIN32USB_API __declspec(dllexport) 9 #else 10 #define WIN32USB_API __declspec(dllimport) 11 #endif 12 13 #ifdef __cplusplus 14 extern "C"{ 15 #endif 16 17 typedef void(*UsbHandler)(); 18 19 WIN32USB_API void UsbInit(int vid, int pid); 20 WIN32USB_API void
UsbNotify(UsbHandler arrival, UsbHandler removed); 21 WIN32USB_API int UsbWrite(unsigned char *dat); 22 WIN32USB_API BOOL UsbRead(unsigned char *dat); 23 WIN32USB_API int InputReportByteLength(); 24 WIN32USB_API int OutputReportByteLength(); 25 WIN32USB_API bool Connected(); 26 WIN32USB_API void
UsbFree(); 27 28 #ifdef __cplusplus 29 } 30 #endif
  1 // Win32Usb.cpp : 定義 DLL 應用程序的導出函數。
  2 //
  3 
  4 #include "stdafx.h"
  5 #include "Win32Usb.h"
  6 #include <Dbt.h>
  7 
  8 #pragma comment(lib, "hid.lib")
  9 #pragma comment(lib, "setupapi.lib")
 10 
 11 bool connected = false;
 12 int inputReportByteLength;
 13 int outputReportByteLength;
 14 
 15 int usb_vid = 0;
 16 int usb_pid = 0;
 17 
 18 HANDLE hUsbWriter = INVALID_HANDLE_VALUE;
 19 HANDLE hUsbReader = INVALID_HANDLE_VALUE;
 20 
 21 // 消息循環線程ID
 22 DWORD msglooper_tid = 0;
 23 HANDLE msgl_handle = INVALID_HANDLE_VALUE;
 24 WNDCLASS wndClass = { 0 };
 25 HDEVNOTIFY hDevnotify = INVALID_HANDLE_VALUE;
 26 
 27 UsbHandler UsbArrivalHandler;
 28 UsbHandler UsbRemovedHandler;
 29 
 30 OVERLAPPED ovw = {0};
 31 OVERLAPPED ovr = {0};
 32 
 33 bool UsbFind();
 34 
 35 WIN32USB_API void UsbInit(int vid, int pid)
 36 {
 37     usb_vid = vid;
 38     usb_pid = pid;
 39 
 40     UsbFind();
 41 }
 42 
 43 bool UsbFind()
 44 {
 45     GUID guid;
 46     HidD_GetHidGuid(&guid);
 47     HDEVINFO hdevinfo = SetupDiGetClassDevs(&guid, 0, 0, DIGCF_PRESENT | DIGCF_DEVICEINTERFACE);
 48 
 49     SP_DEVICE_INTERFACE_DATA device_interface_data;
 50     ZeroMemory(&device_interface_data, sizeof(device_interface_data));
 51     device_interface_data.cbSize = sizeof(device_interface_data);
 52 
 53     //SP_DEVINFO_DATA devinfo_data;
 54     //devinfo_data.cbSize = sizeof(devinfo_data);
 55     //devinfo_data.ClassGuid = guid;
 56 
 57     int device_interface_index = 0;
 58     while (SetupDiEnumDeviceInterfaces(hdevinfo, NULL, &guid, device_interface_index, &device_interface_data))
 59     {
 60         //SP_DEVICE_INTERFACE_DETAIL_DATA device_interface_detail_data;
 61         //ZeroMemory(&device_interface_detail_data, sizeof(device_interface_detail_data));
 62         //device_interface_detail_data.cbSize = sizeof(device_interface_detail_data);
 63         DWORD requireSize;
 64         SetupDiGetDeviceInterfaceDetail(hdevinfo, &device_interface_data, NULL, 0, &requireSize, NULL);
 65 
 66         PSP_DEVICE_INTERFACE_DETAIL_DATA psp_device_interface_detail_data = (PSP_DEVICE_INTERFACE_DETAIL_DATA)malloc(requireSize);
 67         psp_device_interface_detail_data->cbSize = sizeof(SP_DEVICE_INTERFACE_DETAIL_DATA);
 68         if (SetupDiGetDeviceInterfaceDetail(hdevinfo, &device_interface_data, psp_device_interface_detail_data, requireSize, &requireSize, NULL))
 69         {
 70             char * _devicePath = psp_device_interface_detail_data->DevicePath;
 71             free(psp_device_interface_detail_data);
 72 
 73             HANDLE _hDevice = CreateFile(_devicePath,
 74                 GENERIC_READ, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, NULL, NULL);
 75             if (_hDevice != INVALID_HANDLE_VALUE)
 76             {
 77                 HIDD_ATTRIBUTES hidd_attributes;
 78                 HidD_GetAttributes(_hDevice, &hidd_attributes);
 79                 if (hidd_attributes.VendorID == usb_vid && hidd_attributes.ProductID == usb_pid)
 80                 {
 81                     PHIDP_PREPARSED_DATA phidp_preparsed_data;
 82                     HidD_GetPreparsedData(_hDevice, &phidp_preparsed_data);
 83                     HIDP_CAPS hidp_caps;
 84                     HidP_GetCaps(phidp_preparsed_data, &hidp_caps);
 85                     inputReportByteLength = hidp_caps.InputReportByteLength;
 86                     outputReportByteLength = hidp_caps.OutputReportByteLength;
 87                     HidD_FreePreparsedData(phidp_preparsed_data);
 88 
 89                     hUsbWriter = CreateFile(_devicePath, GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, 
 90                         FILE_ATTRIBUTE_NORMAL | FILE_FLAG_OVERLAPPED, NULL);
 91                     hUsbReader = CreateFile(_devicePath, GENERIC_READ, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, 
 92                         FILE_ATTRIBUTE_NORMAL | FILE_FLAG_OVERLAPPED, NULL);
 93 
 94                     SetupDiDestroyDeviceInfoList(hdevinfo);
 95                     CloseHandle(_hDevice);
 96                     connected = true;
 97                     return true;
 98                 }
 99 
100                 CloseHandle(_hDevice);
101             }
102         }
103 
104         device_interface_index++;
105     }
106 
107     SetupDiDestroyDeviceInfoList(hdevinfo);
108     return false;
109 }
110 
111 WIN32USB_API BOOL UsbRead(unsigned char *dat)
112 {
113     if (connected && hUsbReader != INVALID_HANDLE_VALUE)
114     {
115         DWORD read_size;
116         BOOL rt = ReadFile(hUsbReader, dat, inputReportByteLength, &read_size, &ovr);
117         if (!rt)
118         {
119             if (GetLastError() == ERROR_IO_PENDING)
120             {
121                 // 此時是否需要對IO狀態作處理看需求,處理與否不會影響IO
122                 //rt = WaitForSingleObject(hUsbReader, 50);
123                 //switch (rt)
124                 //{
125                 //case WAIT_OBJECT_0:
126                 //    cout << "指定的對象處於有信號狀態" << endl;
127                 //    if (GetOverlappedResult(hUsbReader, &ovr, &read_size, FALSE))
128                 //        cout << "read " << read_size << " bytes" << endl;
129                 //    break;
130                 //case WAIT_TIMEOUT:
131                 //    cout << "等待超時" << endl;
132                 //    break;
133                 //case WAIT_FAILED:
134                 //    cout << "出現錯誤,CODE [" << GetLastError() << "]" << endl;
135                 //    break;
136                 //case WAIT_ABANDONED:
137                 //    cout << "當Handle為mutex時,如果擁有mutex的線程在結束時沒有釋放核心對象會引發此返回值" << endl;
138                 //    break;
139                 //}
140 
141                 // 這裏是神精病代碼<網絡上此類代碼非常多>
142                 //WaitForSingleObjectEx(hUsbReader, INFINITE, TRUE);
143                 //rt = GetOverlappedResult(hUsbReader, &ovr, &factBytes, FALSE);
144                 //return rt;
145             }
146             else
147             {
148                 CancelIo(hUsbReader);
149                 return FALSE;
150             }
151         }
152         else return TRUE;
153     }
154 
155     return FALSE;
156 }
157 
158 WIN32USB_API int UsbWrite(unsigned char *dat)
159 {
160     if (connected && hUsbWriter != INVALID_HANDLE_VALUE)
161     {
162         DWORD write_size;
163         BOOL rt = WriteFile(hUsbWriter, dat, outputReportByteLength, &write_size, &ovw);
164         if (!rt)
165         {
166             if (GetLastError() == ERROR_IO_PENDING)
167             {
168                 // 此時是否需要對IO狀態作處理看需求,處理與否不會影響IO
169                 //rt = WaitForSingleObject(hUsbWriter, 50);
170                 //switch (rt)
171                 //{
172                 //case WAIT_OBJECT_0:
173                 //    cout << "指定的對象處於有信號狀態" << endl;
174                 //    if (GetOverlappedResult(hUsbWriter, &ovr, &write_size, FALSE))
175                 //        cout << "write " << write_size << " bytes" << endl;
176                 //    break;
177                 //case WAIT_TIMEOUT:
178                 //    cout << "等待超時" << endl;
179                 //    break;
180                 //case WAIT_FAILED:
181                 //    cout << "出現錯誤,CODE [" << GetLastError() << "]" << endl;
182                 //    break;
183                 //case WAIT_ABANDONED:
184                 //    cout << "當Handle為mutex時,如果擁有mutex的線程在結束時沒有釋放核心對象會引發此返回值" << endl;
185                 //    break;
186                 //}
187 
188                 // 這裏是神精病代碼<網絡上此類代碼非常多>
189                 //WaitForSingleObjectEx(hUsbWriter, INFINITE, TRUE);
190                 //rt = GetOverlappedResult(hUsbWriter, &ovw, &write_size, FALSE);
191                 //if (!rt) return 0;
192             }
193             else
194             {
195                 CancelIo(hUsbWriter);
196                 return 0;
197             }
198         }
199         return write_size;
200     }
201 
202     return 0;
203 }
204 
205 WIN32USB_API int InputReportByteLength(){return inputReportByteLength;}
206 WIN32USB_API int OutputReportByteLength(){ return outputReportByteLength; }
207 WIN32USB_API bool Connected(){ return connected; }
208 
209 LRESULT CALLBACK WndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
210 {
211     if (msg == WM_DEVICECHANGE)
212     {
213         //MessageBox(NULL, TEXT("WM_DEVICECHANGE"), TEXT("WndProc"), MB_OK);
214         //return 0;
215         switch (wParam)
216         {
217         case DBT_DEVICEARRIVAL:
218             //printf("[wndproc]device arrival.");            
219             if (!connected)
220             {
221                 if (UsbFind())
222                 {
223                     if (UsbArrivalHandler != NULL) UsbArrivalHandler();
224                 }
225             }
226             break;
227         case DBT_DEVICEREMOVECOMPLETE:
228             //printf("[wndproc]device remove.");            
229             if (connected)
230             {
231                 if (!UsbFind())
232                 {
233                     connected = false;
234                     if (hUsbWriter != INVALID_HANDLE_VALUE)
235                     {
236                         CloseHandle(hUsbWriter);
237                         hUsbWriter = INVALID_HANDLE_VALUE;
238                     }
239                     if (hUsbReader != INVALID_HANDLE_VALUE)
240                     {
241                         CloseHandle(hUsbReader);
242                         hUsbReader = INVALID_HANDLE_VALUE;
243                     }                    
244 
245                     if (UsbRemovedHandler != NULL) UsbRemovedHandler();
246                 }
247             }
248             break;
249         default:
250             break;
251         }
252     }
253 
254     return DefWindowProc(hWnd, msg, wParam, lParam);
255 }
256 
257 void MessageLooper()
258 {
259     GUID guid;
260     HINSTANCE hInstance = reinterpret_cast<HINSTANCE>(GetModuleHandle(NULL));
261     wndClass.lpfnWndProc = &WndProc;
262     wndClass.lpszClassName = TEXT("Win32Usb");
263     wndClass.hInstance = hInstance;
264     if (RegisterClass(&wndClass))
265     {
266         // 註意HWND_MESSAGE的關鍵使用
267         HWND wnd = CreateWindowEx(0, wndClass.lpszClassName, NULL, 0, 0, 0, 0, 0, HWND_MESSAGE, NULL, hInstance, NULL);
268         if (wnd != NULL)
269         {
270             HidD_GetHidGuid(&guid);
271             DEV_BROADCAST_DEVICEINTERFACE notificationFilter = { 0 };
272             notificationFilter.dbcc_size = sizeof(notificationFilter);
273             notificationFilter.dbcc_classguid = guid;
274             notificationFilter.dbcc_devicetype = DBT_DEVTYP_DEVICEINTERFACE;
275             hDevnotify = RegisterDeviceNotification(wnd, &notificationFilter, DEVICE_NOTIFY_WINDOW_HANDLE);
276 
277             if (hDevnotify != NULL)
278             {
279                 MSG msg;
280                 if (GetMessage(&msg, NULL, 0, 0) > 0)
281                 {
282                     TranslateMessage(&msg);
283                     DispatchMessage(&msg);
284                 }
285 
286                 connected = false;
287                 if (hUsbWriter != INVALID_HANDLE_VALUE)
288                 {
289                     CloseHandle(hUsbWriter);
290                     hUsbWriter = INVALID_HANDLE_VALUE;
291                 }
292                 if (hUsbReader != INVALID_HANDLE_VALUE)
293                 {
294                     CloseHandle(hUsbReader);
295                     hUsbReader = INVALID_HANDLE_VALUE;
296                 }
297 
298                 UnregisterDeviceNotification(hDevnotify);
299             }
300             DestroyWindow(wnd);
301             UnregisterClass(wndClass.lpszClassName, hInstance);
302         }
303     }
304 }
305 
306 WIN32USB_API void UsbNotify(UsbHandler arrival, UsbHandler removed)
307 {
308     UsbArrivalHandler = arrival;
309     UsbRemovedHandler = removed;
310     // 創建線程消息循環
311     msgl_handle = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)MessageLooper, NULL, THREAD_PRIORITY_NORMAL, &msglooper_tid);
312 }
313 
314 WIN32USB_API void UsbFree()
315 {
316     connected = false;
317     // 關閉僅提供消息循環HWND_MESSAGE標識窗口
318     PostThreadMessage(msglooper_tid, WM_CLOSE, 0, 0);
319     CloseHandle(msgl_handle);
320 }

涉及的一些內容:

  1. 線程中CreateWindowEx的調用
  2. 在CreateWindowEx中使用HWND_MESSAGE的作用
  3. PostThreadMessage與PostMessage使用上區別的地方

創建線程消息循環服務於動態連接庫