1 ///////////////////////////////////////////////////////////////////////////////
2 // BOSSA
3 //
4 // Copyright (c) 2011-2018, ShumaTech
5 // All rights reserved.
6 //
7 // Redistribution and use in source and binary forms, with or without
8 // modification, are permitted provided that the following conditions are met:
9 //     * Redistributions of source code must retain the above copyright
10 //       notice, this list of conditions and the following disclaimer.
11 //     * Redistributions in binary form must reproduce the above copyright
12 //       notice, this list of conditions and the following disclaimer in the
13 //       documentation and/or other materials provided with the distribution.
14 //     * Neither the name of the <organization> nor the
15 //       names of its contributors may be used to endorse or promote products
16 //       derived from this software without specific prior written permission.
17 //
18 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
19 // ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
20 // WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
21 // DISCLAIMED. IN NO EVENT SHALL <COPYRIGHT HOLDER> BE LIABLE FOR ANY
22 // DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
23 // (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
24 // LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
25 // ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
26 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
27 // SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28 ///////////////////////////////////////////////////////////////////////////////
29 #include "WinPortFactory.h"
30 #include "WinSerialPort.h"
31 
32 #define USB_DEVICE_NAME "\\Device\\USB"
33 
WinPortFactory()34 WinPortFactory::WinPortFactory() :
35     _devInfo(INVALID_HANDLE_VALUE), _cfgMgr(NULL), _devNode(NULL), _devNum(0)
36 {
37 }
38 
~WinPortFactory()39 WinPortFactory::~WinPortFactory()
40 {
41     cleanup();
42 }
43 
44 SerialPort::Ptr
create(const std::string & name)45 WinPortFactory::create(const std::string& name)
46 {
47     bool isUsb = false;
48     char szNtDeviceName[MAX_PATH];
49 
50     if (QueryDosDevice(name.c_str(), szNtDeviceName, MAX_PATH))
51     {
52         if (strncmp(szNtDeviceName, USB_DEVICE_NAME, sizeof(USB_DEVICE_NAME) - 1) == 0)
53         {
54             isUsb = true;
55         }
56     }
57 
58     return create(name, isUsb);
59 }
60 
61 SerialPort::Ptr
create(const std::string & name,bool isUsb)62 WinPortFactory::create(const std::string& name, bool isUsb)
63 {
64     return SerialPort::Ptr(new WinSerialPort(name, isUsb));
65 }
66 
67 void
cleanup()68 WinPortFactory::cleanup()
69 {
70     _devNum = 0;
71     _devNode = NULL;
72 
73     if (_cfgMgr == NULL)
74     {
75         FreeLibrary(_cfgMgr);
76         _cfgMgr = NULL;
77     }
78 
79     if (_devInfo != INVALID_HANDLE_VALUE)
80     {
81         SetupDiDestroyDeviceInfoList(_devInfo);
82         _devInfo = INVALID_HANDLE_VALUE;
83     }
84 }
85 
86 std::string
error()87 WinPortFactory::error()
88 {
89     cleanup();
90     return end();
91 }
92 
93 std::string
begin()94 WinPortFactory::begin()
95 {
96     DWORD size = 0;
97 
98     if (_devInfo != INVALID_HANDLE_VALUE)
99         cleanup();
100 
101     SetupDiClassGuidsFromNameA("Ports", 0, 0, &size);
102     if (size < 1)
103         return error();
104 
105     GUID guids[size];
106 
107     if (!SetupDiClassGuidsFromNameA("Ports", guids, size * sizeof(GUID), &size))
108     {
109         return error();
110     }
111 
112     _devInfo = SetupDiGetClassDevs(guids, NULL, NULL, DIGCF_PRESENT);
113     if(_devInfo == INVALID_HANDLE_VALUE)
114         return error();
115 
116     _cfgMgr = LoadLibrary("cfgmgr32");
117     if (!_cfgMgr)
118         return error();
119 
120     _devNode = (CM_Open_DevNode_Key) GetProcAddress(_cfgMgr, "CM_Open_DevNode_Key");
121     if (!_devNode)
122         return error();
123 
124     return next();
125 }
126 
127 std::string
end()128 WinPortFactory::end()
129 {
130     return std::string();
131 }
132 
133 std::string
next()134 WinPortFactory::next()
135 {
136     int rc;
137     BYTE devName[16];
138     SP_DEVINFO_DATA devData;
139     HKEY devKey;
140     DWORD len;
141 
142     if (_devInfo == INVALID_HANDLE_VALUE)
143         return end();
144 
145     while (1)
146     {
147         devData.cbSize = sizeof(SP_DEVINFO_DATA);
148         if (!SetupDiEnumDeviceInfo(_devInfo, _devNum, &devData))
149             return error();
150 
151         rc = _devNode(devData.DevInst,
152                       KEY_QUERY_VALUE,
153                       0,
154                       1,
155                       &devKey,
156                       0);
157 
158         if (rc != ERROR_SUCCESS)
159             return error();
160 
161         len = sizeof(devName);
162         rc = RegQueryValueEx(devKey,
163                              "portname",
164                              NULL,
165                              NULL,
166                              devName,
167                              &len);
168 
169         RegCloseKey(devKey);
170         if (rc != ERROR_SUCCESS)
171             return error();
172 
173         _devNum++;
174 
175         if (strncmp("COM", (char*) devName, 3) == 0)
176             break;
177     }
178 
179     return std::string((char*) devName, len);
180 }
181 
182 std::string
def()183 WinPortFactory::def()
184 {
185     return begin();
186 }
187 
188