Skip to content

Commit

Permalink
Merge pull request #4713 from nextcloud/feature/vfs-windows-thumbnails
Browse files Browse the repository at this point in the history
Feature/vfs windows thumbnails
  • Loading branch information
allexzander authored Jul 29, 2022
2 parents d856e86 + 001deac commit 3383a58
Show file tree
Hide file tree
Showing 34 changed files with 1,367 additions and 18 deletions.
10 changes: 10 additions & 0 deletions NEXTCLOUD.cmake
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,16 @@ if(WIN32)
# MSI Upgrade Code (without brackets)
set( WIN_MSI_UPGRADE_CODE "FD2FCCA9-BB8F-4485-8F70-A0621B84A7F4" )

# CfAPI Shell Extensions
set( CFAPI_SHELL_EXTENSIONS_LIB_NAME CfApiShellExtensions )

set( CFAPI_SHELLEXT_APPID_REG "{E314A650-DCA4-416E-974E-18EA37C213EA}")
set( CFAPI_SHELLEXT_APPID_DISPLAY_NAME "${APPLICATION_NAME} CfApi Shell Extensions" )

set( CFAPI_SHELLEXT_THUMBNAIL_HANDLER_CLASS_ID "6FF9B5B6-389F-444A-9FDD-A286C36EA079" )
set( CFAPI_SHELLEXT_THUMBNAIL_HANDLER_CLASS_ID_REG "{${CFAPI_SHELLEXT_THUMBNAIL_HANDLER_CLASS_ID}}" )
set( CFAPI_SHELLEXT_THUMBNAIL_HANDLER_DISPLAY_NAME "${APPLICATION_NAME} Thumbnail Handler" )

# Windows build options
option( BUILD_WIN_MSI "Build MSI scripts and helper DLL" OFF )
option( BUILD_WIN_TOOLS "Build Win32 migration tools" OFF )
Expand Down
3 changes: 2 additions & 1 deletion admin/win/msi/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ endif()

set(MSI_INSTALLER_FILENAME "${APPLICATION_SHORTNAME}-${VERSION}${VERSION_SUFFIX}-${MSI_BUILD_ARCH}.msi")

configure_file(RegistryCleanup.vbs.in ${CMAKE_CURRENT_BINARY_DIR}/RegistryCleanup.vbs)
configure_file(OEM.wxi.in ${CMAKE_CURRENT_BINARY_DIR}/OEM.wxi)
configure_file(collect-transform.xsl.in ${CMAKE_CURRENT_BINARY_DIR}/collect-transform.xsl)
configure_file(make-msi.bat.in ${CMAKE_CURRENT_BINARY_DIR}/make-msi.bat)
Expand All @@ -26,7 +27,7 @@ install(FILES
${CMAKE_CURRENT_BINARY_DIR}/make-msi.bat
Platform.wxi
Nextcloud.wxs
RegistryCleanup.vbs
${CMAKE_CURRENT_BINARY_DIR}/RegistryCleanup.vbs
RegistryCleanupCustomAction.wxs
gui/banner.bmp
gui/dialog.bmp
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
On Error goto 0

Const HKEY_LOCAL_MACHINE = &H80000002
Const HKEY_CURRENT_USER = &H80000001

Const strObjRegistry = "winmgmts:\\.\root\default:StdRegProv"

Expand Down Expand Up @@ -49,6 +50,25 @@ Function RegistryCleanupSyncRootManager()
End If
End Function

Function RegistryCleanupCfApiShellExtensions()
Set objRegistry = GetObject(strObjRegistry)

strShellExtThumbnailHandlerAppId = "Software\Classes\AppID\@CFAPI_SHELLEXT_APPID_REG@"
strShellExtThumbnailHandlerClsId = "Software\Classes\CLSID\@CFAPI_SHELLEXT_THUMBNAIL_HANDLER_CLASS_ID_REG@"

rootKey = HKEY_CURRENT_USER

If objRegistry.EnumKey(rootKey, strShellExtThumbnailHandlerAppId, arrSubKeys) = 0 Then
RegistryDeleteKeyRecursive rootKey, strShellExtThumbnailHandlerAppId
End If

If objRegistry.EnumKey(rootKey, strShellExtThumbnailHandlerClsId, arrSubKeys) = 0 Then
RegistryDeleteKeyRecursive rootKey, strShellExtThumbnailHandlerClsId
End If

End Function

Function RegistryCleanup()
RegistryCleanupSyncRootManager()
RegistryCleanupCfApiShellExtensions()
End Function
9 changes: 9 additions & 0 deletions config.h.in
Original file line number Diff line number Diff line change
Expand Up @@ -44,4 +44,13 @@

#cmakedefine BUILD_UPDATER "@BUILD_UPDATER@"

#cmakedefine CFAPI_SHELLEXT_APPID_REG "@CFAPI_SHELLEXT_APPID_REG@"
#cmakedefine CFAPI_SHELLEXT_APPID_DISPLAY_NAME "@CFAPI_SHELLEXT_APPID_DISPLAY_NAME@"

#cmakedefine CFAPI_SHELLEXT_THUMBNAIL_HANDLER_CLASS_ID "@CFAPI_SHELLEXT_THUMBNAIL_HANDLER_CLASS_ID@"
#cmakedefine CFAPI_SHELLEXT_THUMBNAIL_HANDLER_CLASS_ID_REG "@CFAPI_SHELLEXT_THUMBNAIL_HANDLER_CLASS_ID_REG@"
#cmakedefine CFAPI_SHELLEXT_THUMBNAIL_HANDLER_DISPLAY_NAME "@CFAPI_SHELLEXT_THUMBNAIL_HANDLER_DISPLAY_NAME@"

#cmakedefine CFAPI_SHELL_EXTENSIONS_LIB_NAME "@CFAPI_SHELL_EXTENSIONS_LIB_NAME@"

#endif
2 changes: 1 addition & 1 deletion src/common/filesystembase.h
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@
#include <QFileInfo>
#include <QLoggingCategory>

#include <ocsynclib.h>
#include <csync/ocsynclib.h>

class QFile;

Expand Down
36 changes: 36 additions & 0 deletions src/common/shellextensionutils.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
#include "shellextensionutils.h"
#include <QJsonDocument>
#include <QLoggingCategory>

namespace VfsShellExtensions {

Q_LOGGING_CATEGORY(lcShellExtensionUtils, "nextcloud.gui.shellextensionutils", QtInfoMsg)

QString VfsShellExtensions::serverNameForApplicationName(const QString &applicationName)
{
return applicationName + QStringLiteral(":VfsShellExtensionsServer");
}

QString VfsShellExtensions::serverNameForApplicationNameDefault()
{
return serverNameForApplicationName(APPLICATION_NAME);
}
namespace Protocol {
QByteArray createJsonMessage(const QVariantMap &message)
{
QVariantMap messageCopy = message;
messageCopy[QStringLiteral("version")] = Version;
return QJsonDocument::fromVariant((messageCopy)).toJson(QJsonDocument::Compact);
}

bool validateProtocolVersion(const QVariantMap &message)
{
const auto valid = message.value(QStringLiteral("version")) == Version;
if (!valid) {
qCWarning(lcShellExtensionUtils) << "Invalid shell extensions IPC protocol: " << message.value(QStringLiteral("version")) << " vs " << Version;
}
Q_ASSERT(valid);
return valid;
}
}
}
35 changes: 35 additions & 0 deletions src/common/shellextensionutils.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
/*
* Copyright (C) by Oleksandr Zolotov <alex@nextcloud.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* for more details.
*/

#pragma once
#include "config.h"
#include <QByteArray>
#include <QString>
#include <QVariantMap>

namespace VfsShellExtensions {
QString serverNameForApplicationName(const QString &applicationName);
QString serverNameForApplicationNameDefault();

namespace Protocol {
static constexpr auto ThumbnailProviderRequestKey = "thumbnailProviderRequest";
static constexpr auto ThumbnailProviderRequestFilePathKey = "filePath";
static constexpr auto ThumbnailProviderRequestFileSizeKey = "fileSize";
static constexpr auto ThumnailProviderDataKey = "thumbnailData";
static constexpr auto Version = "1.0";

QByteArray createJsonMessage(const QVariantMap &message);
bool validateProtocolVersion(const QVariantMap &message);
}
}
3 changes: 2 additions & 1 deletion src/common/utility.h
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@
#define UTILITY_H


#include "ocsynclib.h"
#include "csync/ocsynclib.h"
#include <QString>
#include <QByteArray>
#include <QDateTime>
Expand Down Expand Up @@ -254,6 +254,7 @@ namespace Utility {
OCSYNC_EXPORT bool registryDeleteKeyTree(HKEY hRootKey, const QString &subKey);
OCSYNC_EXPORT bool registryDeleteKeyValue(HKEY hRootKey, const QString &subKey, const QString &valueName);
OCSYNC_EXPORT bool registryWalkSubKeys(HKEY hRootKey, const QString &subKey, const std::function<void(HKEY, const QString &)> &callback);
OCSYNC_EXPORT bool registryWalkValues(HKEY hRootKey, const QString &subKey, const std::function<void(const QString &, bool *)> &callback);
OCSYNC_EXPORT QRect getTaskbarDimensions();

// Possibly refactor to share code with UnixTimevalToFileTime in c_time.c
Expand Down
49 changes: 48 additions & 1 deletion src/common/utility_win.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -28,8 +28,11 @@
#include <winbase.h>
#include <windows.h>
#include <winerror.h>

#include <QCoreApplication>
#include <QDir>
#include <QFile>
#include <QLibrary>
#include <QSettings>

extern Q_CORE_EXPORT int qt_ntfs_permission_lookup;

Expand Down Expand Up @@ -354,6 +357,50 @@ bool Utility::registryWalkSubKeys(HKEY hRootKey, const QString &subKey, const st
return retCode != ERROR_NO_MORE_ITEMS;
}

bool Utility::registryWalkValues(HKEY hRootKey, const QString &subKey, const std::function<void(const QString &, bool *)> &callback)
{
HKEY hKey;
REGSAM sam = KEY_QUERY_VALUE;
LONG result = RegOpenKeyEx(hRootKey, reinterpret_cast<LPCWSTR>(subKey.utf16()), 0, sam, &hKey);
ASSERT(result == ERROR_SUCCESS);
if (result != ERROR_SUCCESS) {
return false;
}

DWORD maxValueNameSize = 0;
result = RegQueryInfoKey(hKey, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, &maxValueNameSize, nullptr, nullptr, nullptr);
ASSERT(result == ERROR_SUCCESS);
if (result != ERROR_SUCCESS) {
RegCloseKey(hKey);
return false;
}

QString valueName;
valueName.reserve(maxValueNameSize + 1);

DWORD retCode = ERROR_SUCCESS;
bool done = false;
for (DWORD i = 0; retCode == ERROR_SUCCESS; ++i) {
Q_ASSERT(unsigned(valueName.capacity()) > maxValueNameSize);
valueName.resize(valueName.capacity());
DWORD valueNameSize = valueName.size();
retCode = RegEnumValue(hKey, i, reinterpret_cast<LPWSTR>(valueName.data()), &valueNameSize, nullptr, nullptr, nullptr, nullptr);

ASSERT(result == ERROR_SUCCESS || retCode == ERROR_NO_MORE_ITEMS);
if (retCode == ERROR_SUCCESS) {
valueName.resize(valueNameSize);
callback(valueName, &done);

if (done) {
break;
}
}
}

RegCloseKey(hKey);
return retCode != ERROR_NO_MORE_ITEMS;
}

DWORD Utility::convertSizeToDWORD(size_t &convertVar)
{
if( convertVar > UINT_MAX ) {
Expand Down
3 changes: 3 additions & 0 deletions src/common/vfs.h
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,9 @@ struct OCSYNC_EXPORT VfsSetupParams
// Folder alias
QString alias;

// Folder registry navigation Pane CLSID
QString navigationPaneClsid;

/** The path to the synced folder on the account
*
* Always ends with /.
Expand Down
2 changes: 1 addition & 1 deletion src/gui/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -291,7 +291,7 @@ IF( NOT WIN32 AND NOT APPLE )
set(client_SRCS ${client_SRCS} folderwatcher_linux.cpp)
ENDIF()
IF( WIN32 )
set(client_SRCS ${client_SRCS} folderwatcher_win.cpp)
set(client_SRCS ${client_SRCS} folderwatcher_win.cpp shellextensionsserver.cpp ${CMAKE_SOURCE_DIR}/src/common/shellextensionutils.cpp)
ENDIF()
IF( APPLE )
list(APPEND client_SRCS folderwatcher_mac.cpp)
Expand Down
4 changes: 4 additions & 0 deletions src/gui/application.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@
#include "accountmanager.h"
#include "creds/abstractcredentials.h"
#include "pushnotifications.h"
#include "shellextensionsserver.h"

#if defined(BUILD_UPDATER)
#include "updater/ocupdater.h"
Expand Down Expand Up @@ -319,6 +320,9 @@ Application::Application(int &argc, char **argv)
qCInfo(lcApplication) << "VFS suffix plugin is available";

_folderManager.reset(new FolderMan);
#ifdef Q_OS_WIN
_shellExtensionsServer.reset(new ShellExtensionsServer);
#endif

connect(this, &SharedTools::QtSingleApplication::messageReceived, this, &Application::slotParseMessage);

Expand Down
4 changes: 4 additions & 0 deletions src/gui/application.h
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,7 @@ Q_DECLARE_LOGGING_CATEGORY(lcApplication)

class Theme;
class Folder;
class ShellExtensionsServer;
class SslErrorDialog;

/**
Expand Down Expand Up @@ -144,6 +145,9 @@ protected slots:
QScopedPointer<CrashReporter::Handler> _crashHandler;
#endif
QScopedPointer<FolderMan> _folderManager;
#ifdef Q_OS_WIN
QScopedPointer<ShellExtensionsServer> _shellExtensionsServer;
#endif
};

} // namespace OCC
Expand Down
1 change: 1 addition & 0 deletions src/gui/folder.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -498,6 +498,7 @@ void Folder::startVfs()
vfsParams.filesystemPath = path();
vfsParams.displayName = shortGuiRemotePathOrAppName();
vfsParams.alias = alias();
vfsParams.navigationPaneClsid = navigationPaneClsid().toString();
vfsParams.remotePath = remotePathTrailingSlash();
vfsParams.account = _accountState->account();
vfsParams.journal = &_journal;
Expand Down
2 changes: 2 additions & 0 deletions src/gui/folderman.h
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@
#include "syncfileitem.h"

class TestFolderMan;
class TestCfApiShellExtensionsIPC;

namespace OCC {

Expand Down Expand Up @@ -362,6 +363,7 @@ private slots:
explicit FolderMan(QObject *parent = nullptr);
friend class OCC::Application;
friend class ::TestFolderMan;
friend class ::TestCfApiShellExtensionsIPC;
};

} // namespace OCC
Expand Down
Loading

0 comments on commit 3383a58

Please sign in to comment.