使用Windows消息队列处理线程之间通信
这个程序前阵子帮一个朋友实现的,之前从未用消息队列做过类似的事情,做完后感觉其在线程同步,通信发面很好用,难怪COM也用这套机制。
程序稍微修改便能用作一般性的处理,目前实现的功能类似于监控Windows USB设备的插拔操作。
可以直接注释掉CString的使用后使用 cl /EHsc /W4 /Zi 编译,或粘贴到任意的VS中做编译。
1 #include <Windows.h> 2 #include <tchar.h> 3 #include <Dbt.h> 4 #include <setupapi.h> 5 #include <iostream> 6 #include <atlstr.h> // CString 7 using namespace std; 8 9 #pragma comment (lib, "Kernel32.lib") 10 #pragma comment (lib, "User32.lib") 11 12 #define THRD_MESSAGE_EXIT WM_USER + 1 13 const _TCHAR CLASS_NAME[] = _T("Sample Window Class"); 14 15 HWND hWnd; 16 17 static const GUID GUID_DEVINTERFACE_LIST[] = 18 { 19 // GUID_DEVINTERFACE_USB_DEVICE 20 { 0xA5DCBF10, 0x6530, 0x11D2, { 0x90, 0x1F, 0x00, 0xC0, 0x4F, 0xB9, 0x51, 0xED } }, 21 // GUID_DEVINTERFACE_DISK 22 { 0x53f56307, 0xb6bf, 0x11d0, { 0x94, 0xf2, 0x00, 0xa0, 0xc9, 0x1e, 0xfb, 0x8b } }, 23 // GUID_DEVINTERFACE_HID, 24 { 0x4D1E55B2, 0xF16F, 0x11CF, { 0x88, 0xCB, 0x00, 0x11, 0x11, 0x00, 0x00, 0x30 } }, 25 // GUID_NDIS_LAN_CLASS 26 { 0xad498944, 0x762f, 0x11d0, { 0x8d, 0xcb, 0x00, 0xc0, 0x4f, 0xc3, 0x35, 0x8c } } 27 //// GUID_DEVINTERFACE_COMPORT 28 //{ 0x86e0d1e0, 0x8089, 0x11d0, { 0x9c, 0xe4, 0x08, 0x00, 0x3e, 0x30, 0x1f, 0x73 } }, 29 //// GUID_DEVINTERFACE_SERENUM_BUS_ENUMERATOR 30 //{ 0x4D36E978, 0xE325, 0x11CE, { 0xBF, 0xC1, 0x08, 0x00, 0x2B, 0xE1, 0x03, 0x18 } }, 31 //// GUID_DEVINTERFACE_PARALLEL 32 //{ 0x97F76EF0, 0xF883, 0x11D0, { 0xAF, 0x1F, 0x00, 0x00, 0xF8, 0x00, 0x84, 0x5C } }, 33 //// GUID_DEVINTERFACE_PARCLASS 34 //{ 0x811FC6A5, 0xF728, 0x11D0, { 0xA5, 0x37, 0x00, 0x00, 0xF8, 0x75, 0x3E, 0xD1 } } 35 }; 36 37 void UpdateDevice(PDEV_BROADCAST_DEVICEINTERFACE pDevInf, WPARAM wParam) 38 { 39 CString szDevId = pDevInf->dbcc_name + 4; 40 int idx = szDevId.ReverseFind(_T('#')); 41 szDevId.Truncate(idx); 42 szDevId.Replace(_T('#'), _T('\\')); 43 szDevId.MakeUpper(); 44 45 CString szClass; 46 idx = szDevId.Find(_T('\\')); 47 szClass = szDevId.Left(idx); 48 49 CString szTmp; 50 if ( DBT_DEVICEARRIVAL == wParam ) \ 51 szTmp.Format(_T("Adding %s\r\n"), szDevId.GetBuffer()); 52 else 53 szTmp.Format(_T("Removing %s\r\n"), szDevId.GetBuffer()); 54 55 _tprintf(szTmp); 56 } 57 58 LRESULT DeviceChange(UINT message, WPARAM wParam, LPARAM lParam) 59 { 60 if ( DBT_DEVICEARRIVAL == wParam || DBT_DEVICEREMOVECOMPLETE == wParam ) 61 { 62 PDEV_BROADCAST_HDR pHdr = (PDEV_BROADCAST_HDR)lParam; 63 PDEV_BROADCAST_DEVICEINTERFACE pDevInf; 64 PDEV_BROADCAST_HANDLE pDevHnd; 65 PDEV_BROADCAST_OEM pDevOem; 66 PDEV_BROADCAST_PORT pDevPort; 67 PDEV_BROADCAST_VOLUME pDevVolume; 68 switch( pHdr->dbch_devicetype ) 69 { 70 case DBT_DEVTYP_DEVICEINTERFACE: 71 pDevInf = (PDEV_BROADCAST_DEVICEINTERFACE)pHdr; 72 UpdateDevice(pDevInf, wParam); 73 break; 74 75 case DBT_DEVTYP_HANDLE: 76 pDevHnd = (PDEV_BROADCAST_HANDLE)pHdr; 77 break; 78 79 case DBT_DEVTYP_OEM: 80 pDevOem = (PDEV_BROADCAST_OEM)pHdr; 81 break; 82 83 case DBT_DEVTYP_PORT: 84 pDevPort = (PDEV_BROADCAST_PORT)pHdr; 85 break; 86 87 case DBT_DEVTYP_VOLUME: 88 pDevVolume = (PDEV_BROADCAST_VOLUME)pHdr; 89 break; 90 } 91 } 92 return 0; 93 } 94 95 LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) 96 { 97 switch(message) 98 { 99 case WM_PAINT: 100 break; 101 case WM_SIZE: 102 break; 103 case WM_DEVICECHANGE: 104 return DeviceChange(message, wParam, lParam); 105 } 106 107 return DefWindowProc(hWnd, message, wParam, lParam); 108 } 109 110 ATOM MyRegisterClass() 111 { 112 WNDCLASS wc = {0}; 113 wc.lpfnWndProc = WndProc; 114 wc.hInstance = GetModuleHandle(NULL); 115 wc.lpszClassName = CLASS_NAME; 116 return RegisterClass(&wc); 117 } 118 119 bool CreateMessageOnlyWindow() 120 { 121 hWnd = CreateWindowEx(0, CLASS_NAME, _T(""), WS_OVERLAPPEDWINDOW, 122 CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, 123 NULL, // Parent window 124 NULL, // Menu 125 GetModuleHandle(NULL), // Instance handle 126 NULL // Additional application data 127 ); 128 129 return hWnd != NULL; 130 } 131 132 void RegisterDeviceNotify() 133 { 134 HDEVNOTIFY hDevNotify; 135 for (int i = 0; i < sizeof(GUID_DEVINTERFACE_LIST) / sizeof(GUID); i++) 136 { 137 DEV_BROADCAST_DEVICEINTERFACE NotificationFilter; 138 ZeroMemory( &NotificationFilter, sizeof(NotificationFilter) ); 139 NotificationFilter.dbcc_size = sizeof(DEV_BROADCAST_DEVICEINTERFACE); 140 NotificationFilter.dbcc_devicetype = DBT_DEVTYP_DEVICEINTERFACE; 141 NotificationFilter.dbcc_classguid = GUID_DEVINTERFACE_LIST[i]; 142 hDevNotify = RegisterDeviceNotification(hWnd, &NotificationFilter, DEVICE_NOTIFY_WINDOW_HANDLE); 143 } 144 } 145 146 DWORD WINAPI ThrdFunc( LPVOID lpParam ) 147 { 148 if (0 == MyRegisterClass()) 149 return -1; 150 151 if (!CreateMessageOnlyWindow()) 152 return -1; 153 154 RegisterDeviceNotify(); 155 156 MSG msg; 157 while (GetMessage(&msg, NULL, 0, 0)) 158 { 159 if (msg.message == THRD_MESSAGE_EXIT) 160 { 161 cout << "worker receive the exiting Message..." << endl; 162 return 0; 163 } 164 165 TranslateMessage(&msg); 166 DispatchMessage(&msg); 167 } 168 169 return 0; 170 } 171 172 int main(int argc, char** argv) 173 { 174 DWORD iThread; 175 HANDLE hThread = CreateThread( NULL, 0, ThrdFunc, NULL, 0, &iThread); 176 if (hThread == NULL) { 177 cout << "error" << endl; 178 return -1; 179 } 180 181 char chQtNum; 182 do 183 { 184 cout << "enter Q/q for quit: " << endl; 185 cin >> chQtNum; 186 187 } while (chQtNum != 'Q' && chQtNum != 'q'); 188 189 PostThreadMessage(iThread, THRD_MESSAGE_EXIT, 0, 0); 190 WaitForSingleObject(hThread, INFINITE); 191 CloseHandle(hThread); 192 return 0; 193 }
:-)