qtmobility/src/publishsubscribe/registrylayer_win.cpp
changeset 1 2b40d63a9c3d
child 11 06b8e2af4411
equal deleted inserted replaced
0:cfcbf08528c4 1:2b40d63a9c3d
       
     1 /****************************************************************************
       
     2 **
       
     3 ** Copyright (C) 2009 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     int index = path.lastIndexOf(QLatin1Char('/'), -1);
       
   456 
       
   457     bool createdHandle = false;
       
   458 
       
   459     QString value;
       
   460     if (index == -1) {
       
   461         value = path;
       
   462     } else {
       
   463         // want a value that is in a sub path under handle
       
   464         value = path.mid(index + 1);
       
   465         path.truncate(index);
       
   466 
       
   467         handle = item(handle, path);
       
   468         createdHandle = true;
       
   469     }
       
   470 
       
   471     RegistryHandle *rh = registryHandle(handle);
       
   472 
       
   473     openRegistryKey(rh);
       
   474     if (!hKeys.contains(rh)) {
       
   475         if (createdHandle)
       
   476             removeHandle(handle);
       
   477 
       
   478         return false;
       
   479     }
       
   480 
       
   481     HKEY key = hKeys.value(rh);
       
   482 
       
   483     DWORD regSize = 0;
       
   484     long result = RegQueryValueEx(key,
       
   485             reinterpret_cast<const wchar_t*>(value.utf16()), 0, 0, 0, &regSize);
       
   486     if (result == ERROR_FILE_NOT_FOUND) {
       
   487         *data = QVariant();
       
   488         if (createdHandle)
       
   489             removeHandle(handle);
       
   490         return false;
       
   491     } else if (result != ERROR_SUCCESS) {
       
   492         qDebug() << "RegQueryValueEx failed with error" << result;
       
   493         if (createdHandle)
       
   494             removeHandle(handle);
       
   495         return false;
       
   496     }
       
   497 
       
   498     BYTE *regData = new BYTE[regSize];
       
   499     DWORD regType;
       
   500 
       
   501     result = RegQueryValueEx(key,
       
   502             reinterpret_cast<const wchar_t*>(value.utf16()), 
       
   503             0, &regType, regData, &regSize);
       
   504     if (result != ERROR_SUCCESS) {
       
   505         qDebug() << "real RegQueryValueEx failed with error" << result;
       
   506         if (createdHandle)
       
   507             removeHandle(handle);
       
   508         return false;
       
   509     }
       
   510 
       
   511     switch (regType) {
       
   512     case REG_DWORD:
       
   513         *data = qVariantFromValue(*reinterpret_cast<uint *>(regData));
       
   514         break;
       
   515     case REG_QWORD:
       
   516         *data = qVariantFromValue(*reinterpret_cast<quint64 *>(regData));
       
   517         break;
       
   518     case REG_SZ:
       
   519         *data = qVariantFromValue(QString::fromWCharArray(reinterpret_cast<wchar_t *>(regData)));
       
   520         break;
       
   521     case REG_MULTI_SZ: {
       
   522         QStringList list;
       
   523         wchar_t *temp = reinterpret_cast<wchar_t *>(regData);
       
   524         while (*temp != L'\0') {
       
   525             QString string = QString::fromWCharArray(temp);
       
   526             list << string;
       
   527             temp += string.length() + 1;
       
   528         }
       
   529         *data = qVariantFromValue(list);
       
   530         break;
       
   531     }
       
   532     case REG_BINARY:
       
   533         *data = qVariantFromValue(QByteArray(reinterpret_cast<char *>(regData), regSize));
       
   534         break;
       
   535     case REG_NONE: {
       
   536         QDataStream stream(QByteArray::fromRawData(reinterpret_cast<char *>(regData), regSize));
       
   537         stream >> *data;
       
   538         break;
       
   539     }
       
   540     default:
       
   541         qDebug() << "Unknown REG type" << regType;
       
   542         delete[] regData;
       
   543         if (createdHandle)
       
   544             removeHandle(handle);
       
   545         return false;
       
   546         break;
       
   547     }
       
   548 
       
   549     delete[] regData;
       
   550 
       
   551     if (createdHandle)
       
   552         removeHandle(handle);
       
   553 
       
   554     return true;
       
   555 }
       
   556 
       
   557 #define MAX_KEY_LENGTH 255
       
   558 #define MAX_NAME_LENGTH 16383
       
   559 QSet<QString> RegistryLayer::children(Handle handle)
       
   560 {
       
   561     QMutexLocker locker(&localLock);
       
   562 
       
   563     QSet<QString> foundChildren;
       
   564 
       
   565     RegistryHandle *rh = registryHandle(handle);
       
   566     if (!rh)
       
   567         return foundChildren;
       
   568 
       
   569     openRegistryKey(rh);
       
   570     if (rh->valueHandle || !hKeys.contains(rh))
       
   571         return foundChildren;
       
   572 
       
   573     HKEY key = hKeys.value(rh);
       
   574     int i = 0;
       
   575     long result;
       
   576     do {
       
   577         TCHAR subKey[MAX_KEY_LENGTH];
       
   578         DWORD subKeySize = MAX_KEY_LENGTH;
       
   579 
       
   580         result = RegEnumKeyEx(key, i, subKey, &subKeySize, 0, 0, 0, 0);
       
   581         if (result == ERROR_NO_MORE_ITEMS)
       
   582             break;
       
   583 
       
   584         foundChildren << QString::fromWCharArray(subKey, subKeySize);
       
   585         ++i;
       
   586     } while (result == ERROR_SUCCESS);
       
   587 
       
   588     i = 0;
       
   589     do {
       
   590         TCHAR valueName[MAX_NAME_LENGTH];
       
   591         DWORD valueNameSize = MAX_NAME_LENGTH;
       
   592 
       
   593         result = RegEnumValue(key, i, valueName, &valueNameSize, 0, 0, 0, 0);
       
   594         if (result == ERROR_NO_MORE_ITEMS)
       
   595             break;
       
   596 
       
   597         foundChildren << QString::fromWCharArray(valueName, valueNameSize);
       
   598         ++i;
       
   599     } while (result == ERROR_SUCCESS);
       
   600 
       
   601     return foundChildren;
       
   602 }
       
   603 
       
   604 QAbstractValueSpaceLayer::Handle RegistryLayer::item(Handle parent, const QString &path)
       
   605 {
       
   606     QMutexLocker locker(&localLock);
       
   607 
       
   608     QString fullPath;
       
   609 
       
   610     // Fail on invalid path.
       
   611     if (path.isEmpty() || path.contains(QLatin1String("//")))
       
   612         return InvalidHandle;
       
   613 
       
   614     if (parent == InvalidHandle) {
       
   615         fullPath = path;
       
   616     } else {
       
   617         RegistryHandle *rh = registryHandle(parent);
       
   618         if (!rh)
       
   619             return InvalidHandle;
       
   620 
       
   621         if (path == QLatin1String("/")) {
       
   622             fullPath = rh->path;
       
   623         } else if (rh->path.endsWith(QLatin1Char('/')) && path.startsWith(QLatin1Char('/')))
       
   624             fullPath = rh->path + path.mid(1);
       
   625         else if (!rh->path.endsWith(QLatin1Char('/')) && !path.startsWith(QLatin1Char('/')))
       
   626             fullPath = rh->path + QLatin1Char('/') + path;
       
   627         else
       
   628             fullPath = rh->path + path;
       
   629     }
       
   630 
       
   631     if (handles.contains(fullPath)) {
       
   632         RegistryHandle *rh = handles.value(fullPath);
       
   633         ++rh->refCount;
       
   634         return Handle(rh);
       
   635     }
       
   636 
       
   637     // Create a new handle for path
       
   638     RegistryHandle *rh = new RegistryHandle(fullPath);
       
   639     handles.insert(fullPath, rh);
       
   640 
       
   641     return Handle(rh);
       
   642 }
       
   643 
       
   644 void RegistryLayer::setProperty(Handle handle, Properties properties)
       
   645 {
       
   646     QMutexLocker locker(&localLock);
       
   647 
       
   648     RegistryHandle *rh = registryHandle(handle);
       
   649     if (!rh)
       
   650         return;
       
   651 
       
   652     if (properties & QAbstractValueSpaceLayer::Publish) {
       
   653         // Enable change notification for handle
       
   654         openRegistryKey(rh);
       
   655         if (!hKeys.contains(rh)) {
       
   656             // The key does not exist. Temporarily use the parent key as a proxy.
       
   657             QString path = rh->path;
       
   658             while (!path.isEmpty()) {
       
   659                 rh = registryHandle(item(InvalidHandle, path));
       
   660                 openRegistryKey(rh);
       
   661                 if (hKeys.contains(rh)) {
       
   662                     notifyProxies.insert(rh, registryHandle(handle));
       
   663                     break;
       
   664                 }
       
   665                 removeHandle(Handle(rh));
       
   666 
       
   667                 // root path doesn't exists
       
   668                 if (path.length() == 1)
       
   669                     return;
       
   670 
       
   671                 int index = path.lastIndexOf(QLatin1Char('/'));
       
   672                 if (index == 0)
       
   673                     path.truncate(1);
       
   674                 else
       
   675                     path.truncate(index);
       
   676             }
       
   677         }
       
   678 
       
   679         HKEY key = hKeys.value(rh);
       
   680 
       
   681         if (waitHandles.contains(key))
       
   682             return;
       
   683 
       
   684 #ifdef Q_OS_WINCE
       
   685         DWORD filter = REG_NOTIFY_CHANGE_NAME | REG_NOTIFY_CHANGE_LAST_SET;
       
   686         ::HANDLE event = CeFindFirstRegChange(key, true, filter);
       
   687         if (event == INVALID_HANDLE_VALUE) {
       
   688             qDebug() << "CeFindFirstRegChange failed with error" << GetLastError();
       
   689             return;
       
   690         }
       
   691 
       
   692         notifyThread->addHandle(event);
       
   693 
       
   694         waitHandles.insert(key, QPair<::HANDLE, ::HANDLE>(event, INVALID_HANDLE_VALUE));
       
   695 #else
       
   696         ::HANDLE event = CreateEvent(0, false, false, 0);
       
   697         if (event == 0) {
       
   698             qDebug() << "CreateEvent failed with error" << GetLastError();
       
   699             return;
       
   700         }
       
   701 
       
   702         DWORD filter = REG_NOTIFY_CHANGE_NAME | REG_NOTIFY_CHANGE_ATTRIBUTES | REG_NOTIFY_CHANGE_LAST_SET;
       
   703         long result = RegNotifyChangeKeyValue(key, true, filter, event, true);
       
   704 
       
   705         if (result != ERROR_SUCCESS) {
       
   706             qDebug() << "RegNotifyChangeKeyValue failed with error" << result;
       
   707             return;
       
   708         }
       
   709 
       
   710         ::HANDLE waitHandle;
       
   711         if (!RegisterWaitForSingleObject(&waitHandle, event, m_callback, key,
       
   712                                          INFINITE, WT_EXECUTEDEFAULT)) {
       
   713             qDebug() << "RegisterWaitForSingleObject failed with error" << GetLastError();
       
   714             return;
       
   715         }
       
   716 
       
   717         //waitHandles.insert(key, QPair<::HANDLE, ::HANDLE>(event, waitHandle));
       
   718         waitHandles.insert(key, HandlePair(event, waitHandle));
       
   719 #endif
       
   720     }
       
   721     if (!(properties & QAbstractValueSpaceLayer::Publish)) {
       
   722         // Disable change notification for handle
       
   723         if (!hKeys.contains(rh))
       
   724             return;
       
   725 
       
   726         HKEY key = hKeys.value(rh);
       
   727 
       
   728         if (waitHandles.contains(key)) {
       
   729             //QPair<::HANDLE, ::HANDLE> wait = waitHandles.take(key);
       
   730             HandlePair wait = waitHandles.take(key);
       
   731 
       
   732 #ifdef Q_OS_WINCE
       
   733             notifyThread->removeHandle(wait.first);
       
   734 #else
       
   735             UnregisterWait(wait.second);
       
   736 #endif
       
   737 
       
   738             CloseHandle(wait.first);
       
   739         }
       
   740     }
       
   741 }
       
   742 
       
   743 void RegistryLayer::removeHandle(Handle handle)
       
   744 {
       
   745     QMutexLocker locker(&localLock);
       
   746 
       
   747     RegistryHandle *rh = registryHandle(handle);
       
   748     if (!rh)
       
   749         return;
       
   750 
       
   751     if (--rh->refCount)
       
   752         return;
       
   753 
       
   754     QList<RegistryHandle *> proxies = notifyProxies.keys(rh);
       
   755     while (!proxies.isEmpty()) {
       
   756         notifyProxies.remove(proxies.first(), rh);
       
   757         removeHandle(Handle(proxies.takeFirst()));
       
   758     }
       
   759 
       
   760     handles.remove(rh->path);
       
   761 
       
   762     closeRegistryKey(rh);
       
   763 
       
   764     delete rh;
       
   765 }
       
   766 
       
   767 void RegistryLayer::closeRegistryKey(RegistryHandle *handle)
       
   768 {
       
   769     QMutexLocker locker(&localLock);
       
   770 
       
   771     if (!hKeys.contains(handle))
       
   772         return;
       
   773 
       
   774     HKEY key = hKeys.take(handle);
       
   775 
       
   776     // Check if other handles are using this registry key.
       
   777     if (!hKeys.keys(key).isEmpty())
       
   778         return;
       
   779 
       
   780     if (waitHandles.contains(key)) {
       
   781         //QPair<::HANDLE, ::HANDLE> wait = waitHandles.take(key);
       
   782         HandlePair wait = waitHandles.take(key);
       
   783 
       
   784 #ifdef Q_OS_WINCE
       
   785         notifyThread->removeHandle(wait.first);
       
   786 #else
       
   787         UnregisterWait(wait.second);
       
   788 #endif
       
   789 
       
   790         CloseHandle(wait.first);
       
   791     }
       
   792 
       
   793     RegCloseKey(key);
       
   794 }
       
   795 
       
   796 static LONG qRegDeleteTree(HKEY hKey, LPCTSTR lpSubKey)
       
   797 {
       
   798     HKEY key;
       
   799     long result = RegOpenKeyEx(hKey, lpSubKey, 0, KEY_ALL_ACCESS, &key);
       
   800     if (result != ERROR_SUCCESS) {
       
   801         if (result == ERROR_FILE_NOT_FOUND)
       
   802             return ERROR_SUCCESS;
       
   803         else
       
   804             return result;
       
   805     }
       
   806 
       
   807     do {
       
   808         TCHAR subKey[MAX_KEY_LENGTH];
       
   809         DWORD subKeySize = MAX_KEY_LENGTH;
       
   810 
       
   811         result = RegEnumKeyEx(key, 0, subKey, &subKeySize, 0, 0, 0, 0);
       
   812         if (result == ERROR_NO_MORE_ITEMS)
       
   813             break;
       
   814 
       
   815         result = qRegDeleteTree(key, subKey);
       
   816     } while (result == ERROR_SUCCESS);
       
   817 
       
   818     RegCloseKey(key);
       
   819 
       
   820     if (result != ERROR_NO_MORE_ITEMS && result != ERROR_SUCCESS)
       
   821         return result;
       
   822 
       
   823     return RegDeleteKey(hKey, lpSubKey);
       
   824 }
       
   825 
       
   826 bool RegistryLayer::removeRegistryValue(RegistryHandle *handle, const QString &subPath)
       
   827 {
       
   828     QMutexLocker locker(&localLock);
       
   829 
       
   830     QString path(subPath);
       
   831     while (path.endsWith(QLatin1Char('/')))
       
   832         path.chop(1);
       
   833 
       
   834     int index = path.lastIndexOf(QLatin1Char('/'), -1);
       
   835 
       
   836     bool createdHandle = false;
       
   837 
       
   838     RegistryHandle *rh;
       
   839     QString value;
       
   840     if (index == -1) {
       
   841         rh = handle;
       
   842         value = path;
       
   843     } else {
       
   844         // want a value that is in a sub path under handle
       
   845         value = path.mid(index + 1);
       
   846         path.truncate(index);
       
   847         if (path.isEmpty())
       
   848             path.append(QLatin1Char('/'));
       
   849 
       
   850         rh = registryHandle(item(handle ? Handle(handle) : InvalidHandle, path));
       
   851 
       
   852         createdHandle = true;
       
   853     }
       
   854 
       
   855 #ifdef Q_OS_WINCE
       
   856     QList<RegistryHandle *> deletedKeys;
       
   857     QString fullPath;
       
   858     if (rh && rh->path != QLatin1String("/"))
       
   859         fullPath = rh->path + QLatin1Char('/') + value;
       
   860     else
       
   861         fullPath = QLatin1Char('/') + value;
       
   862 
       
   863     foreach (RegistryHandle *h, hKeys.keys()) {
       
   864         if (h->path.startsWith(fullPath) && !h->valueHandle) {
       
   865             deletedKeys.append(h);
       
   866             closeRegistryKey(h);
       
   867         }
       
   868     }
       
   869 #endif
       
   870 
       
   871     openRegistryKey(rh);
       
   872     if (!hKeys.contains(rh)) {
       
   873         if (createdHandle)
       
   874             removeHandle(Handle(rh));
       
   875 
       
   876         return false;
       
   877     }
       
   878 
       
   879     HKEY key = hKeys.value(rh);
       
   880 
       
   881     long result = RegDeleteValue(key, reinterpret_cast<const wchar_t*>(value.utf16()));
       
   882     if (result == ERROR_FILE_NOT_FOUND) {
       
   883         result = qRegDeleteTree(key, reinterpret_cast<const wchar_t*>(value.utf16()));
       
   884         if (result == ERROR_SUCCESS) {
       
   885             const QString rootPath = rh->path;
       
   886 
       
   887             QList<QString> paths = handles.keys();
       
   888             while (!paths.isEmpty()) {
       
   889                 QString p = paths.takeFirst();
       
   890 
       
   891                 if (p.startsWith(rootPath))
       
   892                     closeRegistryKey(handles.value(p));
       
   893             }
       
   894         }
       
   895         if (result != ERROR_SUCCESS)
       
   896             qDebug() << "RegDeleteTree failed with error" << result;
       
   897     } else if (result != ERROR_SUCCESS) {
       
   898         qDebug() << "RegDeleteValue failed with error" << result;
       
   899     }
       
   900 
       
   901 #ifdef Q_OS_WINCE
       
   902     while (!deletedKeys.isEmpty())
       
   903         emit handleChanged(Handle(deletedKeys.takeFirst()));
       
   904 #endif
       
   905 
       
   906     if (createdHandle)
       
   907         removeHandle(Handle(rh));
       
   908 
       
   909     return result == ERROR_SUCCESS;
       
   910 }
       
   911 
       
   912 bool RegistryLayer::setValue(QValueSpacePublisher *creator, Handle handle, const QVariant &data)
       
   913 {
       
   914     return setValue(creator, handle, QString(), data);
       
   915 }
       
   916 
       
   917 bool RegistryLayer::setValue(QValueSpacePublisher *creator, Handle handle, const QString &subPath,
       
   918                              const QVariant &data)
       
   919 {
       
   920     QMutexLocker locker(&localLock);
       
   921 
       
   922     RegistryHandle *rh = registryHandle(handle);
       
   923     if (!rh)
       
   924         return false;
       
   925 
       
   926     QString path(subPath);
       
   927     while (path.endsWith(QLatin1Char('/')))
       
   928         path.chop(1);
       
   929 
       
   930     int index = path.lastIndexOf(QLatin1Char('/'), -1);
       
   931 
       
   932     bool createdHandle = false;
       
   933 
       
   934     QString value;
       
   935     if (index == -1) {
       
   936         value = path;
       
   937     } else {
       
   938         // want a value that is in a sub path under handle
       
   939         value = path.mid(index + 1);
       
   940         path.truncate(index);
       
   941 
       
   942         if (path.isEmpty())
       
   943             path.append(QLatin1Char('/'));
       
   944 
       
   945         rh = registryHandle(item(Handle(rh), path));
       
   946         createdHandle = true;
       
   947     }
       
   948 
       
   949     if (createRegistryKey(rh)) {
       
   950         if (!creators[creator].contains(rh->path))
       
   951             creators[creator].append(rh->path);
       
   952     }
       
   953     if (!hKeys.contains(rh)) {
       
   954         if (createdHandle)
       
   955             removeHandle(Handle(rh));
       
   956 
       
   957         return false;
       
   958     }
       
   959 
       
   960     HKEY key = hKeys.value(rh);
       
   961 
       
   962     long result;
       
   963 
       
   964     switch (data.type()) {
       
   965     case QVariant::UInt: {
       
   966         DWORD temp = data.toUInt();
       
   967         result = RegSetValueEx(key, reinterpret_cast<const wchar_t*>(value.utf16()), 0,
       
   968                                REG_DWORD, reinterpret_cast<const BYTE *>(&temp), sizeof(DWORD));
       
   969         break;
       
   970     }
       
   971     case QVariant::ULongLong: {
       
   972         quint64 temp = data.toULongLong();
       
   973         result = RegSetValueEx(key, reinterpret_cast<const wchar_t*>(value.utf16()), 0,
       
   974                                REG_QWORD, reinterpret_cast<const BYTE *>(&temp), sizeof(quint64));
       
   975         break;
       
   976     }
       
   977     case QVariant::String: {
       
   978         // This may be wrong!
       
   979         QString tempString = data.toString();
       
   980         int length = tempString.length() + 1;
       
   981         wchar_t *temp = new wchar_t[length];
       
   982         tempString.toWCharArray(temp);
       
   983         temp[length - 1] = L'\0';
       
   984         result = RegSetValueEx(key, reinterpret_cast<const wchar_t*>(value.utf16()), 0,
       
   985                     REG_SZ, reinterpret_cast<const BYTE *>(temp), length * sizeof(wchar_t));
       
   986         delete[] temp;
       
   987         break;
       
   988     }
       
   989     case QVariant::StringList: {
       
   990         const QString joined = data.toStringList().join(QString(QLatin1Char('\0')));
       
   991         int length = joined.length() + 2;
       
   992         wchar_t *temp = new wchar_t[length];
       
   993         joined.toWCharArray(temp);
       
   994         temp[length - 2] = L'\0';
       
   995         temp[length - 1] = L'\0';
       
   996         result = RegSetValueEx(key, reinterpret_cast<const wchar_t*>(value.utf16()), 0,
       
   997                                REG_MULTI_SZ, reinterpret_cast<const BYTE *>(temp),
       
   998                                length * sizeof(wchar_t));
       
   999         delete[] temp;
       
  1000         break;
       
  1001     }
       
  1002     case QVariant::ByteArray: {
       
  1003         QByteArray temp = data.toByteArray();
       
  1004         result = RegSetValueEx(key, reinterpret_cast<const wchar_t*>(value.utf16()), 0,
       
  1005                                REG_BINARY, reinterpret_cast<const BYTE *>(temp.constData()),
       
  1006                                temp.length());
       
  1007         break;
       
  1008     }
       
  1009     default: {
       
  1010         QByteArray temp;
       
  1011         QDataStream stream(&temp, QIODevice::WriteOnly | QIODevice::Truncate);
       
  1012         stream << data;
       
  1013         result = RegSetValueEx(key, reinterpret_cast<const wchar_t*>(value.utf16()), 0,
       
  1014                                REG_NONE, reinterpret_cast<const BYTE *>(temp.constData()),
       
  1015                                temp.length());
       
  1016         break;
       
  1017     }
       
  1018     };
       
  1019 
       
  1020     QString fullPath(rh->path);
       
  1021     if (fullPath != QLatin1String("/"))
       
  1022         fullPath.append(QLatin1Char('/'));
       
  1023 
       
  1024     fullPath.append(value);
       
  1025 
       
  1026     if (!creators[creator].contains(fullPath))
       
  1027         creators[creator].append(fullPath);
       
  1028 
       
  1029     if (createdHandle)
       
  1030         removeHandle(Handle(rh));
       
  1031 
       
  1032     return result == ERROR_SUCCESS;
       
  1033 }
       
  1034 
       
  1035 void RegistryLayer::sync()
       
  1036 {
       
  1037     QMutexLocker locker(&localLock);
       
  1038 
       
  1039     // Wait for change notification callbacks before returning
       
  1040     QEventLoop loop;
       
  1041     connect(this, SIGNAL(handleChanged(quintptr)), &loop, SLOT(quit()));
       
  1042     bool wait = false;
       
  1043 
       
  1044     QList<HKEY> keys = hKeys.values();
       
  1045     while (!keys.isEmpty()) {
       
  1046         HKEY key = keys.takeFirst();
       
  1047 
       
  1048         if (!wait && waitHandles.contains(key))
       
  1049             wait = true;
       
  1050 
       
  1051         RegFlushKey(key);
       
  1052     }
       
  1053 
       
  1054     if (wait) {
       
  1055         locker.unlock();
       
  1056         QTimer::singleShot(1000, &loop, SLOT(quit()));
       
  1057         loop.exec();
       
  1058     }
       
  1059 }
       
  1060 
       
  1061 void RegistryLayer::emitHandleChanged(void *k)
       
  1062 {
       
  1063     QMutexLocker locker(&localLock);
       
  1064 
       
  1065     HKEY key = reinterpret_cast<HKEY>(k);
       
  1066 
       
  1067     QList<RegistryHandle *> changedHandles = hKeys.keys(key);
       
  1068     if (changedHandles.isEmpty()) {
       
  1069         if (waitHandles.contains(key)) {
       
  1070             //QPair<::HANDLE, ::HANDLE> wait = waitHandles.take(key);
       
  1071             HandlePair wait = waitHandles.take(key);
       
  1072 
       
  1073 #ifdef Q_OS_WINCE
       
  1074             notifyThread->removeHandle(wait.first);
       
  1075 #else
       
  1076             UnregisterWait(wait.second);
       
  1077 #endif
       
  1078             CloseHandle(wait.first);
       
  1079             return;
       
  1080         }
       
  1081     }
       
  1082 
       
  1083     while (!changedHandles.isEmpty()) {
       
  1084         RegistryHandle *handle = changedHandles.takeFirst();
       
  1085         emit handleChanged(Handle(handle));
       
  1086 
       
  1087         // Emit signal for handles that this handle is proxying for.
       
  1088         foreach (RegistryHandle *proxied, notifyProxies.values(handle)) {
       
  1089             openRegistryKey(proxied);
       
  1090             if (hKeys.contains(proxied)) {
       
  1091                 notifyProxies.remove(handle, proxied);
       
  1092                 removeHandle(Handle(handle));
       
  1093                 setProperty(Handle(proxied), Publish);
       
  1094 
       
  1095                 emit handleChanged(Handle(proxied));
       
  1096             }
       
  1097         }
       
  1098     }
       
  1099 
       
  1100     if (waitHandles.contains(key)) {
       
  1101         //QPair<::HANDLE, ::HANDLE> wait = waitHandles.take(key);
       
  1102         HandlePair wait = waitHandles.take(key);
       
  1103 
       
  1104         ::HANDLE event = wait.first;
       
  1105 
       
  1106 #ifdef Q_OS_WINCE
       
  1107         notifyThread->removeHandle(event);
       
  1108 #else
       
  1109         UnregisterWait(wait.second);
       
  1110 #endif
       
  1111 
       
  1112 #ifdef Q_OS_WINCE
       
  1113         if (!CeFindNextRegChange(event)) {
       
  1114             long result = GetLastError();
       
  1115             if (result == ERROR_KEY_DELETED) {
       
  1116                 CloseHandle(event);
       
  1117 
       
  1118                 QList<RegistryHandle *> changedHandles = hKeys.keys(key);
       
  1119 
       
  1120                 for (int i = 0; i < changedHandles.count(); ++i)
       
  1121                     hKeys.remove(changedHandles.at(i));
       
  1122 
       
  1123                 RegCloseKey(key);
       
  1124 
       
  1125                 for (int i = 0; i < changedHandles.count(); ++i)
       
  1126                     setProperty(Handle(changedHandles.at(i)), Publish);
       
  1127             } else {
       
  1128                 qDebug() << "CeFindNextRegChange failed with error" << result;
       
  1129             }
       
  1130 
       
  1131             return;
       
  1132         }
       
  1133 
       
  1134         notifyThread->addHandle(event);
       
  1135 
       
  1136         waitHandles.insert(key, QPair<::HANDLE, ::HANDLE>(event, INVALID_HANDLE_VALUE));
       
  1137 #else
       
  1138         long result = RegNotifyChangeKeyValue(key, true, REG_NOTIFY_CHANGE_NAME |
       
  1139                                               REG_NOTIFY_CHANGE_ATTRIBUTES |
       
  1140                                               REG_NOTIFY_CHANGE_LAST_SET,
       
  1141                                               event, true);
       
  1142 
       
  1143         if (result != ERROR_SUCCESS) {
       
  1144             if (result == ERROR_KEY_DELETED || result == ERROR_INVALID_PARAMETER) {
       
  1145                 CloseHandle(event);
       
  1146 
       
  1147                 QList<RegistryHandle *> changedHandles = hKeys.keys(key);
       
  1148 
       
  1149                 for (int i = 0; i < changedHandles.count(); ++i)
       
  1150                     hKeys.remove(changedHandles.at(i));
       
  1151 
       
  1152                 RegCloseKey(key);
       
  1153 
       
  1154                 for (int i = 0; i < changedHandles.count(); ++i)
       
  1155                     setProperty(Handle(changedHandles.at(i)), Publish);
       
  1156             } else {
       
  1157                 qDebug() << "RegNotifyChangeKeyValue failed with error" << result;
       
  1158             }
       
  1159 
       
  1160             return;
       
  1161         }
       
  1162 
       
  1163         ::HANDLE waitHandle;
       
  1164 
       
  1165         if (!RegisterWaitForSingleObject(&waitHandle, event, m_callback, key,
       
  1166                                          INFINITE, WT_EXECUTEDEFAULT)) {
       
  1167             qDebug() << "RegisterWaitForSingleObject failed with error" << GetLastError();
       
  1168             return;
       
  1169         }
       
  1170 
       
  1171         //waitHandles.insert(key, QPair<::HANDLE, ::HANDLE>(event, waitHandle));
       
  1172         waitHandles.insert(key, HandlePair(event, waitHandle));
       
  1173 #endif
       
  1174     }
       
  1175 }
       
  1176 
       
  1177 #ifdef Q_OS_WINCE
       
  1178 void RegistryLayer::eventSignaled(void *handle)
       
  1179 {
       
  1180     QMutexLocker locker(&localLock);
       
  1181 
       
  1182     HKEY key = waitHandles.key(QPair<::HANDLE, ::HANDLE>(handle, INVALID_HANDLE_VALUE), 0);
       
  1183 
       
  1184     if (key != 0)
       
  1185         emitHandleChanged(key);
       
  1186 }
       
  1187 #endif
       
  1188 
       
  1189 void RegistryLayer::openRegistryKey(RegistryHandle *handle)
       
  1190 {
       
  1191     QMutexLocker locker(&localLock);
       
  1192 
       
  1193     if (!handle)
       
  1194         return;
       
  1195 
       
  1196     // Check if HKEY for this handle already exists.
       
  1197     if (hKeys.contains(handle))
       
  1198         return;
       
  1199 
       
  1200     const QString fullPath = qConvertPath(m_basePath + handle->path);
       
  1201 
       
  1202     // Attempt to open registry key path
       
  1203     HKEY key;
       
  1204     long result = RegOpenKeyEx(HKEY_CURRENT_USER,
       
  1205                                 reinterpret_cast<const wchar_t*>(fullPath.utf16()),
       
  1206                                 0, KEY_ALL_ACCESS, &key);
       
  1207 
       
  1208     if (result == ERROR_SUCCESS) {
       
  1209         hKeys.insert(handle, key);
       
  1210     } else if (result == ERROR_FILE_NOT_FOUND) {
       
  1211         // Key for handle does not exist in Registry, check if it is a value handle.
       
  1212         int index = handle->path.lastIndexOf(QLatin1Char('/'), -1);
       
  1213 
       
  1214         const QString parentPath = handle->path.left(index);
       
  1215         const QString valueName = handle->path.mid(index + 1);
       
  1216 
       
  1217         RegistryHandle *parentHandle = registryHandle(item(InvalidHandle, parentPath));
       
  1218         if (!parentHandle)
       
  1219             return;
       
  1220 
       
  1221         openRegistryKey(parentHandle);
       
  1222         if (!hKeys.contains(parentHandle)) {
       
  1223             removeHandle(Handle(parentHandle));
       
  1224             return;
       
  1225         }
       
  1226 
       
  1227         // Check if value exists.
       
  1228         if (!children(Handle(parentHandle)).contains(valueName)) {
       
  1229             removeHandle(Handle(parentHandle));
       
  1230             return;
       
  1231         }
       
  1232 
       
  1233         handle->valueHandle = true;
       
  1234 
       
  1235         hKeys.insert(handle, hKeys.value(parentHandle));
       
  1236 
       
  1237         removeHandle(Handle(parentHandle));
       
  1238     }
       
  1239 }
       
  1240 
       
  1241 bool RegistryLayer::createRegistryKey(RegistryHandle *handle)
       
  1242 {
       
  1243     QMutexLocker locker(&localLock);
       
  1244 
       
  1245     // Check if HKEY for this handle already exists.
       
  1246     if (hKeys.contains(handle))
       
  1247         return false;
       
  1248 
       
  1249     const QString fullPath = qConvertPath(m_basePath + handle->path);
       
  1250 
       
  1251     // Attempt to open registry key path
       
  1252     HKEY key;
       
  1253     DWORD disposition;
       
  1254     long result = RegCreateKeyEx(HKEY_CURRENT_USER,
       
  1255                                 reinterpret_cast<const wchar_t*>(fullPath.utf16()),
       
  1256                                  0, 0,
       
  1257                                  (m_volatileKeys ? REG_OPTION_VOLATILE : REG_OPTION_NON_VOLATILE),
       
  1258                                  KEY_ALL_ACCESS, 0, &key, &disposition);
       
  1259 
       
  1260     if (result == ERROR_SUCCESS)
       
  1261         hKeys.insert(handle, key);
       
  1262 
       
  1263     return disposition == REG_CREATED_NEW_KEY;
       
  1264 }
       
  1265 
       
  1266 bool RegistryLayer::removeSubTree(QValueSpacePublisher *creator, Handle handle)
       
  1267 {
       
  1268     QMutexLocker locker(&localLock);
       
  1269 
       
  1270     RegistryHandle *rh = registryHandle(handle);
       
  1271     if (!rh)
       
  1272         return false;
       
  1273 
       
  1274     QList<QString> paths = creators.value(creator);
       
  1275 
       
  1276     while (!paths.isEmpty()) {
       
  1277         QString item = paths.takeFirst();
       
  1278         if (!item.startsWith(rh->path))
       
  1279             continue;
       
  1280 
       
  1281         removeRegistryValue(0, item);
       
  1282         creators[creator].removeOne(item);
       
  1283 
       
  1284         int index = item.lastIndexOf(QLatin1Char('/'));
       
  1285         if (index == -1)
       
  1286             continue;
       
  1287 
       
  1288         item.truncate(index);
       
  1289         if (!paths.contains(item))
       
  1290             paths.append(item);
       
  1291     }
       
  1292 
       
  1293     pruneEmptyKeys(rh);
       
  1294 
       
  1295     return true;
       
  1296 }
       
  1297 
       
  1298 void RegistryLayer::pruneEmptyKeys(RegistryHandle *handle)
       
  1299 {
       
  1300     QMutexLocker locker(&localLock);
       
  1301 
       
  1302     if (!children(Handle(handle)).isEmpty())
       
  1303         return;
       
  1304 
       
  1305     QString path = handle->path;
       
  1306 
       
  1307     while (path != QLatin1String("/")) {
       
  1308         int index = path.lastIndexOf(QLatin1Char('/'), -1);
       
  1309 
       
  1310         QString value = path.mid(index + 1);
       
  1311 
       
  1312         path.truncate(index);
       
  1313         if (path.isEmpty())
       
  1314             path.append(QLatin1Char('/'));
       
  1315 
       
  1316         RegistryHandle *rh = registryHandle(item(InvalidHandle, path));
       
  1317 
       
  1318         openRegistryKey(rh);
       
  1319         if (!hKeys.contains(rh)) {
       
  1320             removeHandle(Handle(rh));
       
  1321             return;
       
  1322         }
       
  1323 
       
  1324         HKEY key = hKeys.value(rh);
       
  1325 
       
  1326         long result = RegDeleteKey(key, reinterpret_cast<const wchar_t*>(value.utf16()));
       
  1327         if (result == ERROR_SUCCESS) {
       
  1328             QList<QString> paths = handles.keys();
       
  1329             while (!paths.isEmpty()) {
       
  1330                 const QString p = paths.takeFirst();
       
  1331 
       
  1332                 if (p.startsWith(path))
       
  1333                     closeRegistryKey(handles.value(p));
       
  1334             }
       
  1335         } else if (result != ERROR_FILE_NOT_FOUND) {
       
  1336             return;
       
  1337         }
       
  1338 
       
  1339         bool hasChildren = !children(Handle(rh)).isEmpty();
       
  1340 
       
  1341         removeHandle(Handle(rh));
       
  1342 
       
  1343         if (hasChildren)
       
  1344             break;
       
  1345     }
       
  1346 }
       
  1347 
       
  1348 bool RegistryLayer::removeValue(QValueSpacePublisher *creator,
       
  1349                                 Handle handle,
       
  1350                                 const QString &subPath)
       
  1351 {
       
  1352     QMutexLocker locker(&localLock);
       
  1353 
       
  1354     QString fullPath;
       
  1355 
       
  1356     if (handle == InvalidHandle) {
       
  1357         fullPath = subPath;
       
  1358     } else {
       
  1359         RegistryHandle *rh = registryHandle(handle);
       
  1360         if (!rh)
       
  1361             return false;
       
  1362 
       
  1363         if (subPath == QLatin1String("/"))
       
  1364             fullPath = rh->path;
       
  1365         else if (rh->path.endsWith(QLatin1Char('/')) && subPath.startsWith(QLatin1Char('/')))
       
  1366             fullPath = rh->path + subPath.mid(1);
       
  1367         else if (!rh->path.endsWith(QLatin1Char('/')) && !subPath.startsWith(QLatin1Char('/')))
       
  1368             fullPath = rh->path + QLatin1Char('/') + subPath;
       
  1369         else
       
  1370             fullPath = rh->path + subPath;
       
  1371     }
       
  1372 
       
  1373     // permanent layer always removes items even if our records show that creator does not own it.
       
  1374     if (!creators[creator].contains(fullPath) && (layerOptions() & QValueSpace::TransientLayer))
       
  1375         return false;
       
  1376 
       
  1377     removeRegistryValue(0, fullPath);
       
  1378     creators[creator].removeOne(fullPath);
       
  1379 
       
  1380     return true;
       
  1381 }
       
  1382 
       
  1383 void RegistryLayer::addWatch(QValueSpacePublisher *, Handle)
       
  1384 {
       
  1385 }
       
  1386 
       
  1387 void RegistryLayer::removeWatches(QValueSpacePublisher *, Handle)
       
  1388 {
       
  1389 }
       
  1390 
       
  1391 bool RegistryLayer::supportsInterestNotification() const
       
  1392 {
       
  1393     return false;
       
  1394 }
       
  1395 
       
  1396 bool RegistryLayer::notifyInterest(Handle, bool)
       
  1397 {
       
  1398     return false;
       
  1399 }
       
  1400 #include <registrylayer_win.moc>
       
  1401 QTM_END_NAMESPACE
       
  1402 
       
  1403 
       
  1404