File indexing completed on 2024-05-12 04:01:49
0001 /* 0002 SPDX-FileCopyrightText: 2013 Patrick von Reth <vonreth@kde.org> 0003 0004 SPDX-License-Identifier: LGPL-2.1-only OR LGPL-3.0-only OR LicenseRef-KDE-Accepted-LGPL 0005 */ 0006 0007 #ifndef WINDEVICEMANAGER_H 0008 #define WINDEVICEMANAGER_H 0009 0010 #include <solid/devices/ifaces/devicemanager.h> 0011 0012 #include <QDebug> 0013 #include <QSet> 0014 0015 #include <qt_windows.h> 0016 #include <winioctl.h> 0017 0018 inline QString qGetLastError(ulong errorNummber = GetLastError()) 0019 { 0020 LPVOID error = NULL; 0021 size_t len = FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, 0022 NULL, 0023 errorNummber, 0024 MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), 0025 (LPWSTR)&error, 0026 0, 0027 NULL); 0028 QString out = QString::fromWCharArray((wchar_t *)error, (int)len).trimmed().append(" %1").arg(errorNummber); 0029 LocalFree(error); 0030 return out; 0031 } 0032 0033 namespace Solid 0034 { 0035 namespace Backends 0036 { 0037 namespace Win 0038 { 0039 class WinDeviceManager : public Solid::Ifaces::DeviceManager 0040 { 0041 Q_OBJECT 0042 public: 0043 WinDeviceManager(QObject *parent = 0); 0044 ~WinDeviceManager(); 0045 0046 virtual QString udiPrefix() const; 0047 0048 virtual QSet<Solid::DeviceInterface::Type> supportedInterfaces() const; 0049 0050 virtual QStringList allDevices(); 0051 0052 virtual QStringList devicesFromQuery(const QString &parentUdi, Solid::DeviceInterface::Type type = Solid::DeviceInterface::Unknown); 0053 0054 virtual QObject *createDevice(const QString &udi); 0055 0056 static const WinDeviceManager *instance(); 0057 0058 template<class INFO> 0059 static INFO getDeviceInfo(const QString &devName, int code) 0060 { 0061 return getDeviceInfo<INFO, void *>(devName, code); 0062 } 0063 0064 template<class INFO, class QUERY> 0065 static INFO getDeviceInfo(const QString &devName, int code, QUERY *query = NULL) 0066 { 0067 INFO info; 0068 ZeroMemory(&info, sizeof(INFO)); 0069 getDeviceInfoPrivate(devName, code, &info, sizeof(INFO), query); 0070 return info; 0071 } 0072 0073 template<class BUFFER_TYPE, class QUERY> 0074 static void getDeviceInfo(const QString &devName, int code, BUFFER_TYPE *out, DWORD outSize, QUERY *query = NULL) 0075 { 0076 ZeroMemory(out, sizeof(BUFFER_TYPE) * outSize); 0077 getDeviceInfoPrivate(devName, code, out, outSize, query); 0078 } 0079 0080 static void deviceAction(const QString &devName, int code) 0081 { 0082 getDeviceInfoPrivate<void, void *>(devName, code, NULL, 0, NULL); 0083 } 0084 0085 Q_SIGNALS: 0086 void powerChanged(); 0087 0088 private Q_SLOTS: 0089 void updateDeviceList(); 0090 void slotDeviceAdded(const QSet<QString> &udi); 0091 void slotDeviceRemoved(const QSet<QString> &udi); 0092 0093 private: 0094 friend class SolidWinEventFilter; 0095 0096 QSet<QString> m_devices; 0097 QStringList m_devicesList; 0098 QSet<Solid::DeviceInterface::Type> m_supportedInterfaces; 0099 0100 template<class INFO, class QUERY> 0101 static void getDeviceInfoPrivate(const QString &devName, int code, INFO *info, DWORD size, QUERY *query = NULL) 0102 { 0103 Q_ASSERT(!devName.isNull()); 0104 wchar_t deviceNameBuffer[MAX_PATH]; 0105 QString dev = devName; 0106 if (!dev.startsWith("\\")) { 0107 dev = QLatin1String("\\\\?\\") + dev; 0108 } 0109 deviceNameBuffer[dev.toWCharArray(deviceNameBuffer)] = 0; 0110 DWORD bytesReturned = 0; 0111 0112 ulong err = NO_ERROR; 0113 HANDLE handle = ::CreateFileW(deviceNameBuffer, GENERIC_READ, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, 0, NULL); 0114 if (handle == INVALID_HANDLE_VALUE) { 0115 err = GetLastError(); 0116 if (err == ERROR_ACCESS_DENIED) { 0117 // we would need admin rights for GENERIC_READ on systenm drives and volumes 0118 handle = ::CreateFileW(deviceNameBuffer, 0, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, 0, NULL); 0119 err = GetLastError(); 0120 } 0121 if (handle == INVALID_HANDLE_VALUE) { 0122 qWarning() << "Invalid Handle" << dev << "reason:" << qGetLastError(err) << "this should not happen."; 0123 return; 0124 } 0125 } 0126 if (::DeviceIoControl(handle, code, query, sizeof(QUERY), info, size, &bytesReturned, NULL)) { 0127 ::CloseHandle(handle); 0128 return; 0129 } 0130 0131 if (handle == INVALID_HANDLE_VALUE) { 0132 qWarning() << "Invalid Handle" << devName << "reason:" << qGetLastError() << "is probaply a subst path or more seriously there is bug!"; 0133 return; 0134 } 0135 0136 err = GetLastError(); 0137 switch (err) { 0138 case ERROR_NOT_READY: 0139 // the drive is a cd drive with no disk 0140 break; 0141 case ERROR_INVALID_FUNCTION: 0142 // in most cases this means that the device doesn't support this method, like temperature for some batteries 0143 break; 0144 default: 0145 qWarning() << "Failed to query" << dev << "reason:" << qGetLastError(err); 0146 // DebugBreak(); 0147 } 0148 ::CloseHandle(handle); 0149 } 0150 }; 0151 0152 } 0153 } 0154 } 0155 #endif // WINDEVICEMANAGER_H