1. 程式人生 > >C++/CLI混合編程<Hid示例>

C++/CLI混合編程<Hid示例>

erl rep idp fault over broadcast image patch found

異步IO,支持拔插事件

HidCore
 1 #pragma once
 2 #include "stdafx.h"
 3 #include "HidEvent.h"
 4 
 5 using namespace System;
 6 using namespace System::Diagnostics;
 7 delegate LRESULT HidCoreWndProc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam);
 8 delegate DWORD HidCoreThreadStart(LPVOID lparam);
 9
10 namespace ZSHid 11 { 12 public ref class HidCore 13 { 14 public: 15 HidCore(int vid, int pid); 16 virtual ~HidCore(); 17 18 bool FindMyDevice(); 19 int Write(array<Byte> ^data); 20 int Read(array<Byte> ^data); 21 void
NotifyEvents(Action ^deviceArrival, Action ^deviceRemoved); 22 23 property int InputReportLen 24 { 25 int get(); 26 } 27 28 property int OutputReportLen 29 { 30 int get(); 31 } 32 33 property bool IsConnected 34 {
35 bool get(); 36 } 37 38 Action ^_deviceArrival; 39 Action ^_deviceRemoved; 40 41 42 private: 43 int _vid; 44 int _pid; 45 int _inputReportLen; 46 int _outputReportLen; 47 bool _isConnected; 48 HANDLE _readHandle; 49 HANDLE _writeHandle; 50 DWORD _threadMessageId; 51 HANDLE _threadMessageHandle; 52 HidEvent *_hidEvent; 53 54 OVERLAPPED *_ovlpw; 55 OVERLAPPED *_ovlpr; 56 unsigned char *_readBuffer; 57 unsigned char *_writeBuffer; 58 }; 59 }
技術分享圖片
  1 #include "stdafx.h"
  2 #include "HidCore.h"
  3 #include <vcclr.h>
  4 
  5 using namespace ZSHid;
  6 #pragma comment(lib, "hid.lib")
  7 #pragma comment(lib, "setupapi.lib")
  8 
  9 void HidCore::NotifyEvents(Action ^ deviceArrival, Action ^ deviceRemoved)
 10 {
 11     _deviceArrival = deviceArrival;
 12     _deviceRemoved = deviceRemoved;
 13 
 14     // 創建線程消息循環
 15     pin_ptr<DWORD> pthreadMessageId = &_threadMessageId;
 16     _threadMessageHandle = CreateThread(NULL, 0,
 17         (LPTHREAD_START_ROUTINE)HidEvent::ThreadMessageProc,
 18         NULL, THREAD_PRIORITY_NORMAL,
 19         &(*pthreadMessageId));
 20     if (_threadMessageHandle == INVALID_HANDLE_VALUE)
 21     {
 22         int error = GetLastError();
 23         Console::ForegroundColor = ConsoleColor::Blue;
 24         Console::WriteLine("[CreateThread Error]GetLastError = " + error);
 25         Console::ResetColor();
 26     }
 27 }
 28 
 29 HidCore::HidCore(int vid, int pid)
 30 {
 31     _vid = vid;
 32     _pid = pid;
 33 
 34     OVERLAPPED ovlpw = { 0 };
 35     OVERLAPPED ovlpr = { 0 };
 36     _ovlpw = &ovlpw;
 37     _ovlpr = &ovlpr;
 38 
 39     _readBuffer = new unsigned char[256];
 40     _writeBuffer = new unsigned char[256];
 41 
 42     gcroot<HidCore^> *phidCore = new gcroot<HidCore^>(this);
 43     _hidEvent = new HidEvent(phidCore);
 44 
 45     FindMyDevice();
 46 }
 47 
 48 HidCore::~HidCore()
 49 {
 50     _isConnected = false;
 51     PostThreadMessage(_threadMessageId, WM_CLOSE, 0, 0);
 52     CloseHandle(_threadMessageHandle);
 53 
 54     delete _readBuffer;
 55     delete _writeBuffer;
 56     if (_hidEvent != nullptr) delete _hidEvent;
 57 }
 58 
 59 bool HidCore::FindMyDevice()
 60 {
 61     bool isFind = false;
 62     GUID guid;
 63     HidD_GetHidGuid(&guid);
 64     HDEVINFO hdevinfo = SetupDiGetClassDevs(&guid, 0, 0, DIGCF_PRESENT | DIGCF_DEVICEINTERFACE);
 65     SP_DEVICE_INTERFACE_DATA device_interface_data;
 66     ZeroMemory(&device_interface_data, sizeof(device_interface_data));
 67     device_interface_data.cbSize = sizeof(device_interface_data);
 68 
 69     int device_interface_index = 0;
 70     while (SetupDiEnumDeviceInterfaces(hdevinfo, NULL, &guid, device_interface_index, &device_interface_data))
 71     {
 72         DWORD requireSize;
 73         SetupDiGetDeviceInterfaceDetail(hdevinfo, &device_interface_data, NULL, 0, &requireSize, NULL);
 74         PSP_DEVICE_INTERFACE_DETAIL_DATA psp_device_interface_detail_data = (PSP_DEVICE_INTERFACE_DETAIL_DATA)malloc(requireSize);
 75         psp_device_interface_detail_data->cbSize = sizeof(SP_DEVICE_INTERFACE_DETAIL_DATA);
 76         if (SetupDiGetDeviceInterfaceDetail(hdevinfo, &device_interface_data, psp_device_interface_detail_data, requireSize, &requireSize, NULL))
 77         {
 78             TCHAR *device_path = psp_device_interface_detail_data->DevicePath;
 79 
 80             // 打印設備路徑[將TCHAR *轉換為System::String^]
 81             String ^str = gcnew String(device_path);
 82             Console::ForegroundColor = ConsoleColor::Blue;
 83             Console::WriteLine(str);
 84             Console::ResetColor();
 85 
 86             HANDLE handle = CreateFile(device_path, GENERIC_READ, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, NULL, NULL);
 87             if (handle != INVALID_HANDLE_VALUE)
 88             {
 89                 HIDD_ATTRIBUTES hidd_attributes;
 90                 HidD_GetAttributes(handle, &hidd_attributes);
 91                 if (hidd_attributes.VendorID == _vid && hidd_attributes.ProductID == _pid)
 92                 {
 93                     PHIDP_PREPARSED_DATA phidp_preparsed_data;
 94                     HidD_GetPreparsedData(handle, &phidp_preparsed_data);
 95                     HIDP_CAPS hidp_caps;
 96                     HidP_GetCaps(phidp_preparsed_data, &hidp_caps);
 97                     _inputReportLen = hidp_caps.InputReportByteLength;
 98                     _outputReportLen = hidp_caps.OutputReportByteLength;
 99                     HidD_FreePreparsedData(phidp_preparsed_data);
100 
101                     _readHandle = CreateFile(device_path, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL | FILE_FLAG_OVERLAPPED, NULL);
102                     _writeHandle = CreateFile(device_path, GENERIC_WRITE, FILE_SHARE_WRITE, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL | FILE_FLAG_OVERLAPPED, NULL);
103 
104                     isFind = true;
105                     CloseHandle(handle);
106                     free(psp_device_interface_detail_data);
107                     break;
108                 }
109 
110                 CloseHandle(handle);
111             }
112         }
113         else
114         {
115             int error = GetLastError();
116             Console::ForegroundColor = ConsoleColor::Blue;
117             Console::WriteLine("[SetupDiGetDeviceInterfaceDetail Error]GetLastError = " + error);
118             Console::ResetColor();
119         }
120 
121         device_interface_index++;
122         free(psp_device_interface_detail_data);
123     }
124 
125     SetupDiDestroyDeviceInfoList(hdevinfo);
126     _isConnected = isFind;
127     if (!_isConnected)
128     {
129         CloseHandle(_writeHandle);
130         CloseHandle(_readHandle);
131         _writeHandle = _readHandle = INVALID_HANDLE_VALUE;
132     }
133 
134     return isFind;
135 }
136 
137 int HidCore::Write(array<Byte> ^data)
138 {
139     DWORD write_size = 0;
140     if (IsConnected && _writeHandle != INVALID_HANDLE_VALUE)
141     {
142         for (int i = 0; i < data->Length; i++) _writeBuffer[i] = data[i];
143         BOOL rt = WriteFile(_writeHandle, _writeBuffer, OutputReportLen, &write_size, _ovlpw);
144         if (!rt)
145         {
146             if (ERROR_IO_PENDING == GetLastError())
147             {
148                 // 此時是否需要對IO狀態作處理看需求,處理與否不會影響IO
149                 //rt = WaitForSingleObject(hUsbWriter, 50);
150                 //switch (rt)
151                 //{
152                 //case WAIT_OBJECT_0:
153                 //    cout << "指定的對象處於有信號狀態" << endl;
154                 //    if (GetOverlappedResult(hUsbWriter, &ovr, &write_size, FALSE))
155                 //        cout << "write " << write_size << " bytes" << endl;
156                 //    break;
157                 //case WAIT_TIMEOUT:
158                 //    cout << "等待超時" << endl;
159                 //    break;
160                 //case WAIT_FAILED:
161                 //    cout << "出現錯誤,CODE [" << GetLastError() << "]" << endl;
162                 //    break;
163                 //case WAIT_ABANDONED:
164                 //    cout << "當Handle為mutex時,如果擁有mutex的線程在結束時沒有釋放核心對象會引發此返回值" << endl;
165                 //    break;
166                 //}
167             }
168             else
169             {
170                 CancelIo(_writeHandle);
171 
172                 Console::ForegroundColor = ConsoleColor::Blue;
173                 Console::WriteLine("[WriteFile Error]GetLastError = " + GetLastError());
174                 Console::ResetColor();
175             }
176         }
177     }
178 
179     return write_size;
180 }
181 
182 int HidCore::Read(array<Byte> ^data)
183 {
184     DWORD read_size = 0;
185     if (IsConnected && _readHandle != INVALID_HANDLE_VALUE)
186     {
187         BOOL rt = ReadFile(_readHandle, _readBuffer, InputReportLen, &read_size, _ovlpr);
188         if (!rt)
189         {
190             if (ERROR_IO_PENDING == GetLastError())
191             {
192                 // 此時是否需要對IO狀態作處理看需求,處理與否不會影響IO
193                 //rt = WaitForSingleObject(hUsbReader, 50);
194                 //switch (rt)
195                 //{
196                 //case WAIT_OBJECT_0:
197                 //    cout << "指定的對象處於有信號狀態" << endl;
198                 //    if (GetOverlappedResult(hUsbReader, &ovr, &read_size, FALSE))
199                 //        cout << "read " << read_size << " bytes" << endl;
200                 //    break;
201                 //case WAIT_TIMEOUT:
202                 //    cout << "等待超時" << endl;
203                 //    break;
204                 //case WAIT_FAILED:
205                 //    cout << "出現錯誤,CODE [" << GetLastError() << "]" << endl;
206                 //    break;
207                 //case WAIT_ABANDONED:
208                 //    cout << "當Handle為mutex時,如果擁有mutex的線程在結束時沒有釋放核心對象會引發此返回值" << endl;
209                 //    break;
210                 //}
211             }
212             else
213             {
214                 CancelIo(_readHandle);
215 
216                 Console::ForegroundColor = ConsoleColor::Blue;
217                 Console::WriteLine("[ReadFile Error]GetLastError = " + GetLastError());
218                 Console::ResetColor();
219             }
220         }
221         else
222         {
223             for (int i = 0; i < read_size; i++) data[i] = _readBuffer[i];
224         }
225     }
226 
227     return read_size;
228 }
229 
230 int HidCore::InputReportLen::get()
231 {
232     return _inputReportLen;
233 }
234 
235 int HidCore::OutputReportLen::get()
236 {
237     return _outputReportLen;
238 }
239 
240 bool HidCore::IsConnected::get()
241 {
242     return _isConnected;
243 }
View Code
HidEvent 
 1 #pragma once
 2 
 3 namespace ZSHid
 4 {
 5     class HidEvent
 6     {
 7     public:
 8         HidEvent(void *hidCore);
 9         virtual ~HidEvent();
10 
11         static DWORD ThreadMessageProc(LPVOID lparam);
12         static LRESULT CALLBACK WndProc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam);
13 
14     private:
15         static void *_hidCore;
16         static HDEVNOTIFY _devnotifyHandle;
17     };
18 }
技術分享圖片
  1 #include "stdafx.h"
  2 #include "HidEvent.h"
  3 #include "HidCore.h"
  4 #include <Dbt.h>
  5 #include <vcclr.h>
  6 
  7 using namespace ZSHid;
  8 
  9 void * HidEvent::_hidCore = nullptr;
 10 HDEVNOTIFY HidEvent::_devnotifyHandle = INVALID_HANDLE_VALUE;
 11 
 12 HidEvent::HidEvent(void * hidCore)
 13 {
 14     _hidCore = hidCore;    
 15 }
 16 
 17 HidEvent::~HidEvent()
 18 {
 19     if (_hidCore != nullptr)
 20         delete _hidCore;
 21 }
 22 
 23 DWORD HidEvent::ThreadMessageProc(LPVOID lparam)
 24 {
 25     HINSTANCE hInstance = reinterpret_cast<HINSTANCE>(GetModuleHandle(NULL));
 26     WNDCLASS wndClass = { 0 };
 27     wndClass.lpfnWndProc = HidEvent::WndProc;
 28     wndClass.lpszClassName = _T("ZSHid");
 29     wndClass.hInstance = hInstance;
 30     if (RegisterClass(&wndClass))
 31     {
 32         // HWND_MESSAGE表示創建的為線程消息循環
 33         HWND hwnd = CreateWindowEx(0, wndClass.lpszClassName, NULL, 0, 0, 0, 0, 0,
 34             HWND_MESSAGE, NULL, hInstance, NULL);
 35         if (hwnd != INVALID_HANDLE_VALUE)
 36         {
 37             GUID guid;
 38             HidD_GetHidGuid(&guid);
 39             DEV_BROADCAST_DEVICEINTERFACE notificationFilter = { 0 };
 40             notificationFilter.dbcc_size = sizeof(DEV_BROADCAST_DEVICEINTERFACE);
 41             notificationFilter.dbcc_classguid = guid;
 42             notificationFilter.dbcc_devicetype = DBT_DEVTYP_DEVICEINTERFACE;
 43             _devnotifyHandle = RegisterDeviceNotification(hwnd, &notificationFilter, DEVICE_NOTIFY_WINDOW_HANDLE);
 44 
 45             if (_devnotifyHandle != INVALID_HANDLE_VALUE)
 46             {
 47                 Console::ForegroundColor = ConsoleColor::Blue;
 48                 Console::WriteLine("Notify註冊成功,即將進入消息循環.");
 49                 Console::ResetColor();
 50 
 51                 MSG msg;
 52                 if (GetMessage(&msg, NULL, 0, 0) > 0)
 53                 {
 54                     TranslateMessage(&msg);
 55                     DispatchMessage(&msg);
 56                 }
 57             }
 58 
 59             // 消息循環退出
 60             Console::ForegroundColor = ConsoleColor::Blue;
 61             Console::WriteLine("消息循環已退出........................");
 62             Console::ResetColor();
 63 
 64             UnregisterDeviceNotification(_devnotifyHandle);
 65             DestroyWindow(hwnd);
 66             UnregisterClass(wndClass.lpszClassName, hInstance);
 67         }
 68     }
 69 
 70     return 0;
 71 }
 72 
 73 LRESULT  CALLBACK HidEvent::WndProc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam)
 74 {
 75     if (msg == WM_DEVICECHANGE)
 76     {
 77         switch (wparam)
 78         {
 79         case DBT_DEVICEARRIVAL:
 80         {
 81             gcroot<HidCore^> *hc = (gcroot<HidCore^> *)_hidCore;
 82             if (!(*hc)->IsConnected)
 83             {
 84                 if ((*hc)->FindMyDevice())
 85                 {
 86                     Console::ForegroundColor = ConsoleColor::Blue;
 87                     Console::WriteLine("MY HID DEVICE IS FOUND AND OPEN.");
 88                     Console::ResetColor();
 89                     (*hc)->_deviceArrival();
 90                 }
 91             }
 92         }
 93             break;
 94         case DBT_DEVICEREMOVECOMPLETE:
 95         {
 96             gcroot<HidCore^> *hc = (gcroot<HidCore^> *)_hidCore;
 97             if (!(*hc)->FindMyDevice())
 98             {
 99                 Console::ForegroundColor = ConsoleColor::Blue;
100                 Console::WriteLine("MY HID DEVICE REMOVED.");
101                 Console::ResetColor();
102                 (*hc)->_deviceRemoved();
103             }
104         }
105             break;
106         default:
107             break;
108         }
109     }
110 
111     return DefWindowProc(hwnd, msg, wparam, lparam);
112 }
View Code

C++/CLI的優點就是C++或者是C#可以引入後直接使用,不必要以C接口方法來調入,dll中不需要其它工具就可以隨意打印調試信息.


在C#中的使用

 1 using System;
 2 using ZSHid;
 3 
 4 namespace ZSHidApp
 5 {
 6     class Program
 7     {
 8         static void Main(string[] args)
 9         {
10             HidCore hid = new HidCore(0x0b6a, 0x5346);
11             hid.NotifyEvents(() =>
12             {
13                 Console.WriteLine("event in c# call by clr[device matched]");
14             }, () =>
15             {
16                 Console.WriteLine("event in c# call by clr[device removed]");
17             });
18             byte[] buffer = new byte[256];
19             int rl = hid.Read(buffer);
20             if (hid.IsConnected)
21             {
22                 Console.WriteLine("my device finded.!!!");
23                 Console.WriteLine("input report length: " + hid.InputReportLen);
24                 Console.WriteLine("output report length: " + hid.OutputReportLen);
25             }
26 
27             Console.WriteLine("press enter 退出dll的消息循環.");
28             Console.ReadLine();
29             hid.Dispose();
30 
31             Console.WriteLine("press enter to exit.");
32             Console.ReadLine();
33         }
34     }
35 }

技術分享圖片

C++/CLI混合編程<Hid示例>