创建线程消息循环服务于动态连接库
Posted 非法关键字
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了创建线程消息循环服务于动态连接库相关的知识,希望对你有一定的参考价值。
因为动态连接库需要对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, ¬ificationFilter, 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 }
涉及的一些内容:
- 线程中CreateWindowEx的调用
- 在CreateWindowEx中使用HWND_MESSAGE的作用
- PostThreadMessage与PostMessage使用上区别的地方
以上是关于创建线程消息循环服务于动态连接库的主要内容,如果未能解决你的问题,请参考以下文章