1 /* 2 Actiona 3 Copyright (C) 2005 Jonathan Mercier-Ganady 4 5 Actiona is free software: you can redistribute it and/or modify 6 it under the terms of the GNU General Public License as published by 7 the Free Software Foundation, either version 3 of the License, or 8 (at your option) any later version. 9 10 Actiona is distributed in the hope that it will be useful, 11 but WITHOUT ANY WARRANTY; without even the implied warranty of 12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 GNU General Public License for more details. 14 15 You should have received a copy of the GNU General Public License 16 along with this program. If not, see <http://www.gnu.org/licenses/>. 17 18 Contact : jmgr@jmgr.info 19 */ 20 21 #include "registry.h" 22 23 #include <QtEndian> 24 #include <QDebug> 25 26 #ifdef Q_OS_WIN 27 #include <strsafe.h> 28 #endif 29 30 namespace Code 31 { constructor(QScriptContext * context,QScriptEngine * engine)32 QScriptValue Registry::constructor(QScriptContext *context, QScriptEngine *engine) 33 { 34 return CodeClass::constructor(new Registry, context, engine); 35 } 36 Registry()37 Registry::Registry() 38 : CodeClass() 39 #ifdef Q_OS_WIN 40 , mHKey(0) 41 , mRootKey(ClassesRoot) 42 #endif 43 { 44 } 45 ~Registry()46 Registry::~Registry() 47 { 48 #ifdef Q_OS_WIN 49 RegCloseKey(mHKey); 50 #endif 51 } 52 openKey(Key key,const QString & subKey)53 QScriptValue Registry::openKey(Key key, const QString &subKey) 54 { 55 #ifdef Q_OS_WIN 56 HKEY hKey = enumToKey(key); 57 58 if(RegOpenKeyEx(hKey, subKey.toStdWString().c_str(), 0, KEY_ALL_ACCESS, &mHKey) != ERROR_SUCCESS) 59 throwError(QStringLiteral("OpenKeyError"), tr("Unable to open the key")); 60 else 61 { 62 mRootKey = key; 63 mSubKey = subKey; 64 } 65 #else 66 Q_UNUSED(key) 67 Q_UNUSED(subKey) 68 #endif 69 return thisObject(); 70 } 71 createKey(Key key,const QString & subKey)72 QScriptValue Registry::createKey(Key key, const QString &subKey) 73 { 74 #ifdef Q_OS_WIN 75 HKEY hKey = enumToKey(key); 76 77 if(RegCreateKeyEx(hKey, subKey.toStdWString().c_str(), 0, 0, 0, KEY_ALL_ACCESS, 0, &mHKey, 0) != ERROR_SUCCESS) 78 throwError(QStringLiteral("CreateKeyError"), tr("Unable to create the key")); 79 else 80 { 81 mRootKey = key; 82 mSubKey = subKey; 83 } 84 #else 85 Q_UNUSED(key) 86 Q_UNUSED(subKey) 87 #endif 88 return thisObject(); 89 } 90 setValue(const QString & value,const QVariant & data) const91 QScriptValue Registry::setValue(const QString &value, const QVariant &data) const 92 { 93 #ifdef Q_OS_WIN 94 std::wstring wideValue = value.toStdWString(); 95 96 switch(data.type()) 97 { 98 case QVariant::Int: 99 case QVariant::UInt: 100 { 101 int intData = data.toInt(); 102 if(RegSetValueEx(mHKey, wideValue.c_str(), 0, REG_DWORD, reinterpret_cast<LPBYTE>(&intData), sizeof(int)) != ERROR_SUCCESS) 103 throwError(QStringLiteral("SetValueError"), tr("Cannot set the value data")); 104 } 105 break; 106 case QVariant::LongLong: 107 case QVariant::ULongLong: 108 { 109 long long intData = data.toLongLong(); 110 if(RegSetValueEx(mHKey, wideValue.c_str(), 0, REG_QWORD, reinterpret_cast<LPBYTE>(&intData), sizeof(long long)) != ERROR_SUCCESS) 111 throwError(QStringLiteral("SetValueError"), tr("Cannot set the value data")); 112 } 113 break; 114 case QVariant::StringList: 115 { 116 const QStringList &stringList = data.toStringList(); 117 std::wstring wideData; 118 119 for(const QString &string: stringList) 120 { 121 wideData += string.toStdWString(); 122 wideData += L'\0'; 123 } 124 125 if(RegSetValueEx(mHKey, wideValue.c_str(), 0, REG_MULTI_SZ, reinterpret_cast<LPBYTE>(const_cast<wchar_t*>(wideData.c_str())), static_cast<DWORD>(wideData.size() * sizeof(wchar_t))) != ERROR_SUCCESS) 126 throwError(QStringLiteral("SetValueError"), tr("Cannot set the value data")); 127 } 128 break; 129 case QVariant::ByteArray: 130 { 131 QByteArray byteArray = data.toByteArray(); 132 if(RegSetValueEx(mHKey, wideValue.c_str(), 0, REG_BINARY, reinterpret_cast<LPBYTE>(byteArray.data()), static_cast<DWORD>(byteArray.size())) != ERROR_SUCCESS) 133 throwError(QStringLiteral("SetValueError"), tr("Cannot set the value data")); 134 } 135 break; 136 default: 137 { 138 if(data.type() == QVariant::String || data.canConvert(QVariant::String)) 139 { 140 std::wstring wideData = data.toString().toStdWString(); 141 if(RegSetValueEx(mHKey, wideValue.c_str(), 0, REG_SZ, reinterpret_cast<LPBYTE>(const_cast<wchar_t*>(wideData.c_str())), static_cast<DWORD>(wideData.size() * sizeof(wchar_t))) != ERROR_SUCCESS) 142 throwError(QStringLiteral("SetValueError"), tr("Cannot set the value data")); 143 } 144 else 145 throwError(QStringLiteral("SetValueError"), tr("Cannot set the value data")); 146 } 147 break; 148 } 149 #else 150 Q_UNUSED(value) 151 Q_UNUSED(data) 152 #endif 153 return thisObject(); 154 } 155 value(const QString & value) const156 QVariant Registry::value(const QString &value) const 157 { 158 #ifdef Q_OS_WIN 159 DWORD size; 160 DWORD type; 161 std::wstring wideValue = value.toStdWString(); 162 if(RegQueryValueEx(mHKey, wideValue.c_str(), 0, &type, 0, &size) != ERROR_SUCCESS) 163 { 164 throwError(QStringLiteral("FindValueError"), tr("Cannot find the value to read")); 165 return {}; 166 } 167 168 switch(type) 169 { 170 case REG_DWORD: 171 case REG_DWORD_BIG_ENDIAN: 172 { 173 qint32 value; 174 if(RegQueryValueEx(mHKey, wideValue.c_str(), 0, 0, reinterpret_cast<LPBYTE>(&value), &size) != ERROR_SUCCESS) 175 { 176 throwError(QStringLiteral("FindValueError"), tr("Cannot find the value to read")); 177 return {}; 178 } 179 180 if(type == REG_DWORD_BIG_ENDIAN) 181 value = qFromBigEndian(value); 182 183 return value; 184 } 185 break; 186 case REG_SZ: 187 case REG_EXPAND_SZ: 188 case REG_LINK: 189 case REG_MULTI_SZ: 190 { 191 std::vector<wchar_t> buffer(size); 192 if(RegQueryValueEx(mHKey, wideValue.c_str(), 0, 0, reinterpret_cast<LPBYTE>(buffer.data()), &size) != ERROR_SUCCESS) 193 { 194 throwError(QStringLiteral("FindValueError"), tr("Cannot find the value to read")); 195 return {}; 196 } 197 198 if(type == REG_MULTI_SZ) 199 { 200 QStringList stringList = QString::fromWCharArray(buffer.data(), size / 2).split(QChar(L'\0'), QString::SkipEmptyParts); 201 202 if(stringList.last().isEmpty()) 203 stringList.removeLast(); 204 205 return stringList; 206 } 207 else 208 return QString::fromWCharArray(buffer.data(), size / 2); 209 } 210 break; 211 case REG_BINARY: 212 { 213 std::vector<char> buffer(size); 214 if(RegQueryValueEx(mHKey, wideValue.c_str(), 0, 0, reinterpret_cast<LPBYTE>(buffer.data()), &size) != ERROR_SUCCESS) 215 { 216 throwError(QStringLiteral("FindValueError"), tr("Cannot find the value to read")); 217 return {}; 218 } 219 220 QByteArray back = QByteArray::fromRawData(buffer.data(), size); 221 222 return back; 223 } 224 break; 225 case REG_QWORD: 226 { 227 qint64 value; 228 if(RegQueryValueEx(mHKey, wideValue.c_str(), 0, 0, reinterpret_cast<LPBYTE>(&value), &size) != ERROR_SUCCESS) 229 { 230 throwError(QStringLiteral("FindValueError"), tr("Cannot find the value to read")); 231 return {}; 232 } 233 234 return value; 235 } 236 break; 237 case REG_NONE: 238 default: 239 throwError(QStringLiteral("InvalidValueError"), tr("Invalid value type")); 240 return {}; 241 break; 242 } 243 #else 244 Q_UNUSED(value) 245 246 return QVariant(); 247 #endif 248 } 249 valueNames() const250 QStringList Registry::valueNames() const 251 { 252 #ifdef Q_OS_WIN 253 int index = 0; 254 DWORD valueCount; 255 DWORD maxValueNameLength; 256 257 if(RegQueryInfoKey(mHKey, 0, 0, 0, 0, 0, 0, &valueCount, &maxValueNameLength, 0, 0, 0) != ERROR_SUCCESS) 258 { 259 throwError(QStringLiteral("InvalidKeyError"), tr("Unable to query informations about this key")); 260 return {}; 261 } 262 263 if(valueCount == 0 || maxValueNameLength == 0) 264 return {}; 265 266 std::vector<wchar_t> valueName(maxValueNameLength + 1); 267 int result; 268 QStringList back; 269 270 for(;;++index) 271 { 272 DWORD valueNameSize = maxValueNameLength + 1; 273 274 result = RegEnumValue(mHKey, index, valueName.data(), &valueNameSize, 0, 0, 0, 0); 275 if(result == ERROR_NO_MORE_ITEMS) 276 break; 277 278 if(valueNameSize == 0) 279 continue;//Skip the default value 280 281 back.append(QString::fromWCharArray(valueName.data(), valueNameSize)); 282 } 283 284 return back; 285 #else 286 return {}; 287 #endif 288 } 289 keys() const290 QStringList Registry::keys() const 291 { 292 #ifdef Q_OS_WIN 293 int index = 0; 294 DWORD subKeyCount; 295 DWORD maxSubKeyNameLength; 296 297 if(RegQueryInfoKey(mHKey, 0, 0, 0, &subKeyCount, &maxSubKeyNameLength, 0, 0, 0, 0, 0, 0) != ERROR_SUCCESS) 298 { 299 throwError(QStringLiteral("InvalidKeyError"), tr("Unable to query informations about this key")); 300 return {}; 301 } 302 303 if(subKeyCount == 0 || maxSubKeyNameLength == 0) 304 return {}; 305 306 std::vector<wchar_t> subKeyName(maxSubKeyNameLength + 1); 307 int result; 308 QStringList back; 309 310 for(;;++index) 311 { 312 DWORD subKeyNameSize = maxSubKeyNameLength + 1; 313 314 result = RegEnumKeyEx(mHKey, index, subKeyName.data(), &subKeyNameSize, 0, 0, 0, 0); 315 if(result == ERROR_NO_MORE_ITEMS) 316 break; 317 318 back.append(QString::fromWCharArray(subKeyName.data(), subKeyNameSize)); 319 } 320 321 return back; 322 #else 323 return {}; 324 #endif 325 } 326 deleteValue(const QString & value) const327 QScriptValue Registry::deleteValue(const QString &value) const 328 { 329 #ifdef Q_OS_WIN 330 if(RegDeleteValue(mHKey, value.toStdWString().c_str()) != ERROR_SUCCESS) 331 throwError(QStringLiteral("InvalidKeyError"), tr("Unable to delete the key")); 332 #else 333 Q_UNUSED(value) 334 #endif 335 return thisObject(); 336 } 337 338 #ifdef Q_OS_WIN RegDelnodeRecurse(HKEY hKeyRoot,LPTSTR lpSubKey)339 BOOL RegDelnodeRecurse (HKEY hKeyRoot, LPTSTR lpSubKey) 340 { 341 LPTSTR lpEnd; 342 LONG lResult; 343 DWORD dwSize; 344 WCHAR szName[MAX_PATH]; 345 HKEY hKey; 346 FILETIME ftWrite; 347 348 // First, see if we can delete the key without having 349 // to recurse. 350 351 lResult = RegDeleteKey(hKeyRoot, lpSubKey); 352 353 if (lResult == ERROR_SUCCESS) 354 return TRUE; 355 356 lResult = RegOpenKeyEx (hKeyRoot, lpSubKey, 0, KEY_READ, &hKey); 357 358 if (lResult != ERROR_SUCCESS) 359 { 360 if (lResult == ERROR_FILE_NOT_FOUND) { 361 printf("Key not found.\n"); 362 return TRUE; 363 } 364 else { 365 printf("Error opening key.\n"); 366 return FALSE; 367 } 368 } 369 370 // Check for an ending slash and add one if it is missing. 371 372 lpEnd = lpSubKey + lstrlen(lpSubKey); 373 374 if (*(lpEnd - 1) != TEXT('\\')) 375 { 376 *lpEnd = TEXT('\\'); 377 lpEnd++; 378 *lpEnd = TEXT('\0'); 379 } 380 381 // Enumerate the keys 382 383 dwSize = MAX_PATH; 384 lResult = RegEnumKeyEx(hKey, 0, szName, &dwSize, NULL, 385 NULL, NULL, &ftWrite); 386 387 if (lResult == ERROR_SUCCESS) 388 { 389 do { 390 391 StringCchCopy (lpEnd, MAX_PATH*2, szName); 392 393 if (!RegDelnodeRecurse(hKeyRoot, lpSubKey)) { 394 break; 395 } 396 397 dwSize = MAX_PATH; 398 399 lResult = RegEnumKeyEx(hKey, 0, szName, &dwSize, NULL, 400 NULL, NULL, &ftWrite); 401 402 } while (lResult == ERROR_SUCCESS); 403 } 404 405 lpEnd--; 406 *lpEnd = TEXT('\0'); 407 408 RegCloseKey (hKey); 409 410 // Try again to delete the key. 411 412 lResult = RegDeleteKey(hKeyRoot, lpSubKey); 413 414 if (lResult == ERROR_SUCCESS) 415 return TRUE; 416 417 return FALSE; 418 } 419 RegDelnode(HKEY hKeyRoot,LPCTSTR lpSubKey)420 BOOL RegDelnode (HKEY hKeyRoot, LPCTSTR lpSubKey) 421 { 422 WCHAR szDelKey[MAX_PATH*2]; 423 424 StringCchCopy (szDelKey, MAX_PATH*2, lpSubKey); 425 return RegDelnodeRecurse(hKeyRoot, szDelKey); 426 427 } 428 #endif 429 deleteKey(Key key,const QString & subKey) const430 QScriptValue Registry::deleteKey(Key key, const QString &subKey) const 431 { 432 #ifdef Q_OS_WIN 433 HKEY hKey = enumToKey(key); 434 435 if(!RegDelnode(hKey, subKey.toStdWString().c_str())) 436 throwError(QStringLiteral("InvalidKeyError"), tr("Unable to delete the key")); 437 #else 438 Q_UNUSED(key) 439 Q_UNUSED(subKey) 440 #endif 441 return thisObject(); 442 } 443 deleteKey() const444 QScriptValue Registry::deleteKey() const 445 { 446 #ifdef Q_OS_WIN 447 RegCloseKey(mHKey); 448 449 deleteKey(mRootKey, mSubKey); 450 #endif 451 return thisObject(); 452 } 453 closeKey() const454 QScriptValue Registry::closeKey() const 455 { 456 #ifdef Q_OS_WIN 457 RegCloseKey(mHKey); 458 #endif 459 return thisObject(); 460 } 461 462 #ifdef Q_OS_WIN enumToKey(Key key) const463 HKEY Registry::enumToKey(Key key) const 464 { 465 switch(key) 466 { 467 case ClassesRoot: 468 return HKEY_CLASSES_ROOT; 469 case CurrentConfig: 470 return HKEY_CURRENT_CONFIG; 471 case CurrentUser: 472 return HKEY_CURRENT_USER; 473 case Users: 474 return HKEY_USERS; 475 case LocalMachine: 476 return HKEY_LOCAL_MACHINE; 477 default: 478 return HKEY_CURRENT_USER; 479 } 480 } 481 #endif 482 } 483