-
Notifications
You must be signed in to change notification settings - Fork 0
/
qextserialenumerator.cpp
156 lines (139 loc) · 5.05 KB
/
qextserialenumerator.cpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
/**
* @file qextserialenumerator.cpp
* @author Michał Policht
* @see QextSerialEnumerator
*/
#include "qextserialenumerator.h"
#include <objbase.h>
#include <initguid.h>
#ifdef _TTY_WIN_
//this is serial port GUID
#ifndef GUID_CLASS_COMPORT
DEFINE_GUID(GUID_CLASS_COMPORT, 0x86e0d1e0L, 0x8089, 0x11d0, 0x9c, 0xe4, 0x08, 0x00, 0x3e, 0x30, 0x1f, 0x73);
#endif
/* Gordon Schumacher's macros for TCHAR -> QString conversions and vice versa */
#ifdef UNICODE
#define QStringToTCHAR(x) (wchar_t*) x.utf16()
#define PQStringToTCHAR(x) (wchar_t*) x->utf16()
#define TCHARToQString(x) QString::fromUtf16((ushort*)(x))
#define TCHARToQStringN(x,y) QString::fromUtf16((ushort*)(x),(y))
#else
#define QStringToTCHAR(x) x.local8Bit().constData()
#define PQStringToTCHAR(x) x->local8Bit().constData()
#define TCHARToQString(x) QString::fromLocal8Bit((x))
#define TCHARToQStringN(x,y) QString::fromLocal8Bit((x),(y))
#endif /*UNICODE*/
//static
QString QextSerialEnumerator::getRegKeyValue(HKEY key, LPCTSTR property)
{
DWORD size = 0;
RegQueryValueEx(key, property, NULL, NULL, NULL, & size);
BYTE * buff = new BYTE[size];
if (RegQueryValueEx(key, property, NULL, NULL, buff, & size) == ERROR_SUCCESS) {
return TCHARToQStringN(buff, size);
delete [] buff;
} else {
qWarning("QextSerialEnumerator::getRegKeyValue: can not obtain value from registry");
delete [] buff;
return QString();
}
}
//static
QString QextSerialEnumerator::getDeviceProperty(HDEVINFO devInfo, PSP_DEVINFO_DATA devData, DWORD property)
{
DWORD buffSize = 0;
SetupDiGetDeviceRegistryProperty(devInfo, devData, property, NULL, NULL, 0, & buffSize);
BYTE * buff = new BYTE[buffSize];
if (!SetupDiGetDeviceRegistryProperty(devInfo, devData, property, NULL, buff, buffSize, NULL))
qCritical("Can not obtain property: %ld from registry", property);
QString result = TCHARToQString(buff);
delete [] buff;
return result;
}
//static
void QextSerialEnumerator::setupAPIScan(QList<QextPortInfo> & infoList)
{
HDEVINFO devInfo = INVALID_HANDLE_VALUE;
GUID * guidDev = (GUID *) & GUID_CLASS_COMPORT;
devInfo = SetupDiGetClassDevs(guidDev, NULL, NULL, DIGCF_PRESENT | DIGCF_DEVICEINTERFACE);
if(devInfo == INVALID_HANDLE_VALUE) {
qCritical("SetupDiGetClassDevs failed. Error code: %ld", GetLastError());
return;
}
//enumerate the devices
bool ok = true;
SP_DEVICE_INTERFACE_DATA ifcData;
ifcData.cbSize = sizeof(SP_DEVICE_INTERFACE_DATA);
SP_DEVICE_INTERFACE_DETAIL_DATA * detData = NULL;
DWORD detDataSize = 0;
DWORD oldDetDataSize = 0;
for (DWORD i = 0; ok; i++) {
ok = SetupDiEnumDeviceInterfaces(devInfo, NULL, guidDev, i, &ifcData);
if (ok) {
SP_DEVINFO_DATA devData = {sizeof(SP_DEVINFO_DATA)};
//check for required detData size
SetupDiGetDeviceInterfaceDetail(devInfo, & ifcData, NULL, 0, & detDataSize, & devData);
//if larger than old detData size then reallocate the buffer
if (detDataSize > oldDetDataSize) {
delete [] detData;
detData = (SP_DEVICE_INTERFACE_DETAIL_DATA *) new char[detDataSize];
detData->cbSize = sizeof(SP_DEVICE_INTERFACE_DETAIL_DATA);
oldDetDataSize = detDataSize;
}
//check the details
if (SetupDiGetDeviceInterfaceDetail(devInfo, & ifcData, detData, detDataSize,
NULL, & devData)) {
// Got a device. Get the details.
QextPortInfo info;
info.friendName = getDeviceProperty(devInfo, & devData, SPDRP_FRIENDLYNAME);
info.physName = getDeviceProperty(devInfo, & devData, SPDRP_PHYSICAL_DEVICE_OBJECT_NAME);
info.enumName = getDeviceProperty(devInfo, & devData, SPDRP_ENUMERATOR_NAME);
//anyway, to get the port name we must still open registry directly :( ???
//Eh...
HKEY devKey = SetupDiOpenDevRegKey(devInfo, & devData, DICS_FLAG_GLOBAL, 0,
DIREG_DEV, KEY_READ);
info.portName = getRegKeyValue(devKey, TEXT("PortName"));
RegCloseKey(devKey);
infoList.append(info);
} else {
qCritical("SetupDiGetDeviceInterfaceDetail failed. Error code: %ld", GetLastError());
delete [] detData;
return;
}
} else {
if (GetLastError() != ERROR_NO_MORE_ITEMS) {
delete [] detData;
qCritical("SetupDiEnumDeviceInterfaces failed. Error code: %ld", GetLastError());
return;
}
}
}
delete [] detData;
}
#endif /*_TTY_WIN_*/
//static
QList<QextPortInfo> QextSerialEnumerator::getPorts()
{
QList<QextPortInfo> ports;
#ifdef _TTY_WIN_
OSVERSIONINFO vi;
vi.dwOSVersionInfoSize = sizeof(vi);
if (!::GetVersionEx(&vi)) {
qCritical("Could not get OS version.");
return ports;
}
// Handle windows 9x and NT4 specially
if (vi.dwMajorVersion < 5) {
qCritical("Enumeration for this version of Windows is not implemented yet");
/* if (vi.dwPlatformId == VER_PLATFORM_WIN32_NT)
EnumPortsWNt4(ports);
else
EnumPortsW9x(ports);*/
} else //w2k or later
setupAPIScan(ports);
#endif /*_TTY_WIN_*/
#ifdef _TTY_POSIX_
qCritical("Enumeration for POSIX systems is not implemented yet.");
#endif /*_TTY_POSIX_*/
return ports;
}