src/publishsubscribe/registrylayer_win.cpp
changeset 0 876b1a06bc25
equal deleted inserted replaced
-1:000000000000 0:876b1a06bc25
       
     1 /****************************************************************************
       
     2 **
       
     3 ** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
       
     4 ** All rights reserved.
       
     5 ** Contact: Nokia Corporation (qt-info@nokia.com)
       
     6 **
       
     7 ** This file is part of the Qt Mobility Components.
       
     8 **
       
     9 ** $QT_BEGIN_LICENSE:LGPL$
       
    10 ** No Commercial Usage
       
    11 ** This file contains pre-release code and may not be distributed.
       
    12 ** You may use this file in accordance with the terms and conditions
       
    13 ** contained in the Technology Preview License Agreement accompanying
       
    14 ** this package.
       
    15 **
       
    16 ** GNU Lesser General Public License Usage
       
    17 ** Alternatively, this file may be used under the terms of the GNU Lesser
       
    18 ** General Public License version 2.1 as published by the Free Software
       
    19 ** Foundation and appearing in the file LICENSE.LGPL included in the
       
    20 ** packaging of this file.  Please review the following information to
       
    21 ** ensure the GNU Lesser General Public License version 2.1 requirements
       
    22 ** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
       
    23 **
       
    24 ** In addition, as a special exception, Nokia gives you certain additional
       
    25 ** rights.  These rights are described in the Nokia Qt LGPL Exception
       
    26 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
       
    27 **
       
    28 ** If you have questions regarding the use of this file, please contact
       
    29 ** Nokia at qt-info@nokia.com.
       
    30 **
       
    31 **
       
    32 **
       
    33 **
       
    34 **
       
    35 **
       
    36 **
       
    37 **
       
    38 ** $QT_END_LICENSE$
       
    39 **
       
    40 ****************************************************************************/
       
    41 
       
    42 #include "qvaluespace_p.h"
       
    43 #include "qvaluespacepublisher.h"
       
    44 
       
    45 #include <QSet>
       
    46 #include <QStringList>
       
    47 #include <QEventLoop>
       
    48 #include <QTimer>
       
    49 #include <QVariant>
       
    50 #include <QMutex>
       
    51 
       
    52 #ifdef Q_OS_WINCE
       
    53 #include <QThread>
       
    54 #endif
       
    55 
       
    56 #include <QDebug>
       
    57 
       
    58 // Define win32 version to pull in RegisterWaitForSingleObject and UnregisterWait.
       
    59 #define _WIN32_WINNT 0x0500
       
    60 #include <windows.h>
       
    61 
       
    62 #ifdef Q_OS_WINCE
       
    63 #include <regext.h>
       
    64 #define RegistryCallback REGISTRYNOTIFYCALLBACK
       
    65 #else
       
    66 #define RegistryCallback WAITORTIMERCALLBACK
       
    67 #endif
       
    68 
       
    69 QTM_BEGIN_NAMESPACE
       
    70 
       
    71 #ifdef Q_OS_WINCE
       
    72 class QWindowsCENotify : public QThread
       
    73 {
       
    74     Q_OBJECT
       
    75 
       
    76 public:
       
    77     QWindowsCENotify(QObject *parent = 0);
       
    78     ~QWindowsCENotify();
       
    79 
       
    80     void addHandle(HANDLE handle);
       
    81     void removeHandle(HANDLE handle);
       
    82 
       
    83 protected:
       
    84     void run();
       
    85 
       
    86 signals:
       
    87     void eventSignaled(void *handle);
       
    88 
       
    89 private:
       
    90     HANDLE wakeUp;
       
    91     QSet<HANDLE> handles;
       
    92 };
       
    93 
       
    94 QWindowsCENotify::QWindowsCENotify(QObject *parent)
       
    95 :   QThread(parent)
       
    96 {
       
    97     wakeUp = CreateEvent(0, false, false, 0);
       
    98 }
       
    99 
       
   100 QWindowsCENotify::~QWindowsCENotify()
       
   101 {
       
   102     CloseHandle(wakeUp);
       
   103     wakeUp = INVALID_HANDLE_VALUE;
       
   104     wait();
       
   105 }
       
   106 
       
   107 void QWindowsCENotify::addHandle(HANDLE handle)
       
   108 {
       
   109     handles.insert(handle);
       
   110 
       
   111     SetEvent(wakeUp);
       
   112 }
       
   113 
       
   114 void QWindowsCENotify::removeHandle(HANDLE handle)
       
   115 {
       
   116     handles.remove(handle);
       
   117 
       
   118     SetEvent(wakeUp);
       
   119 }
       
   120 
       
   121 void QWindowsCENotify::run()
       
   122 {
       
   123     while (wakeUp != INVALID_HANDLE_VALUE) {
       
   124         ResetEvent(wakeUp);
       
   125 
       
   126         QVector<HANDLE> waitHandles = handles.toList().toVector();
       
   127         waitHandles.append(wakeUp);
       
   128         DWORD index = WaitForMultipleObjects(waitHandles.count(), waitHandles.data(),
       
   129                                              false, INFINITE);
       
   130 
       
   131         if (index >= WAIT_OBJECT_0 && index < WAIT_OBJECT_0 + waitHandles.count()) {
       
   132             if (index - WAIT_OBJECT_0 != waitHandles.count() - 1) {
       
   133                 handles.remove(waitHandles.at(index - WAIT_OBJECT_0));
       
   134                 emit eventSignaled(waitHandles.at(index - WAIT_OBJECT_0));
       
   135             }
       
   136         } else if (index >= WAIT_ABANDONED_0 && index < WAIT_ABANDONED_0 + waitHandles.count()) {
       
   137             //qDebug() << "woke up because of abandoned index" << index - WAIT_ABANDONED_0;
       
   138         } else {
       
   139             qDebug() << "WaitForMultipleObjects failed with error" << GetLastError();
       
   140         }
       
   141     }
       
   142 }
       
   143 #endif
       
   144 
       
   145 class RegistryLayer : public QAbstractValueSpaceLayer
       
   146 {
       
   147     Q_OBJECT
       
   148 
       
   149 public:
       
   150     RegistryLayer(const QString &basePath, bool volatileKeys, RegistryCallback callback);
       
   151     ~RegistryLayer();
       
   152 
       
   153     /* Common functions */
       
   154     bool startup(Type t);
       
   155 
       
   156     Handle item(Handle parent, const QString &path);
       
   157     void removeHandle(Handle handle);
       
   158     void setProperty(Handle handle, Properties);
       
   159 
       
   160     bool value(Handle handle, QVariant *data);
       
   161     bool value(Handle handle, const QString &subPath, QVariant *data);
       
   162     QSet<QString> children(Handle handle);
       
   163 
       
   164     /* QValueSpaceSubscriber functions */
       
   165     bool supportsInterestNotification() const;
       
   166     bool notifyInterest(Handle handle, bool interested);
       
   167 
       
   168     /* QValueSpacePublisher functions */
       
   169     bool setValue(QValueSpacePublisher *creator, Handle handle, const QVariant &data);
       
   170     bool setValue(QValueSpacePublisher *creator, Handle handle, const QString &path,
       
   171                   const QVariant &data);
       
   172     bool removeValue(QValueSpacePublisher *creator, Handle handle, const QString &subPath);
       
   173     bool removeSubTree(QValueSpacePublisher *creator, Handle parent);
       
   174     void addWatch(QValueSpacePublisher *creator, Handle handle);
       
   175     void removeWatches(QValueSpacePublisher *creator, Handle parent);
       
   176     void sync();
       
   177 
       
   178 public slots:
       
   179     void emitHandleChanged(void *hkey);
       
   180 #ifdef Q_OS_WINCE
       
   181     void eventSignaled(void *handle);
       
   182 #endif
       
   183 
       
   184 private:
       
   185     struct RegistryHandle {
       
   186         RegistryHandle(const QString &p)
       
   187         :   path(p), valueHandle(false), refCount(1)
       
   188         {
       
   189         }
       
   190 
       
   191         QString path;
       
   192         bool valueHandle;
       
   193         unsigned int refCount;
       
   194     };
       
   195 
       
   196     void openRegistryKey(RegistryHandle *handle);
       
   197     bool createRegistryKey(RegistryHandle *handle);
       
   198     bool removeRegistryValue(RegistryHandle *handle, const QString &path);
       
   199     void closeRegistryKey(RegistryHandle *handle);
       
   200     void pruneEmptyKeys(RegistryHandle *handle);
       
   201 
       
   202     QMutex localLock;
       
   203     QString m_basePath;
       
   204     bool m_volatileKeys;
       
   205     RegistryCallback m_callback;
       
   206 
       
   207     QHash<QString, RegistryHandle *> handles;
       
   208 
       
   209     RegistryHandle *registryHandle(Handle handle)
       
   210     {
       
   211         if (handle == InvalidHandle)
       
   212             return 0;
       
   213 
       
   214         RegistryHandle *h = reinterpret_cast<RegistryHandle *>(handle);
       
   215         if (handles.values().contains(h))
       
   216             return h;
       
   217 
       
   218         return 0;
       
   219     }
       
   220 
       
   221     QMap<RegistryHandle *, HKEY> hKeys;
       
   222     QMultiMap<RegistryHandle *, RegistryHandle *> notifyProxies;
       
   223     // MinGW complains about QPair<::HANDLE, ::HANDLE>
       
   224     typedef ::HANDLE HandleType;
       
   225     typedef QPair<HandleType, HandleType> HandlePair;
       
   226     QMap<HKEY, HandlePair > waitHandles;
       
   227 #ifdef Q_OS_WINCE
       
   228     QWindowsCENotify *notifyThread;
       
   229 #endif
       
   230 
       
   231     QMap<QValueSpacePublisher *, QList<QString> > creators;
       
   232 };
       
   233 
       
   234 class VolatileRegistryLayer : public RegistryLayer
       
   235 {
       
   236     Q_OBJECT
       
   237 
       
   238 public:
       
   239     VolatileRegistryLayer();
       
   240     ~VolatileRegistryLayer();
       
   241 
       
   242     /* Common functions */
       
   243     QString name();
       
   244 
       
   245     QUuid id();
       
   246     unsigned int order();
       
   247 
       
   248     QValueSpace::LayerOptions layerOptions() const;
       
   249 
       
   250     static VolatileRegistryLayer *instance();
       
   251 };
       
   252 
       
   253 Q_GLOBAL_STATIC(VolatileRegistryLayer, volatileRegistryLayer);
       
   254 QVALUESPACE_AUTO_INSTALL_LAYER(VolatileRegistryLayer);
       
   255 
       
   256 class NonVolatileRegistryLayer : public RegistryLayer
       
   257 {
       
   258     Q_OBJECT
       
   259 
       
   260 public:
       
   261     NonVolatileRegistryLayer();
       
   262     ~NonVolatileRegistryLayer();
       
   263 
       
   264     /* Common functions */
       
   265     QString name();
       
   266 
       
   267     QUuid id();
       
   268     unsigned int order();
       
   269 
       
   270     QValueSpace::LayerOptions layerOptions() const;
       
   271 
       
   272     static NonVolatileRegistryLayer *instance();
       
   273 };
       
   274 
       
   275 Q_GLOBAL_STATIC(NonVolatileRegistryLayer, nonVolatileRegistryLayer);
       
   276 QVALUESPACE_AUTO_INSTALL_LAYER(NonVolatileRegistryLayer);
       
   277 
       
   278 #ifdef Q_OS_WINCE
       
   279 void qVolatileRegistryLayerCallback(HREGNOTIFY hNotify, DWORD dwUserData,
       
   280                                     const PBYTE pData, const UINT cbdata)
       
   281 {
       
   282 }
       
   283 
       
   284 void qNonVolatileRegistryLayerCallback(HREGNOTIFY hNotify, DWORD dwUserData,
       
   285                                     const PBYTE pData, const UINT cbdata)
       
   286 {
       
   287 }
       
   288 
       
   289 #else
       
   290 void CALLBACK qVolatileRegistryLayerCallback(PVOID lpParameter, BOOLEAN)
       
   291 {
       
   292     QMetaObject::invokeMethod(volatileRegistryLayer(), "emitHandleChanged", Qt::QueuedConnection,
       
   293                               Q_ARG(void *, lpParameter));
       
   294 }
       
   295 
       
   296 void CALLBACK qNonVolatileRegistryLayerCallback(PVOID lpParameter, BOOLEAN)
       
   297 {
       
   298     QMetaObject::invokeMethod(nonVolatileRegistryLayer(), "emitHandleChanged",
       
   299                               Qt::QueuedConnection, Q_ARG(void *, lpParameter));
       
   300 }
       
   301 #endif
       
   302 
       
   303 static QString qConvertPath(const QString &path)
       
   304 {
       
   305     QString fixedPath(path);
       
   306 
       
   307     while (fixedPath.endsWith(QLatin1Char('/')))
       
   308         fixedPath.chop(1);
       
   309 
       
   310     fixedPath.replace(QLatin1Char('/'), QLatin1Char('\\'));
       
   311 
       
   312     return fixedPath;
       
   313 }
       
   314 
       
   315 VolatileRegistryLayer::VolatileRegistryLayer()
       
   316 :   RegistryLayer(QLatin1String("Software/Nokia/QtMobility/volatileContext"), true,
       
   317                   &qVolatileRegistryLayerCallback)
       
   318 {
       
   319 }
       
   320 
       
   321 VolatileRegistryLayer::~VolatileRegistryLayer()
       
   322 {
       
   323 }
       
   324 
       
   325 QString VolatileRegistryLayer::name()
       
   326 {
       
   327     return QLatin1String("Volatile Registry Layer");
       
   328 }
       
   329 
       
   330 QUuid VolatileRegistryLayer::id()
       
   331 {
       
   332     return QVALUESPACE_VOLATILEREGISTRY_LAYER;
       
   333 }
       
   334 
       
   335 unsigned int VolatileRegistryLayer::order()
       
   336 {
       
   337     return 0x1000;
       
   338 }
       
   339 
       
   340 QValueSpace::LayerOptions VolatileRegistryLayer::layerOptions() const
       
   341 {
       
   342     return QValueSpace::TransientLayer | QValueSpace::WritableLayer;
       
   343 }
       
   344 
       
   345 VolatileRegistryLayer *VolatileRegistryLayer::instance()
       
   346 {
       
   347     return volatileRegistryLayer();
       
   348 }
       
   349 
       
   350 NonVolatileRegistryLayer::NonVolatileRegistryLayer()
       
   351 :   RegistryLayer(QLatin1String("Software/Nokia/QtMobility/nonVolatileContext"), false,
       
   352                   &qNonVolatileRegistryLayerCallback)
       
   353 {
       
   354 }
       
   355 
       
   356 NonVolatileRegistryLayer::~NonVolatileRegistryLayer()
       
   357 {
       
   358 }
       
   359 
       
   360 QString NonVolatileRegistryLayer::name()
       
   361 {
       
   362     return QLatin1String("Non-Volatile Registry Layer");
       
   363 }
       
   364 
       
   365 QUuid NonVolatileRegistryLayer::id()
       
   366 {
       
   367     return QVALUESPACE_NONVOLATILEREGISTRY_LAYER;
       
   368 }
       
   369 
       
   370 unsigned int NonVolatileRegistryLayer::order()
       
   371 {
       
   372     return 0;
       
   373 }
       
   374 
       
   375 QValueSpace::LayerOptions NonVolatileRegistryLayer::layerOptions() const
       
   376 {
       
   377     return QValueSpace::PermanentLayer | QValueSpace::WritableLayer;
       
   378 }
       
   379 
       
   380 NonVolatileRegistryLayer *NonVolatileRegistryLayer::instance()
       
   381 {
       
   382     return nonVolatileRegistryLayer();
       
   383 }
       
   384 
       
   385 RegistryLayer::RegistryLayer(const QString &basePath, bool volatileKeys, RegistryCallback callback)
       
   386 :   localLock(QMutex::Recursive), m_basePath(basePath), m_volatileKeys(volatileKeys),
       
   387     m_callback(callback)
       
   388 {
       
   389     // Ensure that the m_basePath key exists and is non-volatile.
       
   390     HKEY key;
       
   391     RegCreateKeyEx(HKEY_CURRENT_USER,
       
   392                     reinterpret_cast<const wchar_t*>(qConvertPath(m_basePath).utf16()),
       
   393                     0, 0, REG_OPTION_NON_VOLATILE, KEY_ALL_ACCESS, 0, &key, 0);
       
   394 
       
   395     RegCloseKey(key);
       
   396 
       
   397 #ifdef Q_OS_WINCE
       
   398     notifyThread = new QWindowsCENotify(this);
       
   399     connect(notifyThread, SIGNAL(eventSignaled(void*)),
       
   400             this, SLOT(eventSignaled(void*)), Qt::QueuedConnection);
       
   401     notifyThread->start();
       
   402 #endif
       
   403 }
       
   404 
       
   405 RegistryLayer::~RegistryLayer()
       
   406 {
       
   407     QMutableHashIterator<QString, RegistryHandle *> i(handles);
       
   408     while (i.hasNext()) {
       
   409         i.next();
       
   410 
       
   411         RegistryHandle *handle = i.value();
       
   412 
       
   413         if (handle->valueHandle)
       
   414             removeHandle(Handle(handle));
       
   415     }
       
   416 
       
   417     i.toFront();
       
   418     while (i.hasNext()) {
       
   419         i.next();
       
   420 
       
   421         removeHandle(Handle(i.value()));
       
   422     }
       
   423 }
       
   424 
       
   425 bool RegistryLayer::startup(Type)
       
   426 {
       
   427     return true;
       
   428 }
       
   429 
       
   430 bool RegistryLayer::value(Handle handle, QVariant *data)
       
   431 {
       
   432     QMutexLocker locker(&localLock);
       
   433 
       
   434     RegistryHandle *rh = registryHandle(handle);
       
   435     if (!rh)
       
   436         return false;
       
   437 
       
   438     return value(InvalidHandle, rh->path, data);
       
   439 }
       
   440 
       
   441 bool RegistryLayer::value(Handle handle, const QString &subPath, QVariant *data)
       
   442 {
       
   443     QMutexLocker locker(&localLock);
       
   444 
       
   445     if (handle != InvalidHandle && !registryHandle(handle))
       
   446         return false;
       
   447 
       
   448     QString path(subPath);
       
   449     while (path.endsWith(QLatin1Char('/')))
       
   450         path.chop(1);
       
   451     if (handle != InvalidHandle)
       
   452         while (path.startsWith(QLatin1Char('/')))
       
   453             path = path.mid(1);
       
   454 
       
   455     Handle fullHandle = item(handle, subPath);
       
   456     if (fullHandle != InvalidHandle) {
       
   457         RegistryHandle *rh = registryHandle(fullHandle);
       
   458         if (rh) {
       
   459             openRegistryKey(rh);
       
   460             if (!rh->valueHandle) {
       
   461                 handle = fullHandle;
       
   462                 path.clear();
       
   463             }
       
   464         }
       
   465     }
       
   466 
       
   467     int index = path.lastIndexOf(QLatin1Char('/'), -1);
       
   468 
       
   469     bool createdHandle = false;
       
   470 
       
   471     QString value;
       
   472     if (index == -1) {
       
   473         value = path;
       
   474     } else {
       
   475         // want a value that is in a sub path under handle
       
   476         value = path.mid(index + 1);
       
   477         path.truncate(index);
       
   478         if (path.isEmpty())
       
   479             path = QLatin1String("/");
       
   480 
       
   481         handle = item(handle, path);
       
   482         createdHandle = true;
       
   483     }
       
   484 
       
   485     RegistryHandle *rh = registryHandle(handle);
       
   486 
       
   487     openRegistryKey(rh);
       
   488     if (!hKeys.contains(rh)) {
       
   489         if (createdHandle)
       
   490             removeHandle(handle);
       
   491 
       
   492         return false;
       
   493     }
       
   494 
       
   495     HKEY key = hKeys.value(rh);
       
   496 
       
   497     DWORD regSize = 0;
       
   498     long result = RegQueryValueEx(key,
       
   499             reinterpret_cast<const wchar_t*>(value.utf16()), 0, 0, 0, &regSize);
       
   500     if (result == ERROR_FILE_NOT_FOUND) {
       
   501         *data = QVariant();
       
   502         if (createdHandle)
       
   503             removeHandle(handle);
       
   504         return false;
       
   505     } else if (result != ERROR_SUCCESS) {
       
   506         qDebug() << "RegQueryValueEx failed with error" << result;
       
   507         *data = QVariant();
       
   508         if (createdHandle)
       
   509             removeHandle(handle);
       
   510         return false;
       
   511     }
       
   512 
       
   513     BYTE *regData = new BYTE[regSize];
       
   514     DWORD regType;
       
   515 
       
   516     result = RegQueryValueEx(key,
       
   517             reinterpret_cast<const wchar_t*>(value.utf16()), 
       
   518             0, &regType, regData, &regSize);
       
   519     if (result != ERROR_SUCCESS) {
       
   520         qDebug() << "real RegQueryValueEx failed with error" << result;
       
   521         if (createdHandle)
       
   522             removeHandle(handle);
       
   523         return false;
       
   524     }
       
   525 
       
   526     switch (regType) {
       
   527     case REG_DWORD:
       
   528         *data = qVariantFromValue(*reinterpret_cast<uint *>(regData));
       
   529         break;
       
   530     case REG_QWORD:
       
   531         *data = qVariantFromValue(*reinterpret_cast<quint64 *>(regData));
       
   532         break;
       
   533     case REG_SZ:
       
   534         *data = qVariantFromValue(QString::fromWCharArray(reinterpret_cast<wchar_t *>(regData)));
       
   535         break;
       
   536     case REG_MULTI_SZ: {
       
   537         QStringList list;
       
   538         wchar_t *temp = reinterpret_cast<wchar_t *>(regData);
       
   539         while (*temp != L'\0') {
       
   540             QString string = QString::fromWCharArray(temp);
       
   541             list << string;
       
   542             temp += string.length() + 1;
       
   543         }
       
   544         *data = qVariantFromValue(list);
       
   545         break;
       
   546     }
       
   547     case REG_BINARY:
       
   548         *data = qVariantFromValue(QByteArray(reinterpret_cast<char *>(regData), regSize));
       
   549         break;
       
   550     case REG_NONE: {
       
   551         QDataStream stream(QByteArray::fromRawData(reinterpret_cast<char *>(regData), regSize));
       
   552         stream >> *data;
       
   553         break;
       
   554     }
       
   555     default:
       
   556         qDebug() << "Unknown REG type" << regType;
       
   557         delete[] regData;
       
   558         if (createdHandle)
       
   559             removeHandle(handle);
       
   560         return false;
       
   561         break;
       
   562     }
       
   563 
       
   564     delete[] regData;
       
   565 
       
   566     if (createdHandle)
       
   567         removeHandle(handle);
       
   568 
       
   569     return true;
       
   570 }
       
   571 
       
   572 #define MAX_KEY_LENGTH 255
       
   573 #define MAX_NAME_LENGTH 16383
       
   574 QSet<QString> RegistryLayer::children(Handle handle)
       
   575 {
       
   576     QMutexLocker locker(&localLock);
       
   577 
       
   578     QSet<QString> foundChildren;
       
   579 
       
   580     RegistryHandle *rh = registryHandle(handle);
       
   581     if (!rh)
       
   582         return foundChildren;
       
   583 
       
   584     openRegistryKey(rh);
       
   585     if (rh->valueHandle || !hKeys.contains(rh))
       
   586         return foundChildren;
       
   587 
       
   588     HKEY key = hKeys.value(rh);
       
   589     int i = 0;
       
   590     long result;
       
   591     do {
       
   592         TCHAR subKey[MAX_KEY_LENGTH];
       
   593         DWORD subKeySize = MAX_KEY_LENGTH;
       
   594 
       
   595         result = RegEnumKeyEx(key, i, subKey, &subKeySize, 0, 0, 0, 0);
       
   596         if (result == ERROR_KEY_DELETED) {
       
   597             QMetaObject::invokeMethod(this, "emitHandleChanged", Qt::QueuedConnection,
       
   598                                       Q_ARG(void *, key));
       
   599             break;
       
   600         }
       
   601         if (result != ERROR_SUCCESS)
       
   602             break;
       
   603 
       
   604         foundChildren << QString::fromWCharArray(subKey, subKeySize);
       
   605         ++i;
       
   606     } while (result == ERROR_SUCCESS);
       
   607 
       
   608     i = 0;
       
   609     do {
       
   610         TCHAR valueName[MAX_NAME_LENGTH];
       
   611         DWORD valueNameSize = MAX_NAME_LENGTH;
       
   612 
       
   613         result = RegEnumValue(key, i, valueName, &valueNameSize, 0, 0, 0, 0);
       
   614         if (result == ERROR_KEY_DELETED) {
       
   615             QMetaObject::invokeMethod(this, "emitHandleChanged", Qt::QueuedConnection,
       
   616                                       Q_ARG(void *, key));
       
   617             break;
       
   618         }
       
   619         if (result != ERROR_SUCCESS)
       
   620             break;
       
   621 
       
   622         QString value = QString::fromWCharArray(valueName, valueNameSize);
       
   623         if (!value.isEmpty())
       
   624             foundChildren << value;
       
   625 
       
   626         ++i;
       
   627     } while (result == ERROR_SUCCESS);
       
   628 
       
   629     return foundChildren;
       
   630 }
       
   631 
       
   632 QAbstractValueSpaceLayer::Handle RegistryLayer::item(Handle parent, const QString &path)
       
   633 {
       
   634     QMutexLocker locker(&localLock);
       
   635 
       
   636     QString fullPath;
       
   637 
       
   638     // Fail on invalid path.
       
   639     if (path.isEmpty() || path.contains(QLatin1String("//")))
       
   640         return InvalidHandle;
       
   641 
       
   642     if (parent == InvalidHandle) {
       
   643         fullPath = path;
       
   644     } else {
       
   645         RegistryHandle *rh = registryHandle(parent);
       
   646         if (!rh)
       
   647             return InvalidHandle;
       
   648 
       
   649         if (path == QLatin1String("/")) {
       
   650             fullPath = rh->path;
       
   651         } else if (rh->path.endsWith(QLatin1Char('/')) && path.startsWith(QLatin1Char('/')))
       
   652             fullPath = rh->path + path.mid(1);
       
   653         else if (!rh->path.endsWith(QLatin1Char('/')) && !path.startsWith(QLatin1Char('/')))
       
   654             fullPath = rh->path + QLatin1Char('/') + path;
       
   655         else
       
   656             fullPath = rh->path + path;
       
   657     }
       
   658 
       
   659     if (handles.contains(fullPath)) {
       
   660         RegistryHandle *rh = handles.value(fullPath);
       
   661         ++rh->refCount;
       
   662         return Handle(rh);
       
   663     }
       
   664 
       
   665     // Create a new handle for path
       
   666     RegistryHandle *rh = new RegistryHandle(fullPath);
       
   667     handles.insert(fullPath, rh);
       
   668 
       
   669     return Handle(rh);
       
   670 }
       
   671 
       
   672 void RegistryLayer::setProperty(Handle handle, Properties properties)
       
   673 {
       
   674     QMutexLocker locker(&localLock);
       
   675 
       
   676     RegistryHandle *rh = registryHandle(handle);
       
   677     if (!rh)
       
   678         return;
       
   679 
       
   680     if (properties & QAbstractValueSpaceLayer::Publish) {
       
   681         // Enable change notification for handle
       
   682         openRegistryKey(rh);
       
   683         if (!hKeys.contains(rh)) {
       
   684             // The key does not exist. Temporarily use the parent key as a proxy.
       
   685             QString path = rh->path;
       
   686             while (!path.isEmpty()) {
       
   687                 rh = registryHandle(item(InvalidHandle, path));
       
   688                 openRegistryKey(rh);
       
   689                 if (hKeys.contains(rh)) {
       
   690                     notifyProxies.insert(rh, registryHandle(handle));
       
   691                     break;
       
   692                 }
       
   693                 removeHandle(Handle(rh));
       
   694 
       
   695                 // root path doesn't exists
       
   696                 if (path.length() == 1)
       
   697                     return;
       
   698 
       
   699                 int index = path.lastIndexOf(QLatin1Char('/'));
       
   700                 if (index == 0)
       
   701                     path.truncate(1);
       
   702                 else
       
   703                     path.truncate(index);
       
   704             }
       
   705         }
       
   706 
       
   707         HKEY key = hKeys.value(rh);
       
   708 
       
   709         if (waitHandles.contains(key))
       
   710             return;
       
   711 
       
   712 #ifdef Q_OS_WINCE
       
   713         DWORD filter = REG_NOTIFY_CHANGE_NAME | REG_NOTIFY_CHANGE_LAST_SET;
       
   714         ::HANDLE event = CeFindFirstRegChange(key, true, filter);
       
   715         if (event == INVALID_HANDLE_VALUE) {
       
   716             qDebug() << "CeFindFirstRegChange failed with error" << GetLastError();
       
   717             return;
       
   718         }
       
   719 
       
   720         notifyThread->addHandle(event);
       
   721 
       
   722         waitHandles.insert(key, QPair<::HANDLE, ::HANDLE>(event, INVALID_HANDLE_VALUE));
       
   723 #else
       
   724         ::HANDLE event = CreateEvent(0, false, false, 0);
       
   725         if (event == 0) {
       
   726             qDebug() << "CreateEvent failed with error" << GetLastError();
       
   727             return;
       
   728         }
       
   729 
       
   730         DWORD filter = REG_NOTIFY_CHANGE_NAME | REG_NOTIFY_CHANGE_ATTRIBUTES | REG_NOTIFY_CHANGE_LAST_SET;
       
   731         long result = RegNotifyChangeKeyValue(key, true, filter, event, true);
       
   732 
       
   733         if (result != ERROR_SUCCESS) {
       
   734             qDebug() << "RegNotifyChangeKeyValue failed with error" << result;
       
   735             return;
       
   736         }
       
   737 
       
   738         ::HANDLE waitHandle;
       
   739         if (!RegisterWaitForSingleObject(&waitHandle, event, m_callback, key,
       
   740                                          INFINITE, WT_EXECUTEDEFAULT)) {
       
   741             qDebug() << "RegisterWaitForSingleObject failed with error" << GetLastError();
       
   742             return;
       
   743         }
       
   744 
       
   745         //waitHandles.insert(key, QPair<::HANDLE, ::HANDLE>(event, waitHandle));
       
   746         waitHandles.insert(key, HandlePair(event, waitHandle));
       
   747 #endif
       
   748     }
       
   749     if (!(properties & QAbstractValueSpaceLayer::Publish)) {
       
   750         // Disable change notification for handle
       
   751         if (!hKeys.contains(rh))
       
   752             return;
       
   753 
       
   754         HKEY key = hKeys.value(rh);
       
   755 
       
   756         if (waitHandles.contains(key)) {
       
   757             //QPair<::HANDLE, ::HANDLE> wait = waitHandles.take(key);
       
   758             HandlePair wait = waitHandles.take(key);
       
   759 
       
   760 #ifdef Q_OS_WINCE
       
   761             notifyThread->removeHandle(wait.first);
       
   762 #else
       
   763             UnregisterWait(wait.second);
       
   764 #endif
       
   765 
       
   766             CloseHandle(wait.first);
       
   767         }
       
   768     }
       
   769 }
       
   770 
       
   771 void RegistryLayer::removeHandle(Handle handle)
       
   772 {
       
   773     QMutexLocker locker(&localLock);
       
   774 
       
   775     RegistryHandle *rh = registryHandle(handle);
       
   776     if (!rh)
       
   777         return;
       
   778 
       
   779     if (--rh->refCount)
       
   780         return;
       
   781 
       
   782     QList<RegistryHandle *> proxies = notifyProxies.keys(rh);
       
   783     while (!proxies.isEmpty()) {
       
   784         notifyProxies.remove(proxies.first(), rh);
       
   785         removeHandle(Handle(proxies.takeFirst()));
       
   786     }
       
   787 
       
   788     handles.remove(rh->path);
       
   789 
       
   790     closeRegistryKey(rh);
       
   791 
       
   792     delete rh;
       
   793 }
       
   794 
       
   795 void RegistryLayer::closeRegistryKey(RegistryHandle *handle)
       
   796 {
       
   797     QMutexLocker locker(&localLock);
       
   798 
       
   799     if (!hKeys.contains(handle))
       
   800         return;
       
   801 
       
   802     HKEY key = hKeys.take(handle);
       
   803 
       
   804     // Check if other handles are using this registry key.
       
   805     if (!hKeys.keys(key).isEmpty())
       
   806         return;
       
   807 
       
   808     if (waitHandles.contains(key)) {
       
   809         //QPair<::HANDLE, ::HANDLE> wait = waitHandles.take(key);
       
   810         HandlePair wait = waitHandles.take(key);
       
   811 
       
   812 #ifdef Q_OS_WINCE
       
   813         notifyThread->removeHandle(wait.first);
       
   814 #else
       
   815         UnregisterWait(wait.second);
       
   816 #endif
       
   817 
       
   818         CloseHandle(wait.first);
       
   819     }
       
   820 
       
   821     RegCloseKey(key);
       
   822 }
       
   823 
       
   824 static LONG qRegDeleteTree(HKEY hKey, LPCTSTR lpSubKey)
       
   825 {
       
   826     HKEY key;
       
   827     long result = RegOpenKeyEx(hKey, lpSubKey, 0, KEY_ALL_ACCESS, &key);
       
   828     if (result != ERROR_SUCCESS) {
       
   829         if (result == ERROR_FILE_NOT_FOUND)
       
   830             return ERROR_SUCCESS;
       
   831         else
       
   832             return result;
       
   833     }
       
   834 
       
   835     do {
       
   836         TCHAR subKey[MAX_KEY_LENGTH];
       
   837         DWORD subKeySize = MAX_KEY_LENGTH;
       
   838 
       
   839         result = RegEnumKeyEx(key, 0, subKey, &subKeySize, 0, 0, 0, 0);
       
   840         if (result == ERROR_NO_MORE_ITEMS)
       
   841             break;
       
   842 
       
   843         result = qRegDeleteTree(key, subKey);
       
   844     } while (result == ERROR_SUCCESS);
       
   845 
       
   846     RegCloseKey(key);
       
   847 
       
   848     if (result != ERROR_NO_MORE_ITEMS && result != ERROR_SUCCESS)
       
   849         return result;
       
   850 
       
   851     return RegDeleteKey(hKey, lpSubKey);
       
   852 }
       
   853 
       
   854 bool RegistryLayer::removeRegistryValue(RegistryHandle *handle, const QString &subPath)
       
   855 {
       
   856     QMutexLocker locker(&localLock);
       
   857 
       
   858     QString path(subPath);
       
   859     while (path.endsWith(QLatin1Char('/')))
       
   860         path.chop(1);
       
   861 
       
   862     int index = path.lastIndexOf(QLatin1Char('/'), -1);
       
   863 
       
   864     bool createdHandle = false;
       
   865 
       
   866     RegistryHandle *rh;
       
   867     QString value;
       
   868     if (index == -1) {
       
   869         rh = handle;
       
   870         value = path;
       
   871     } else {
       
   872         // want a value that is in a sub path under handle
       
   873         value = path.mid(index + 1);
       
   874         path.truncate(index);
       
   875         if (path.isEmpty())
       
   876             path.append(QLatin1Char('/'));
       
   877 
       
   878         rh = registryHandle(item(handle ? Handle(handle) : InvalidHandle, path));
       
   879 
       
   880         createdHandle = true;
       
   881     }
       
   882 
       
   883 #ifdef Q_OS_WINCE
       
   884     QList<RegistryHandle *> deletedKeys;
       
   885     QString fullPath;
       
   886     if (rh && rh->path != QLatin1String("/"))
       
   887         fullPath = rh->path + QLatin1Char('/') + value;
       
   888     else
       
   889         fullPath = QLatin1Char('/') + value;
       
   890 
       
   891     foreach (RegistryHandle *h, hKeys.keys()) {
       
   892         if (h->path.startsWith(fullPath) && !h->valueHandle) {
       
   893             deletedKeys.append(h);
       
   894             closeRegistryKey(h);
       
   895         }
       
   896     }
       
   897 #endif
       
   898 
       
   899     openRegistryKey(rh);
       
   900     if (!hKeys.contains(rh)) {
       
   901         if (createdHandle)
       
   902             removeHandle(Handle(rh));
       
   903 
       
   904         return false;
       
   905     }
       
   906 
       
   907     HKEY key = hKeys.value(rh);
       
   908 
       
   909     long result = RegDeleteValue(key, reinterpret_cast<const wchar_t*>(value.utf16()));
       
   910     if (result == ERROR_FILE_NOT_FOUND) {
       
   911         result = qRegDeleteTree(key, reinterpret_cast<const wchar_t*>(value.utf16()));
       
   912         if (result == ERROR_SUCCESS) {
       
   913             const QString rootPath = rh->path;
       
   914 
       
   915             QList<QString> paths = handles.keys();
       
   916             while (!paths.isEmpty()) {
       
   917                 QString p = paths.takeFirst();
       
   918 
       
   919                 if (p.startsWith(rootPath))
       
   920                     closeRegistryKey(handles.value(p));
       
   921             }
       
   922         }
       
   923         if (result != ERROR_SUCCESS)
       
   924             qDebug() << "RegDeleteTree failed with error" << result;
       
   925     } else if (result != ERROR_SUCCESS) {
       
   926         qDebug() << "RegDeleteValue failed with error" << result;
       
   927     }
       
   928 
       
   929 #ifdef Q_OS_WINCE
       
   930     while (!deletedKeys.isEmpty())
       
   931         emit handleChanged(Handle(deletedKeys.takeFirst()));
       
   932 #endif
       
   933 
       
   934     if (createdHandle)
       
   935         removeHandle(Handle(rh));
       
   936 
       
   937     return result == ERROR_SUCCESS;
       
   938 }
       
   939 
       
   940 bool RegistryLayer::setValue(QValueSpacePublisher *creator, Handle handle, const QVariant &data)
       
   941 {
       
   942     return setValue(creator, handle, QString(), data);
       
   943 }
       
   944 
       
   945 bool RegistryLayer::setValue(QValueSpacePublisher *creator, Handle handle, const QString &subPath,
       
   946                              const QVariant &data)
       
   947 {
       
   948     QMutexLocker locker(&localLock);
       
   949 
       
   950     RegistryHandle *rh = registryHandle(handle);
       
   951     if (!rh)
       
   952         return false;
       
   953 
       
   954     QString path(subPath);
       
   955     while (path.endsWith(QLatin1Char('/')))
       
   956         path.chop(1);
       
   957 
       
   958     int index = path.lastIndexOf(QLatin1Char('/'), -1);
       
   959 
       
   960     bool createdHandle = false;
       
   961 
       
   962     QString value;
       
   963     if (index == -1) {
       
   964         value = path;
       
   965     } else {
       
   966         // want a value that is in a sub path under handle
       
   967         value = path.mid(index + 1);
       
   968         path.truncate(index);
       
   969 
       
   970         if (path.isEmpty())
       
   971             path.append(QLatin1Char('/'));
       
   972 
       
   973         rh = registryHandle(item(Handle(rh), path));
       
   974         createdHandle = true;
       
   975     }
       
   976 
       
   977     if (!value.isEmpty()) {
       
   978         QString fullPath = rh->path;
       
   979         if (!fullPath.endsWith(QLatin1Char('/')))
       
   980             fullPath.append(QLatin1Char('/'));
       
   981         fullPath.append(value);
       
   982 
       
   983         RegistryHandle *fullHandle = registryHandle(item(InvalidHandle, fullPath));
       
   984         if (fullHandle) {
       
   985             fullHandle->valueHandle = true;
       
   986             removeHandle(Handle(fullHandle));
       
   987         }
       
   988     }
       
   989 
       
   990     if (createRegistryKey(rh)) {
       
   991         if (!creators[creator].contains(rh->path))
       
   992             creators[creator].append(rh->path);
       
   993     }
       
   994     if (!hKeys.contains(rh)) {
       
   995         if (createdHandle)
       
   996             removeHandle(Handle(rh));
       
   997 
       
   998         return false;
       
   999     }
       
  1000 
       
  1001     HKEY key = hKeys.value(rh);
       
  1002 
       
  1003     long result;
       
  1004 
       
  1005     switch (data.type()) {
       
  1006     case QVariant::UInt: {
       
  1007         DWORD temp = data.toUInt();
       
  1008         result = RegSetValueEx(key, reinterpret_cast<const wchar_t*>(value.utf16()), 0,
       
  1009                                REG_DWORD, reinterpret_cast<const BYTE *>(&temp), sizeof(DWORD));
       
  1010         break;
       
  1011     }
       
  1012     case QVariant::ULongLong: {
       
  1013         quint64 temp = data.toULongLong();
       
  1014         result = RegSetValueEx(key, reinterpret_cast<const wchar_t*>(value.utf16()), 0,
       
  1015                                REG_QWORD, reinterpret_cast<const BYTE *>(&temp), sizeof(quint64));
       
  1016         break;
       
  1017     }
       
  1018     case QVariant::String: {
       
  1019         // This may be wrong!
       
  1020         QString tempString = data.toString();
       
  1021         int length = tempString.length() + 1;
       
  1022         wchar_t *temp = new wchar_t[length];
       
  1023         tempString.toWCharArray(temp);
       
  1024         temp[length - 1] = L'\0';
       
  1025         result = RegSetValueEx(key, reinterpret_cast<const wchar_t*>(value.utf16()), 0,
       
  1026                     REG_SZ, reinterpret_cast<const BYTE *>(temp), length * sizeof(wchar_t));
       
  1027         delete[] temp;
       
  1028         break;
       
  1029     }
       
  1030     case QVariant::StringList: {
       
  1031         const QString joined = data.toStringList().join(QString(QLatin1Char('\0')));
       
  1032         int length = joined.length() + 2;
       
  1033         wchar_t *temp = new wchar_t[length];
       
  1034         joined.toWCharArray(temp);
       
  1035         temp[length - 2] = L'\0';
       
  1036         temp[length - 1] = L'\0';
       
  1037         result = RegSetValueEx(key, reinterpret_cast<const wchar_t*>(value.utf16()), 0,
       
  1038                                REG_MULTI_SZ, reinterpret_cast<const BYTE *>(temp),
       
  1039                                length * sizeof(wchar_t));
       
  1040         delete[] temp;
       
  1041         break;
       
  1042     }
       
  1043     case QVariant::ByteArray: {
       
  1044         QByteArray temp = data.toByteArray();
       
  1045         result = RegSetValueEx(key, reinterpret_cast<const wchar_t*>(value.utf16()), 0,
       
  1046                                REG_BINARY, reinterpret_cast<const BYTE *>(temp.constData()),
       
  1047                                temp.length());
       
  1048         break;
       
  1049     }
       
  1050     default: {
       
  1051         QByteArray temp;
       
  1052         QDataStream stream(&temp, QIODevice::WriteOnly | QIODevice::Truncate);
       
  1053         stream << data;
       
  1054         result = RegSetValueEx(key, reinterpret_cast<const wchar_t*>(value.utf16()), 0,
       
  1055                                REG_NONE, reinterpret_cast<const BYTE *>(temp.constData()),
       
  1056                                temp.length());
       
  1057         break;
       
  1058     }
       
  1059     };
       
  1060 
       
  1061     QString fullPath(rh->path);
       
  1062     if (fullPath != QLatin1String("/"))
       
  1063         fullPath.append(QLatin1Char('/'));
       
  1064 
       
  1065     fullPath.append(value);
       
  1066 
       
  1067     if (!creators[creator].contains(fullPath))
       
  1068         creators[creator].append(fullPath);
       
  1069 
       
  1070     if (createdHandle)
       
  1071         removeHandle(Handle(rh));
       
  1072 
       
  1073     return result == ERROR_SUCCESS;
       
  1074 }
       
  1075 
       
  1076 void RegistryLayer::sync()
       
  1077 {
       
  1078     QMutexLocker locker(&localLock);
       
  1079 
       
  1080     // Wait for change notification callbacks before returning
       
  1081     QEventLoop loop;
       
  1082     connect(this, SIGNAL(handleChanged(quintptr)), &loop, SLOT(quit()));
       
  1083     bool wait = false;
       
  1084 
       
  1085     QList<HKEY> keys = hKeys.values();
       
  1086     while (!keys.isEmpty()) {
       
  1087         HKEY key = keys.takeFirst();
       
  1088 
       
  1089         if (!wait && waitHandles.contains(key))
       
  1090             wait = true;
       
  1091 
       
  1092         RegFlushKey(key);
       
  1093     }
       
  1094 
       
  1095     if (wait) {
       
  1096         locker.unlock();
       
  1097         QTimer::singleShot(1000, &loop, SLOT(quit()));
       
  1098         loop.exec();
       
  1099     }
       
  1100 }
       
  1101 
       
  1102 void RegistryLayer::emitHandleChanged(void *k)
       
  1103 {
       
  1104     QMutexLocker locker(&localLock);
       
  1105 
       
  1106     HKEY key = reinterpret_cast<HKEY>(k);
       
  1107 
       
  1108     QList<RegistryHandle *> changedHandles = hKeys.keys(key);
       
  1109     if (changedHandles.isEmpty()) {
       
  1110         if (waitHandles.contains(key)) {
       
  1111             //QPair<::HANDLE, ::HANDLE> wait = waitHandles.take(key);
       
  1112             HandlePair wait = waitHandles.take(key);
       
  1113 
       
  1114 #ifdef Q_OS_WINCE
       
  1115             notifyThread->removeHandle(wait.first);
       
  1116 #else
       
  1117             UnregisterWait(wait.second);
       
  1118 #endif
       
  1119             CloseHandle(wait.first);
       
  1120             return;
       
  1121         }
       
  1122     }
       
  1123 
       
  1124     while (!changedHandles.isEmpty()) {
       
  1125         RegistryHandle *handle = changedHandles.takeFirst();
       
  1126         emit handleChanged(Handle(handle));
       
  1127 
       
  1128         // Emit signal for handles that this handle is proxying for.
       
  1129         foreach (RegistryHandle *proxied, notifyProxies.values(handle)) {
       
  1130             openRegistryKey(proxied);
       
  1131             if (hKeys.contains(proxied)) {
       
  1132                 notifyProxies.remove(handle, proxied);
       
  1133                 removeHandle(Handle(handle));
       
  1134                 setProperty(Handle(proxied), Publish);
       
  1135 
       
  1136                 emit handleChanged(Handle(proxied));
       
  1137             }
       
  1138         }
       
  1139     }
       
  1140 
       
  1141     if (waitHandles.contains(key)) {
       
  1142         //QPair<::HANDLE, ::HANDLE> wait = waitHandles.take(key);
       
  1143         HandlePair wait = waitHandles.take(key);
       
  1144 
       
  1145         ::HANDLE event = wait.first;
       
  1146 
       
  1147 #ifdef Q_OS_WINCE
       
  1148         notifyThread->removeHandle(event);
       
  1149 #else
       
  1150         UnregisterWait(wait.second);
       
  1151 #endif
       
  1152 
       
  1153 #ifdef Q_OS_WINCE
       
  1154         if (!CeFindNextRegChange(event)) {
       
  1155             long result = GetLastError();
       
  1156             if (result == ERROR_KEY_DELETED) {
       
  1157                 CloseHandle(event);
       
  1158 
       
  1159                 QList<RegistryHandle *> changedHandles = hKeys.keys(key);
       
  1160 
       
  1161                 for (int i = 0; i < changedHandles.count(); ++i)
       
  1162                     hKeys.remove(changedHandles.at(i));
       
  1163 
       
  1164                 RegCloseKey(key);
       
  1165 
       
  1166                 for (int i = 0; i < changedHandles.count(); ++i)
       
  1167                     setProperty(Handle(changedHandles.at(i)), Publish);
       
  1168             } else {
       
  1169                 qDebug() << "CeFindNextRegChange failed with error" << result;
       
  1170             }
       
  1171 
       
  1172             return;
       
  1173         }
       
  1174 
       
  1175         notifyThread->addHandle(event);
       
  1176 
       
  1177         waitHandles.insert(key, QPair<::HANDLE, ::HANDLE>(event, INVALID_HANDLE_VALUE));
       
  1178 #else
       
  1179         long result = RegNotifyChangeKeyValue(key, true, REG_NOTIFY_CHANGE_NAME |
       
  1180                                               REG_NOTIFY_CHANGE_ATTRIBUTES |
       
  1181                                               REG_NOTIFY_CHANGE_LAST_SET,
       
  1182                                               event, true);
       
  1183 
       
  1184         if (result != ERROR_SUCCESS) {
       
  1185             if (result == ERROR_KEY_DELETED || result == ERROR_INVALID_PARAMETER) {
       
  1186                 CloseHandle(event);
       
  1187 
       
  1188                 QList<RegistryHandle *> changedHandles = hKeys.keys(key);
       
  1189 
       
  1190                 for (int i = 0; i < changedHandles.count(); ++i)
       
  1191                     hKeys.remove(changedHandles.at(i));
       
  1192 
       
  1193                 RegCloseKey(key);
       
  1194 
       
  1195                 for (int i = 0; i < changedHandles.count(); ++i)
       
  1196                     setProperty(Handle(changedHandles.at(i)), Publish);
       
  1197             } else {
       
  1198                 qDebug() << "RegNotifyChangeKeyValue failed with error" << result;
       
  1199             }
       
  1200 
       
  1201             return;
       
  1202         }
       
  1203 
       
  1204         ::HANDLE waitHandle;
       
  1205 
       
  1206         if (!RegisterWaitForSingleObject(&waitHandle, event, m_callback, key,
       
  1207                                          INFINITE, WT_EXECUTEDEFAULT)) {
       
  1208             qDebug() << "RegisterWaitForSingleObject failed with error" << GetLastError();
       
  1209             return;
       
  1210         }
       
  1211 
       
  1212         //waitHandles.insert(key, QPair<::HANDLE, ::HANDLE>(event, waitHandle));
       
  1213         waitHandles.insert(key, HandlePair(event, waitHandle));
       
  1214 #endif
       
  1215     }
       
  1216 }
       
  1217 
       
  1218 #ifdef Q_OS_WINCE
       
  1219 void RegistryLayer::eventSignaled(void *handle)
       
  1220 {
       
  1221     QMutexLocker locker(&localLock);
       
  1222 
       
  1223     HKEY key = waitHandles.key(QPair<::HANDLE, ::HANDLE>(handle, INVALID_HANDLE_VALUE), 0);
       
  1224 
       
  1225     if (key != 0)
       
  1226         emitHandleChanged(key);
       
  1227 }
       
  1228 #endif
       
  1229 
       
  1230 void RegistryLayer::openRegistryKey(RegistryHandle *handle)
       
  1231 {
       
  1232     QMutexLocker locker(&localLock);
       
  1233 
       
  1234     if (!handle)
       
  1235         return;
       
  1236 
       
  1237     // Check if HKEY for this handle already exists.
       
  1238     if (hKeys.contains(handle))
       
  1239         return;
       
  1240 
       
  1241     const QString fullPath = qConvertPath(m_basePath + handle->path);
       
  1242 
       
  1243     // Attempt to open registry key path
       
  1244     HKEY key;
       
  1245     long result = RegOpenKeyEx(HKEY_CURRENT_USER,
       
  1246                                 reinterpret_cast<const wchar_t*>(fullPath.utf16()),
       
  1247                                 0, KEY_ALL_ACCESS, &key);
       
  1248 
       
  1249     if (result == ERROR_SUCCESS) {
       
  1250         hKeys.insert(handle, key);
       
  1251     } else if (result == ERROR_FILE_NOT_FOUND) {
       
  1252         // Key for handle does not exist in Registry, check if it is a value handle.
       
  1253         int index = handle->path.lastIndexOf(QLatin1Char('/'), -1);
       
  1254 
       
  1255         const QString parentPath = handle->path.left(index);
       
  1256         const QString valueName = handle->path.mid(index + 1);
       
  1257 
       
  1258         RegistryHandle *parentHandle = registryHandle(item(InvalidHandle, parentPath));
       
  1259         if (!parentHandle)
       
  1260             return;
       
  1261 
       
  1262         openRegistryKey(parentHandle);
       
  1263         if (!hKeys.contains(parentHandle)) {
       
  1264             removeHandle(Handle(parentHandle));
       
  1265             return;
       
  1266         }
       
  1267 
       
  1268         // Check if value exists.
       
  1269         if (!children(Handle(parentHandle)).contains(valueName)) {
       
  1270             removeHandle(Handle(parentHandle));
       
  1271             return;
       
  1272         }
       
  1273 
       
  1274         handle->valueHandle = true;
       
  1275 
       
  1276         hKeys.insert(handle, hKeys.value(parentHandle));
       
  1277 
       
  1278         removeHandle(Handle(parentHandle));
       
  1279     }
       
  1280 }
       
  1281 
       
  1282 bool RegistryLayer::createRegistryKey(RegistryHandle *handle)
       
  1283 {
       
  1284     QMutexLocker locker(&localLock);
       
  1285 
       
  1286     // Check if HKEY for this handle already exists.
       
  1287     if (hKeys.contains(handle))
       
  1288         return false;
       
  1289 
       
  1290     const QString fullPath = qConvertPath(m_basePath + handle->path);
       
  1291 
       
  1292     // Attempt to open registry key path
       
  1293     HKEY key;
       
  1294     DWORD disposition;
       
  1295     long result = RegCreateKeyEx(HKEY_CURRENT_USER,
       
  1296                                 reinterpret_cast<const wchar_t*>(fullPath.utf16()),
       
  1297                                  0, 0,
       
  1298                                  (m_volatileKeys ? REG_OPTION_VOLATILE : REG_OPTION_NON_VOLATILE),
       
  1299                                  KEY_ALL_ACCESS, 0, &key, &disposition);
       
  1300 
       
  1301     if (result == ERROR_SUCCESS)
       
  1302         hKeys.insert(handle, key);
       
  1303 
       
  1304     return disposition == REG_CREATED_NEW_KEY;
       
  1305 }
       
  1306 
       
  1307 bool RegistryLayer::removeSubTree(QValueSpacePublisher *creator, Handle handle)
       
  1308 {
       
  1309     QMutexLocker locker(&localLock);
       
  1310 
       
  1311     RegistryHandle *rh = registryHandle(handle);
       
  1312     if (!rh)
       
  1313         return false;
       
  1314 
       
  1315     QList<QString> paths = creators.value(creator);
       
  1316 
       
  1317     while (!paths.isEmpty()) {
       
  1318         QString item = paths.takeFirst();
       
  1319         if (!item.startsWith(rh->path))
       
  1320             continue;
       
  1321 
       
  1322         removeRegistryValue(0, item);
       
  1323         creators[creator].removeOne(item);
       
  1324 
       
  1325         int index = item.lastIndexOf(QLatin1Char('/'));
       
  1326         if (index == -1)
       
  1327             continue;
       
  1328 
       
  1329         item.truncate(index);
       
  1330         if (!paths.contains(item))
       
  1331             paths.append(item);
       
  1332     }
       
  1333 
       
  1334     pruneEmptyKeys(rh);
       
  1335 
       
  1336     return true;
       
  1337 }
       
  1338 
       
  1339 void RegistryLayer::pruneEmptyKeys(RegistryHandle *handle)
       
  1340 {
       
  1341     QMutexLocker locker(&localLock);
       
  1342 
       
  1343     if (!children(Handle(handle)).isEmpty())
       
  1344         return;
       
  1345 
       
  1346     QString path = handle->path;
       
  1347 
       
  1348     while (path != QLatin1String("/")) {
       
  1349         int index = path.lastIndexOf(QLatin1Char('/'), -1);
       
  1350 
       
  1351         QString value = path.mid(index + 1);
       
  1352 
       
  1353         path.truncate(index);
       
  1354         if (path.isEmpty())
       
  1355             path.append(QLatin1Char('/'));
       
  1356 
       
  1357         RegistryHandle *rh = registryHandle(item(InvalidHandle, path));
       
  1358 
       
  1359         openRegistryKey(rh);
       
  1360         if (!hKeys.contains(rh)) {
       
  1361             removeHandle(Handle(rh));
       
  1362             return;
       
  1363         }
       
  1364 
       
  1365         HKEY key = hKeys.value(rh);
       
  1366 
       
  1367         long result = RegDeleteKey(key, reinterpret_cast<const wchar_t*>(value.utf16()));
       
  1368         if (result == ERROR_SUCCESS) {
       
  1369             QList<QString> paths = handles.keys();
       
  1370             while (!paths.isEmpty()) {
       
  1371                 const QString p = paths.takeFirst();
       
  1372 
       
  1373                 if (p.startsWith(path))
       
  1374                     closeRegistryKey(handles.value(p));
       
  1375             }
       
  1376         } else if (result != ERROR_FILE_NOT_FOUND) {
       
  1377             return;
       
  1378         }
       
  1379 
       
  1380         bool hasChildren = !children(Handle(rh)).isEmpty();
       
  1381 
       
  1382         removeHandle(Handle(rh));
       
  1383 
       
  1384         if (hasChildren)
       
  1385             break;
       
  1386     }
       
  1387 }
       
  1388 
       
  1389 bool RegistryLayer::removeValue(QValueSpacePublisher *creator,
       
  1390                                 Handle handle,
       
  1391                                 const QString &subPath)
       
  1392 {
       
  1393     QMutexLocker locker(&localLock);
       
  1394 
       
  1395     QString fullPath;
       
  1396 
       
  1397     if (handle == InvalidHandle) {
       
  1398         fullPath = subPath;
       
  1399     } else {
       
  1400         RegistryHandle *rh = registryHandle(handle);
       
  1401         if (!rh)
       
  1402             return false;
       
  1403 
       
  1404         if (subPath == QLatin1String("/"))
       
  1405             fullPath = rh->path;
       
  1406         else if (rh->path.endsWith(QLatin1Char('/')) && subPath.startsWith(QLatin1Char('/')))
       
  1407             fullPath = rh->path + subPath.mid(1);
       
  1408         else if (!rh->path.endsWith(QLatin1Char('/')) && !subPath.startsWith(QLatin1Char('/')))
       
  1409             fullPath = rh->path + QLatin1Char('/') + subPath;
       
  1410         else
       
  1411             fullPath = rh->path + subPath;
       
  1412     }
       
  1413 
       
  1414     // permanent layer always removes items even if our records show that creator does not own it.
       
  1415     if (!creators[creator].contains(fullPath) && (layerOptions() & QValueSpace::TransientLayer))
       
  1416         return false;
       
  1417 
       
  1418     removeRegistryValue(0, fullPath);
       
  1419     creators[creator].removeOne(fullPath);
       
  1420 
       
  1421     return true;
       
  1422 }
       
  1423 
       
  1424 void RegistryLayer::addWatch(QValueSpacePublisher *, Handle)
       
  1425 {
       
  1426 }
       
  1427 
       
  1428 void RegistryLayer::removeWatches(QValueSpacePublisher *, Handle)
       
  1429 {
       
  1430 }
       
  1431 
       
  1432 bool RegistryLayer::supportsInterestNotification() const
       
  1433 {
       
  1434     return false;
       
  1435 }
       
  1436 
       
  1437 bool RegistryLayer::notifyInterest(Handle, bool)
       
  1438 {
       
  1439     return false;
       
  1440 }
       
  1441 #include <registrylayer_win.moc>
       
  1442 QTM_END_NAMESPACE
       
  1443 
       
  1444 
       
  1445