From: Michael Schuster Date: Tue, 18 Aug 2020 17:11:08 +0000 (+0200) Subject: Windows shell extensions: Rename all files and classes from OC* to NC*, update versio... X-Git-Tag: archive/raspbian/3.16.7-1_deb13u1+rpi1~1^2~12^2~22^2~216^2~3 X-Git-Url: https://dgit.raspbian.org/?a=commitdiff_plain;h=0ba5df597fe707811418a934c73a0c6ded88a90a;p=nextcloud-desktop.git Windows shell extensions: Rename all files and classes from OC* to NC*, update version info This also ensures a clear separation in the system registry. SelfReg is not recommended by Microsoft and will be handled by the MSI package to allow proper Repair and Uninstall. However, we keep it for backward compatibility with the NSIS installer. For details see: https://stackoverflow.com/questions/364187/how-do-you-register-a-win32-com-dll-file-in-wix-3#364210 https://docs.microsoft.com/en-us/windows/win32/msi/selfreg-table#remarks Another fix by this commit: The "Version" registry value in the NCOverlays self reg should be a key and not a value. Details: https://wixtoolset.org/documentation/manual/v3/xsd/wix/class.html Example: [HKCR\CLSID\{01234567-89AB-CDEF-0123-456789ABCDEF}\Version] @="1.0.0.0" Signed-off-by: Michael Schuster --- diff --git a/shell_integration/windows/CMakeLists.txt b/shell_integration/windows/CMakeLists.txt index 068c8b1d1..a350b09d6 100644 --- a/shell_integration/windows/CMakeLists.txt +++ b/shell_integration/windows/CMakeLists.txt @@ -9,7 +9,7 @@ include_directories( configure_file(WinShellExtConstants.h.in ${CMAKE_CURRENT_BINARY_DIR}/WinShellExtConstants.h) configure_file(WinShellExtConstants.wxi.in ${CMAKE_CURRENT_BINARY_DIR}/WinShellExtConstants.wxi) -add_subdirectory(OCContextMenu) -add_subdirectory(OCOverlays) -add_subdirectory(OCUtil) +add_subdirectory(NCContextMenu) +add_subdirectory(NCOverlays) +add_subdirectory(NCUtil) diff --git a/shell_integration/windows/NCContextMenu/CMakeLists.txt b/shell_integration/windows/NCContextMenu/CMakeLists.txt new file mode 100644 index 000000000..f8f9dc324 --- /dev/null +++ b/shell_integration/windows/NCContextMenu/CMakeLists.txt @@ -0,0 +1,17 @@ +add_library(NCContextMenu MODULE + dllmain.cpp + NCClientInterface.cpp + NCContextMenu.cpp + NCContextMenuFactory.cpp + NCContextMenuRegHandler.cpp + NCContextMenu.rc + NCContextMenu.def +) + +target_link_libraries(NCContextMenu + NCUtil) + +install(TARGETS NCContextMenu + RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR} + LIBRARY DESTINATION ${CMAKE_INSTALL_BINDIR} +) diff --git a/shell_integration/windows/NCContextMenu/NCClientInterface.cpp b/shell_integration/windows/NCContextMenu/NCClientInterface.cpp new file mode 100644 index 000000000..6db4a27c9 --- /dev/null +++ b/shell_integration/windows/NCContextMenu/NCClientInterface.cpp @@ -0,0 +1,93 @@ +/** +* Copyright (c) 2015 Daniel Molkentin . All rights reserved. +* +* This library is free software; you can redistribute it and/or modify it under +* the terms of the GNU Lesser General Public License as published by the Free +* Software Foundation; either version 2.1 of the License, or (at your option) +* any later version. +* +* This library 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 Lesser General Public License for more +* details. +*/ + +#include "NCClientInterface.h" + +#include "CommunicationSocket.h" +#include "StringUtil.h" + +#include + +#include + +#include +#include +#include +#include +#include + +using namespace std; + +#define PIPE_TIMEOUT 5*1000 //ms + +NCClientInterface::ContextMenuInfo NCClientInterface::FetchInfo(const std::wstring &files) +{ + auto pipename = CommunicationSocket::DefaultPipePath(); + + CommunicationSocket socket; + if (!WaitNamedPipe(pipename.data(), PIPE_TIMEOUT)) { + return {}; + } + if (!socket.Connect(pipename)) { + return {}; + } + socket.SendMsg(L"GET_STRINGS:CONTEXT_MENU_TITLE\n"); + socket.SendMsg((L"GET_MENU_ITEMS:" + files + L"\n").data()); + + ContextMenuInfo info; + std::wstring response; + int sleptCount = 0; + while (sleptCount < 5) { + if (socket.ReadLine(&response)) { + if (StringUtil::begins_with(response, wstring(L"REGISTER_PATH:"))) { + wstring responsePath = response.substr(14); // length of REGISTER_PATH + info.watchedDirectories.push_back(responsePath); + } + else if (StringUtil::begins_with(response, wstring(L"STRING:"))) { + wstring stringName, stringValue; + if (!StringUtil::extractChunks(response, stringName, stringValue)) + continue; + if (stringName == L"CONTEXT_MENU_TITLE") + info.contextMenuTitle = move(stringValue); + } else if (StringUtil::begins_with(response, wstring(L"MENU_ITEM:"))) { + wstring commandName, flags, title; + if (!StringUtil::extractChunks(response, commandName, flags, title)) + continue; + info.menuItems.push_back({ commandName, flags, title }); + } else if (StringUtil::begins_with(response, wstring(L"GET_MENU_ITEMS:END"))) { + break; // Stop once we completely received the last sent request + } + } + else { + Sleep(50); + ++sleptCount; + } + } + return info; +} + +void NCClientInterface::SendRequest(const wchar_t *verb, const std::wstring &path) +{ + auto pipename = CommunicationSocket::DefaultPipePath(); + + CommunicationSocket socket; + if (!WaitNamedPipe(pipename.data(), PIPE_TIMEOUT)) { + return; + } + if (!socket.Connect(pipename)) { + return; + } + + socket.SendMsg((verb + (L":" + path + L"\n")).data()); +} diff --git a/shell_integration/windows/NCContextMenu/NCClientInterface.h b/shell_integration/windows/NCContextMenu/NCClientInterface.h new file mode 100644 index 000000000..a76cab5af --- /dev/null +++ b/shell_integration/windows/NCContextMenu/NCClientInterface.h @@ -0,0 +1,59 @@ +/** +* Copyright (c) 2015 ownCloud GmbH. All rights reserved. +* +* This library is free software; you can redistribute it and/or modify it under +* the terms of the GNU Lesser General Public License as published by the Free +* Software Foundation; version 2.1 of the License +* +* This library 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 Lesser General Public License for more +* details. +*/ + +/** +* Copyright (c) 2014 ownCloud GmbH. All rights reserved. +* +* This library is free software; you can redistribute it and/or modify it under +* the terms of the GNU Lesser General Public License as published by the Free +* Software Foundation; version 2.1 of the License +* +* This library 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 Lesser General Public License for more +* details. +*/ + +#ifndef AbstractSocketHandler_H +#define AbstractSocketHandler_H + +#pragma once + +#include +#include +#include +#include +#include +#include +#include +#include + +class CommunicationSocket; + +class NCClientInterface +{ +public: + struct ContextMenuInfo { + std::vector watchedDirectories; + std::wstring contextMenuTitle; + struct MenuItem + { + std::wstring command, flags, title; + }; + std::vector menuItems; + }; + static ContextMenuInfo FetchInfo(const std::wstring &files); + static void SendRequest(const wchar_t *verb, const std::wstring &path); +}; + +#endif //ABSTRACTSOCKETHANDLER_H diff --git a/shell_integration/windows/NCContextMenu/NCContextMenu.cpp b/shell_integration/windows/NCContextMenu/NCContextMenu.cpp new file mode 100644 index 000000000..683376d2c --- /dev/null +++ b/shell_integration/windows/NCContextMenu/NCContextMenu.cpp @@ -0,0 +1,232 @@ +/** +* Copyright (c) 2015 Daniel Molkentin . All rights reserved. +* +* This library is free software; you can redistribute it and/or modify it under +* the terms of the GNU Lesser General Public License as published by the Free +* Software Foundation; either version 2.1 of the License, or (at your option) +* any later version. +* +* This library 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 Lesser General Public License for more +* details. +*/ + +#include "NCContextMenu.h" +#include "NCClientInterface.h" + +#include +#include +#include +#include +#include + +extern long g_cDllRef; + +NCContextMenu::NCContextMenu(void) + : m_cRef(1) +{ + InterlockedIncrement(&g_cDllRef); +} + +NCContextMenu::~NCContextMenu(void) +{ + InterlockedDecrement(&g_cDllRef); +} + +#pragma region IUnknown + +// Query to the interface the component supported. +IFACEMETHODIMP NCContextMenu::QueryInterface(REFIID riid, void **ppv) +{ + static const QITAB qit[] = + { + QITABENT(NCContextMenu, IContextMenu), + QITABENT(NCContextMenu, IShellExtInit), + { 0 }, + }; + return QISearch(this, qit, riid, ppv); +} + +// Increase the reference count for an interface on an object. +IFACEMETHODIMP_(ULONG) NCContextMenu::AddRef() +{ + return InterlockedIncrement(&m_cRef); +} + +// Decrease the reference count for an interface on an object. +IFACEMETHODIMP_(ULONG) NCContextMenu::Release() +{ + ULONG cRef = InterlockedDecrement(&m_cRef); + if (0 == cRef) { + delete this; + } + + return cRef; +} + +#pragma endregion + + +#pragma region IShellExtInit + +// Initialize the context menu handler. +IFACEMETHODIMP NCContextMenu::Initialize( + LPCITEMIDLIST pidlFolder, LPDATAOBJECT pDataObj, HKEY hKeyProgID) +{ + m_selectedFiles.clear(); + + if (!pDataObj) { + return E_INVALIDARG; + } + + FORMATETC fe = { CF_HDROP, nullptr, DVASPECT_CONTENT, -1, TYMED_HGLOBAL }; + STGMEDIUM stm; + + if (SUCCEEDED(pDataObj->GetData(&fe, &stm))) { + // Get an HDROP handle. + HDROP hDrop = static_cast(GlobalLock(stm.hGlobal)); + if (hDrop) { + UINT nFiles = DragQueryFile(hDrop, 0xFFFFFFFF, nullptr, 0); + for (UINT i = 0; i < nFiles; ++i) { + // Get the path of the file. + wchar_t buffer[MAX_PATH]; + + if (!DragQueryFile(hDrop, i, buffer, ARRAYSIZE(buffer))) { + m_selectedFiles.clear(); + break; + } + + if (i) + m_selectedFiles += L'\x1e'; + m_selectedFiles += buffer; + } + + GlobalUnlock(stm.hGlobal); + } + + ReleaseStgMedium(&stm); + } + + // If any value other than S_OK is returned from the method, the context + // menu item is not displayed. + return m_selectedFiles.empty() ? E_FAIL : S_OK; +} + +#pragma endregion + + +#pragma region IContextMenu + +void InsertSeperator(HMENU hMenu, UINT indexMenu) +{ + // Add a separator. + MENUITEMINFO sep = { sizeof(sep) }; + sep.fMask = MIIM_TYPE; + sep.fType = MFT_SEPARATOR; + InsertMenuItem(hMenu, indexMenu, TRUE, &sep); +} + +IFACEMETHODIMP NCContextMenu::QueryContextMenu(HMENU hMenu, UINT indexMenu, UINT idCmdFirst, UINT idCmdLast, UINT uFlags) +{ + // If uFlags include CMF_DEFAULTONLY then we should not do anything. + if (CMF_DEFAULTONLY & uFlags) + { + return MAKE_HRESULT(SEVERITY_SUCCESS, 0, USHORT(0)); + } + + m_info = NCClientInterface::FetchInfo(m_selectedFiles); + if (m_info.menuItems.empty()) { + return MAKE_HRESULT(SEVERITY_SUCCESS, 0, USHORT(0)); + } + + InsertSeperator(hMenu, indexMenu++); + + HMENU hSubmenu = CreateMenu(); + { + MENUITEMINFO mii = { sizeof(mii) }; + mii.fMask = MIIM_SUBMENU | MIIM_FTYPE | MIIM_STRING; + mii.hSubMenu = hSubmenu; + mii.fType = MFT_STRING; + mii.dwTypeData = &m_info.contextMenuTitle[0]; + + if (!InsertMenuItem(hMenu, indexMenu++, TRUE, &mii)) + return HRESULT_FROM_WIN32(GetLastError()); + } + InsertSeperator(hMenu, indexMenu++); + + UINT indexSubMenu = 0; + for (auto &item : m_info.menuItems) { + bool disabled = item.flags.find(L'd') != std::string::npos; + + MENUITEMINFO mii = { sizeof(mii) }; + mii.fMask = MIIM_ID | MIIM_FTYPE | MIIM_STRING | MIIM_STATE; + mii.wID = idCmdFirst + indexSubMenu; + mii.fType = MFT_STRING; + mii.dwTypeData = &item.title[0]; + mii.fState = disabled ? MFS_DISABLED : MFS_ENABLED; + + if (!InsertMenuItem(hSubmenu, indexSubMenu, true, &mii)) + return HRESULT_FROM_WIN32(GetLastError()); + indexSubMenu++; + } + + // Return an HRESULT value with the severity set to SEVERITY_SUCCESS. + // Set the code value to the offset of the largest command identifier + // that was assigned, plus one (1). + return MAKE_HRESULT(SEVERITY_SUCCESS, 0, USHORT(indexSubMenu)); +} + +IFACEMETHODIMP NCContextMenu::InvokeCommand(LPCMINVOKECOMMANDINFO pici) +{ + std::wstring command; + + CMINVOKECOMMANDINFOEX *piciEx = nullptr; + if (pici->cbSize == sizeof(CMINVOKECOMMANDINFOEX)) + piciEx = (CMINVOKECOMMANDINFOEX*)pici; + + // For the Unicode case, if the high-order word is not zero, the + // command's verb string is in lpcmi->lpVerbW. + if (piciEx + && (piciEx->fMask & CMIC_MASK_UNICODE) + && HIWORD(((CMINVOKECOMMANDINFOEX*)pici)->lpVerbW)) { + + command = piciEx->lpVerbW; + + // Verify that we handle the verb + bool handled = false; + for (auto &item : m_info.menuItems) { + if (item.command == command) { + handled = true; + break; + } + } + if (!handled) + return E_FAIL; + } else if (IS_INTRESOURCE(pici->lpVerb)) { + // If the command cannot be identified through the verb string, then + // check the identifier offset. + auto offset = LOWORD(pici->lpVerb); + if (offset >= m_info.menuItems.size()) + return E_FAIL; + + command = m_info.menuItems[offset].command; + } else { + return E_FAIL; + } + + NCClientInterface::SendRequest(command.data(), m_selectedFiles); + return S_OK; +} + +IFACEMETHODIMP NCContextMenu::GetCommandString(UINT_PTR idCommand, + UINT uFlags, UINT *pwReserved, LPSTR pszName, UINT cchMax) +{ + if (idCommand < m_info.menuItems.size() && uFlags == GCS_VERBW) { + return StringCchCopyW(reinterpret_cast(pszName), cchMax, + m_info.menuItems[idCommand].command.data()); + } + return E_INVALIDARG; +} + +#pragma endregion diff --git a/shell_integration/windows/NCContextMenu/NCContextMenu.def b/shell_integration/windows/NCContextMenu/NCContextMenu.def new file mode 100644 index 000000000..8cde2bd02 --- /dev/null +++ b/shell_integration/windows/NCContextMenu/NCContextMenu.def @@ -0,0 +1,6 @@ +LIBRARY +EXPORTS + DllGetClassObject PRIVATE + DllCanUnloadNow PRIVATE + DllRegisterServer PRIVATE + DllUnregisterServer PRIVATE \ No newline at end of file diff --git a/shell_integration/windows/NCContextMenu/NCContextMenu.h b/shell_integration/windows/NCContextMenu/NCContextMenu.h new file mode 100644 index 000000000..b5b2a3eb7 --- /dev/null +++ b/shell_integration/windows/NCContextMenu/NCContextMenu.h @@ -0,0 +1,53 @@ +/** +* Copyright (c) 2015 Daniel Molkentin . All rights reserved. +* +* This library is free software; you can redistribute it and/or modify it under +* the terms of the GNU Lesser General Public License as published by the Free +* Software Foundation; either version 2.1 of the License, or (at your option) +* any later version. +* +* This library 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 Lesser General Public License for more +* details. +*/ + +#ifndef NCCONTEXTMENU_H +#define NCCONTEXTMENU_H + +#pragma once +#include // For IShellExtInit and IContextMenu +#include +#include "NCClientInterface.h" + +class NCContextMenu : public IShellExtInit, public IContextMenu +{ +public: + // IUnknown + IFACEMETHODIMP QueryInterface(REFIID riid, void **ppv); + IFACEMETHODIMP_(ULONG) AddRef(); + IFACEMETHODIMP_(ULONG) Release(); + + // IShellExtInit + IFACEMETHODIMP Initialize(LPCITEMIDLIST pidlFolder, LPDATAOBJECT pDataObj, HKEY hKeyProgID); + + // IContextMenu + IFACEMETHODIMP QueryContextMenu(HMENU hMenu, UINT indexMenu, UINT idCmdFirst, UINT idCmdLast, UINT uFlags); + IFACEMETHODIMP InvokeCommand(LPCMINVOKECOMMANDINFO pici); + IFACEMETHODIMP GetCommandString(UINT_PTR idCommand, UINT uFlags, UINT *pwReserved, LPSTR pszName, UINT cchMax); + + NCContextMenu(); + +protected: + ~NCContextMenu(); + +private: + // Reference count of component. + long m_cRef; + + // The name of the selected files (separated by '\x1e') + std::wstring m_selectedFiles; + NCClientInterface::ContextMenuInfo m_info; +}; + +#endif //NCCONTEXTMENU_H diff --git a/shell_integration/windows/NCContextMenu/NCContextMenu.rc b/shell_integration/windows/NCContextMenu/NCContextMenu.rc new file mode 100644 index 000000000..ea3f44b20 Binary files /dev/null and b/shell_integration/windows/NCContextMenu/NCContextMenu.rc differ diff --git a/shell_integration/windows/NCContextMenu/NCContextMenuFactory.cpp b/shell_integration/windows/NCContextMenu/NCContextMenuFactory.cpp new file mode 100644 index 000000000..8d1e1b65d --- /dev/null +++ b/shell_integration/windows/NCContextMenu/NCContextMenuFactory.cpp @@ -0,0 +1,89 @@ +/** +* Copyright (c) 2015 Daniel Molkentin . All rights reserved. +* +* This library is free software; you can redistribute it and/or modify it under +* the terms of the GNU Lesser General Public License as published by the Free +* Software Foundation; either version 2.1 of the License, or (at your option) +* any later version. +* +* This library 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 Lesser General Public License for more +* details. +*/ + +#include "NCContextMenuFactory.h" +#include "NCContextMenu.h" +#include +#include +#pragma comment(lib, "shlwapi.lib") + + +extern long g_cDllRef; + + +NCContextMenuFactory::NCContextMenuFactory() : m_cRef(1) +{ + InterlockedIncrement(&g_cDllRef); +} + +NCContextMenuFactory::~NCContextMenuFactory() +{ + InterlockedDecrement(&g_cDllRef); +} + + +// IUnknown methods + +IFACEMETHODIMP NCContextMenuFactory::QueryInterface(REFIID riid, void **ppv) +{ + static const QITAB qit[] = { QITABENT(NCContextMenuFactory, IClassFactory), { 0 }, }; + return QISearch(this, qit, riid, ppv); +} + +IFACEMETHODIMP_(ULONG) NCContextMenuFactory::AddRef() +{ + return InterlockedIncrement(&m_cRef); +} + +IFACEMETHODIMP_(ULONG) NCContextMenuFactory::Release() +{ + ULONG cRef = InterlockedDecrement(&m_cRef); + if (0 == cRef) { + delete this; + } + return cRef; +} + + +// IClassFactory methods + +IFACEMETHODIMP NCContextMenuFactory::CreateInstance(IUnknown *pUnkOuter, REFIID riid, void **ppv) +{ + HRESULT hr = CLASS_E_NOAGGREGATION; + + // pUnkOuter is used for aggregation. We do not support it in the sample. + if (!pUnkOuter) { + hr = E_OUTOFMEMORY; + + // Create the COM component. + NCContextMenu *pExt = new (std::nothrow) NCContextMenu(); + if (pExt) { + // Query the specified interface. + hr = pExt->QueryInterface(riid, ppv); + pExt->Release(); + } + } + + return hr; +} + +IFACEMETHODIMP NCContextMenuFactory::LockServer(BOOL fLock) +{ + if (fLock) { + InterlockedIncrement(&g_cDllRef); + } else { + InterlockedDecrement(&g_cDllRef); + } + return S_OK; +} diff --git a/shell_integration/windows/NCContextMenu/NCContextMenuFactory.h b/shell_integration/windows/NCContextMenu/NCContextMenuFactory.h new file mode 100644 index 000000000..4f878ab46 --- /dev/null +++ b/shell_integration/windows/NCContextMenu/NCContextMenuFactory.h @@ -0,0 +1,42 @@ +/** +* Copyright (c) 2015 Daniel Molkentin . All rights reserved. +* +* This library is free software; you can redistribute it and/or modify it under +* the terms of the GNU Lesser General Public License as published by the Free +* Software Foundation; either version 2.1 of the License, or (at your option) +* any later version. +* +* This library 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 Lesser General Public License for more +* details. +*/ + + +#ifndef NCCONTEXTMENUFACTORY_H +#define NCCONTEXTMENUFACTORY_H + +#pragma once + +#include // For IClassFactory + +class NCContextMenuFactory : public IClassFactory +{ +public: + // IUnknown + IFACEMETHODIMP QueryInterface(REFIID riid, void **ppv); + IFACEMETHODIMP_(ULONG) AddRef(); + IFACEMETHODIMP_(ULONG) Release(); + + // IClassFactory + IFACEMETHODIMP CreateInstance(IUnknown *pUnkOuter, REFIID riid, void **ppv); + IFACEMETHODIMP LockServer(BOOL fLock); + + NCContextMenuFactory(); + +private: + ~NCContextMenuFactory(); + long m_cRef; +}; + +#endif //NCCONTEXTMENUFACTORY_H \ No newline at end of file diff --git a/shell_integration/windows/NCContextMenu/NCContextMenuRegHandler.cpp b/shell_integration/windows/NCContextMenu/NCContextMenuRegHandler.cpp new file mode 100644 index 000000000..37865b89a --- /dev/null +++ b/shell_integration/windows/NCContextMenu/NCContextMenuRegHandler.cpp @@ -0,0 +1,216 @@ +/** +* Copyright (c) 2015 Daniel Molkentin . All rights reserved. +* +* This library is free software; you can redistribute it and/or modify it under +* the terms of the GNU Lesser General Public License as published by the Free +* Software Foundation; either version 2.1 of the License, or (at your option) +* any later version. +* +* This library 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 Lesser General Public License for more +* details. +*/ + +#include "NCContextMenuRegHandler.h" +#include "RegDelnode.h" +#include +#include + +namespace { + +HRESULT SetHKCRRegistryKeyAndValue(PCWSTR pszSubKey, PCWSTR pszValueName, PCWSTR pszData) +{ + HRESULT hr; + HKEY hKey = nullptr; + + // Creates the specified registry key. If the key already exists, the + // function opens it. + hr = HRESULT_FROM_WIN32(RegCreateKeyEx(HKEY_CLASSES_ROOT, pszSubKey, 0, + nullptr, REG_OPTION_NON_VOLATILE, KEY_WRITE, nullptr, &hKey, nullptr)); + + if (SUCCEEDED(hr)) + { + if (pszData) + { + // Set the specified value of the key. + DWORD cbData = lstrlen(pszData) * sizeof(*pszData); + hr = HRESULT_FROM_WIN32(RegSetValueEx(hKey, pszValueName, 0, + REG_SZ, reinterpret_cast(pszData), cbData)); + } + + RegCloseKey(hKey); + } + + return hr; +} + +HRESULT GetHKCRRegistryKeyAndValue(PCWSTR pszSubKey, PCWSTR pszValueName, PWSTR pszData, DWORD cbData) +{ + HRESULT hr; + HKEY hKey = nullptr; + + // Try to open the specified registry key. + hr = HRESULT_FROM_WIN32(RegOpenKeyEx(HKEY_CLASSES_ROOT, pszSubKey, 0, + KEY_READ, &hKey)); + + if (SUCCEEDED(hr)) + { + // Get the data for the specified value name. + hr = HRESULT_FROM_WIN32(RegQueryValueEx(hKey, pszValueName, nullptr, + nullptr, reinterpret_cast(pszData), &cbData)); + + RegCloseKey(hKey); + } + + return hr; +} + +} + +HRESULT NCContextMenuRegHandler::RegisterInprocServer(PCWSTR pszModule, const CLSID& clsid, PCWSTR pszFriendlyName, PCWSTR pszThreadModel) +{ + if (!pszModule || !pszThreadModel) + { + return E_INVALIDARG; + } + + HRESULT hr; + + wchar_t szCLSID[MAX_PATH]; + StringFromGUID2(clsid, szCLSID, ARRAYSIZE(szCLSID)); + + wchar_t szSubkey[MAX_PATH]; + + // Create the HKCR\CLSID\{} key. + hr = StringCchPrintf(szSubkey, ARRAYSIZE(szSubkey), LR"(CLSID\%s)", szCLSID); + if (SUCCEEDED(hr)) + { + hr = SetHKCRRegistryKeyAndValue(szSubkey, nullptr, pszFriendlyName); + + // Create the HKCR\CLSID\{}\InprocServer32 key. + if (SUCCEEDED(hr)) + { + hr = StringCchPrintf(szSubkey, ARRAYSIZE(szSubkey), + LR"(CLSID\%s\InprocServer32)", szCLSID); + if (SUCCEEDED(hr)) + { + // Set the default value of the InprocServer32 key to the + // path of the COM module. + hr = SetHKCRRegistryKeyAndValue(szSubkey, nullptr, pszModule); + if (SUCCEEDED(hr)) + { + // Set the threading model of the component. + hr = SetHKCRRegistryKeyAndValue(szSubkey, + L"ThreadingModel", pszThreadModel); + } + } + } + } + + return hr; +} + +HRESULT NCContextMenuRegHandler::UnregisterInprocServer(const CLSID& clsid) +{ + HRESULT hr = S_OK; + + wchar_t szCLSID[MAX_PATH]; + StringFromGUID2(clsid, szCLSID, ARRAYSIZE(szCLSID)); + + wchar_t szSubkey[MAX_PATH]; + + // Delete the HKCR\CLSID\{} key. + hr = StringCchPrintf(szSubkey, ARRAYSIZE(szSubkey), LR"(CLSID\%s)", szCLSID); + if (SUCCEEDED(hr)) + { + hr = HRESULT_FROM_WIN32(RegDelnode(HKEY_CLASSES_ROOT, szSubkey)); + } + + return hr; +} + + +HRESULT NCContextMenuRegHandler::RegisterShellExtContextMenuHandler( + PCWSTR pszFileType, const CLSID& clsid, PCWSTR pszFriendlyName) +{ + if (!pszFileType) + { + return E_INVALIDARG; + } + + HRESULT hr; + + wchar_t szCLSID[MAX_PATH]; + StringFromGUID2(clsid, szCLSID, ARRAYSIZE(szCLSID)); + + wchar_t szSubkey[MAX_PATH]; + + // If pszFileType starts with '.', try to read the default value of the + // HKCR\ key which contains the ProgID to which the file type + // is linked. + if (*pszFileType == L'.') + { + wchar_t szDefaultVal[260]; + hr = GetHKCRRegistryKeyAndValue(pszFileType, nullptr, szDefaultVal, + sizeof(szDefaultVal)); + + // If the key exists and its default value is not empty, use the + // ProgID as the file type. + if (SUCCEEDED(hr) && szDefaultVal[0] != L'\0') + { + pszFileType = szDefaultVal; + } + } + + // Create the key HKCR\\shellex\ContextMenuHandlers\{friendlyName>} + hr = StringCchPrintf(szSubkey, ARRAYSIZE(szSubkey), + LR"(%s\shellex\ContextMenuHandlers\%s)", pszFileType, pszFriendlyName); + if (SUCCEEDED(hr)) + { + // Set the default value of the key. + hr = SetHKCRRegistryKeyAndValue(szSubkey, nullptr, szCLSID); + } + + return hr; +} + +HRESULT NCContextMenuRegHandler::UnregisterShellExtContextMenuHandler( + PCWSTR pszFileType, PCWSTR pszFriendlyName) +{ + if (!pszFileType) + { + return E_INVALIDARG; + } + + HRESULT hr; + + wchar_t szSubkey[MAX_PATH]; + + // If pszFileType starts with '.', try to read the default value of the + // HKCR\ key which contains the ProgID to which the file type + // is linked. + if (*pszFileType == L'.') + { + wchar_t szDefaultVal[260]; + hr = GetHKCRRegistryKeyAndValue(pszFileType, nullptr, szDefaultVal, + sizeof(szDefaultVal)); + + // If the key exists and its default value is not empty, use the + // ProgID as the file type. + if (SUCCEEDED(hr) && szDefaultVal[0] != L'\0') + { + pszFileType = szDefaultVal; + } + } + + // Remove the HKCR\\shellex\ContextMenuHandlers\{friendlyName} key. + hr = StringCchPrintf(szSubkey, ARRAYSIZE(szSubkey), + LR"(%s\shellex\ContextMenuHandlers\%s)", pszFileType, pszFriendlyName); + if (SUCCEEDED(hr)) + { + hr = HRESULT_FROM_WIN32(RegDelnode(HKEY_CLASSES_ROOT, szSubkey)); + } + + return hr; +} diff --git a/shell_integration/windows/NCContextMenu/NCContextMenuRegHandler.h b/shell_integration/windows/NCContextMenu/NCContextMenuRegHandler.h new file mode 100644 index 000000000..2dba0fd52 --- /dev/null +++ b/shell_integration/windows/NCContextMenu/NCContextMenuRegHandler.h @@ -0,0 +1,38 @@ +/** +* Copyright (c) 2015 Daniel Molkentin . All rights reserved. +* +* This library is free software; you can redistribute it and/or modify it under +* the terms of the GNU Lesser General Public License as published by the Free +* Software Foundation; either version 2.1 of the License, or (at your option) +* any later version. +* +* This library 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 Lesser General Public License for more +* details. +*/ + + +#ifndef NCCONTEXTMENUREGHANDLER_H +#define NCCONTEXTMENUREGHANDLER_H + +#pragma once + +#include + +class __declspec(dllexport) NCContextMenuRegHandler +{ +public: + static HRESULT MakeRegistryEntries(const CLSID& clsid, PCWSTR fileType); + static HRESULT RegisterCOMObject(PCWSTR modulePath, PCWSTR friendlyName, const CLSID& clsid); + static HRESULT RemoveRegistryEntries(PCWSTR friendlyName); + static HRESULT UnregisterCOMObject(const CLSID& clsid); + + static HRESULT RegisterInprocServer(PCWSTR pszModule, const CLSID& clsid, PCWSTR pszFriendlyName, PCWSTR pszThreadModel); + static HRESULT UnregisterInprocServer(const CLSID& clsid); + + static HRESULT RegisterShellExtContextMenuHandler(PCWSTR pszFileType, const CLSID& clsid, PCWSTR pszFriendlyName); + static HRESULT UnregisterShellExtContextMenuHandler(PCWSTR pszFileType, PCWSTR pszFriendlyName); +}; + +#endif //NCCONTEXTMENUREGHANDLER_H \ No newline at end of file diff --git a/shell_integration/windows/NCContextMenu/RegDelnode.h b/shell_integration/windows/NCContextMenu/RegDelnode.h new file mode 100644 index 000000000..f79d1dcca --- /dev/null +++ b/shell_integration/windows/NCContextMenu/RegDelnode.h @@ -0,0 +1,114 @@ +#pragma once + +#include +#include +#include + +// Stolen from the "Deleting a Key with Subkeys" example to replace +// RegDeleteTree which isn't available on WinXP. +// https://msdn.microsoft.com/en-us/library/ms724235(VS.85).aspx + +//************************************************************* +// +// RegDelnodeRecurse() +// +// Purpose: Deletes a registry key and all its subkeys / values. +// +// Parameters: hKeyRoot - Root key +// lpSubKey - SubKey to delete +// +// Return: TRUE if successful. +// FALSE if an error occurs. +// +//************************************************************* + +HRESULT RegDelnodeRecurse(HKEY hKeyRoot, LPTSTR lpSubKey) +{ + LPTSTR lpEnd; + LONG lResult; + DWORD dwSize; + TCHAR szName[MAX_PATH]; + HKEY hKey; + FILETIME ftWrite; + + // First, see if we can delete the key without having + // to recurse. + + lResult = RegDeleteKey(hKeyRoot, lpSubKey); + + if (lResult == ERROR_SUCCESS) + return lResult; + + lResult = RegOpenKeyEx(hKeyRoot, lpSubKey, 0, KEY_READ, &hKey); + + if (lResult != ERROR_SUCCESS) + return lResult; + + // Check for an ending slash and add one if it is missing. + + lpEnd = lpSubKey + lstrlen(lpSubKey); + + if (*(lpEnd - 1) != TEXT('\\')) + { + *lpEnd = TEXT('\\'); + lpEnd++; + *lpEnd = TEXT('\0'); + } + + // Enumerate the keys + + dwSize = MAX_PATH; + lResult = RegEnumKeyEx(hKey, 0, szName, &dwSize, nullptr, + nullptr, nullptr, &ftWrite); + + if (lResult == ERROR_SUCCESS) + { + do { + + StringCchCopy(lpEnd, MAX_PATH * 2, szName); + + if (RegDelnodeRecurse(hKeyRoot, lpSubKey) != ERROR_SUCCESS) { + break; + } + + dwSize = MAX_PATH; + + lResult = RegEnumKeyEx(hKey, 0, szName, &dwSize, nullptr, + nullptr, nullptr, &ftWrite); + + } while (lResult == ERROR_SUCCESS); + } + + lpEnd--; + *lpEnd = TEXT('\0'); + + RegCloseKey(hKey); + + // Try again to delete the key. + + lResult = RegDeleteKey(hKeyRoot, lpSubKey); + return lResult; +} + +//************************************************************* +// +// RegDelnode() +// +// Purpose: Deletes a registry key and all its subkeys / values. +// +// Parameters: hKeyRoot - Root key +// lpSubKey - SubKey to delete +// +// Return: TRUE if successful. +// FALSE if an error occurs. +// +//************************************************************* + +HRESULT RegDelnode(HKEY hKeyRoot, LPTSTR lpSubKey) +{ + TCHAR szDelKey[MAX_PATH * 2]; + + StringCchCopy(szDelKey, MAX_PATH * 2, lpSubKey); + return RegDelnodeRecurse(hKeyRoot, szDelKey); + +} diff --git a/shell_integration/windows/NCContextMenu/dllmain.cpp b/shell_integration/windows/NCContextMenu/dllmain.cpp new file mode 100644 index 000000000..a8c6b6ed6 --- /dev/null +++ b/shell_integration/windows/NCContextMenu/dllmain.cpp @@ -0,0 +1,124 @@ +/** +* Copyright (c) 2015 Daniel Molkentin . All rights reserved. +* +* This library is free software; you can redistribute it and/or modify it under +* the terms of the GNU Lesser General Public License as published by the Free +* Software Foundation; either version 2.1 of the License, or (at your option) +* any later version. +* +* This library 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 Lesser General Public License for more +* details. +*/ + +#include +#include +#include "NCContextMenuRegHandler.h" +#include "NCContextMenuFactory.h" +#include "WinShellExtConstants.h" + +HINSTANCE g_hInst = nullptr; +long g_cDllRef = 0; + +BOOL APIENTRY DllMain(HMODULE hModule, DWORD dwReason, LPVOID lpReserved) +{ + switch (dwReason) + { + case DLL_PROCESS_ATTACH: + // Hold the instance of this DLL module, we will use it to get the + // path of the DLL to register the component. + g_hInst = hModule; + DisableThreadLibraryCalls(hModule); + break; + case DLL_THREAD_ATTACH: + case DLL_THREAD_DETACH: + case DLL_PROCESS_DETACH: + break; + } + return TRUE; +} + +STDAPI DllGetClassObject(REFCLSID rclsid, REFIID riid, void **ppv) +{ + HRESULT hr; + GUID guid; + + hr = CLSIDFromString(CONTEXT_MENU_GUID, (LPCLSID)&guid); + if (!SUCCEEDED(hr)) { + return hr; + } + + hr = CLASS_E_CLASSNOTAVAILABLE; + + if (IsEqualCLSID(guid, rclsid)) { + hr = E_OUTOFMEMORY; + + NCContextMenuFactory *pClassFactory = new NCContextMenuFactory(); + if (pClassFactory) { + hr = pClassFactory->QueryInterface(riid, ppv); + pClassFactory->Release(); + } + } + + return hr; +} + +STDAPI DllCanUnloadNow(void) +{ + return g_cDllRef > 0 ? S_FALSE : S_OK; +} + +STDAPI DllRegisterServer(void) +{ + HRESULT hr; + GUID guid; + + hr = CLSIDFromString(CONTEXT_MENU_GUID, (LPCLSID)&guid); + if (!SUCCEEDED(hr)) { + return hr; + } + + wchar_t szModule[MAX_PATH]; + if (GetModuleFileName(g_hInst, szModule, ARRAYSIZE(szModule)) == 0) { + hr = HRESULT_FROM_WIN32(GetLastError()); + return hr; + } + + // Register the component. + hr = NCContextMenuRegHandler::RegisterInprocServer(szModule, guid, + CONTEXT_MENU_DESCRIPTION, L"Apartment"); + if (SUCCEEDED(hr)) { + // Register the context menu handler. The context menu handler is + // associated with the .cpp file class. + hr = NCContextMenuRegHandler::RegisterShellExtContextMenuHandler(L"AllFileSystemObjects", guid, CONTEXT_MENU_REGKEY_NAME); + } + + return hr; +} + +STDAPI DllUnregisterServer(void) +{ + HRESULT hr = S_OK; + GUID guid; + + hr = CLSIDFromString(CONTEXT_MENU_GUID, (LPCLSID)&guid); + if (!SUCCEEDED(hr)) { + return hr; + } + + wchar_t szModule[MAX_PATH]; + if (GetModuleFileName(g_hInst, szModule, ARRAYSIZE(szModule)) == 0) { + hr = HRESULT_FROM_WIN32(GetLastError()); + return hr; + } + + // Unregister the component. + hr = NCContextMenuRegHandler::UnregisterInprocServer(guid); + if (SUCCEEDED(hr)) { + // Unregister the context menu handler. + hr = NCContextMenuRegHandler::UnregisterShellExtContextMenuHandler(L"AllFileSystemObjects", CONTEXT_MENU_REGKEY_NAME); + } + + return hr; +} diff --git a/shell_integration/windows/NCContextMenu/resource.h b/shell_integration/windows/NCContextMenu/resource.h new file mode 100644 index 000000000..c80f97834 --- /dev/null +++ b/shell_integration/windows/NCContextMenu/resource.h @@ -0,0 +1,14 @@ +//{{NO_DEPENDENCIES}} +// Microsoft Visual C++ generated include file. +// Used by NCContextMenu.rc + +// Next default values for new objects +// +#ifdef APSTUDIO_INVOKED +#ifndef APSTUDIO_READONLY_SYMBOLS +#define _APS_NEXT_RESOURCE_VALUE 101 +#define _APS_NEXT_COMMAND_VALUE 40001 +#define _APS_NEXT_CONTROL_VALUE 1001 +#define _APS_NEXT_SYMED_VALUE 101 +#endif +#endif diff --git a/shell_integration/windows/NCOverlays/CMakeLists.txt b/shell_integration/windows/NCOverlays/CMakeLists.txt new file mode 100644 index 000000000..35bfc2ce5 --- /dev/null +++ b/shell_integration/windows/NCOverlays/CMakeLists.txt @@ -0,0 +1,16 @@ +add_library(NCOverlays MODULE + DllMain.cpp + NCOverlay.cpp + NCOverlayFactory.cpp + NCOverlayRegistrationHandler.cpp + NCOverlay.rc + NCOverlays.def +) + +target_link_libraries(NCOverlays + NCUtil) + +install(TARGETS NCOverlays + RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR} + LIBRARY DESTINATION ${CMAKE_INSTALL_BINDIR} +) diff --git a/shell_integration/windows/NCOverlays/DllMain.cpp b/shell_integration/windows/NCOverlays/DllMain.cpp new file mode 100644 index 000000000..1798225d1 --- /dev/null +++ b/shell_integration/windows/NCOverlays/DllMain.cpp @@ -0,0 +1,177 @@ +/** + * Copyright (c) 2000-2013 Liferay, Inc. All rights reserved. + * + * This library is free software; you can redistribute it and/or modify it under + * the terms of the GNU Lesser General Public License as published by the Free + * Software Foundation; either version 2.1 of the License, or (at your option) + * any later version. + * + * This library 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 Lesser General Public License for more + * details. + */ + +#include "NCOverlayRegistrationHandler.h" +#include "NCOverlayFactory.h" +#include "WinShellExtConstants.h" + +HINSTANCE instanceHandle = nullptr; + +long dllReferenceCount = 0; + +BOOL APIENTRY DllMain(HMODULE hModule, DWORD dwReason, LPVOID lpReserved) +{ + switch (dwReason) + { + case DLL_PROCESS_ATTACH: + instanceHandle = hModule; + DisableThreadLibraryCalls(hModule); + break; + case DLL_THREAD_ATTACH: + case DLL_THREAD_DETACH: + case DLL_PROCESS_DETACH: + break; + } + + return TRUE; +} + +HRESULT CreateFactory(REFIID riid, void **ppv, int state) +{ + HRESULT hResult = E_OUTOFMEMORY; + + NCOverlayFactory* ncOverlayFactory = new NCOverlayFactory(state); + + if (ncOverlayFactory) { + hResult = ncOverlayFactory->QueryInterface(riid, ppv); + ncOverlayFactory->Release(); + } + return hResult; +} + +STDAPI DllGetClassObject(REFCLSID rclsid, REFIID riid, void **ppv) +{ + HRESULT hResult = CLASS_E_CLASSNOTAVAILABLE; + GUID guid; + + hResult = CLSIDFromString(OVERLAY_GUID_ERROR, (LPCLSID)&guid); + if (!SUCCEEDED(hResult)) { return hResult; } + if (IsEqualCLSID(guid, rclsid)) { return CreateFactory(riid, ppv, State_Error); } + + hResult = CLSIDFromString(OVERLAY_GUID_OK, (LPCLSID)&guid); + if (!SUCCEEDED(hResult)) { return hResult; } + if (IsEqualCLSID(guid, rclsid)) { return CreateFactory(riid, ppv, State_OK); } + + hResult = CLSIDFromString(OVERLAY_GUID_OK_SHARED, (LPCLSID)&guid); + if (!SUCCEEDED(hResult)) { return hResult; } + if (IsEqualCLSID(guid, rclsid)) { return CreateFactory(riid, ppv, State_OKShared); } + + hResult = CLSIDFromString(OVERLAY_GUID_SYNC, (LPCLSID)&guid); + if (!SUCCEEDED(hResult)) { return hResult; } + if (IsEqualCLSID(guid, rclsid)) { return CreateFactory(riid, ppv, State_Sync); } + + hResult = CLSIDFromString(OVERLAY_GUID_WARNING, (LPCLSID)&guid); + if (!SUCCEEDED(hResult)) { return hResult; } + if (IsEqualCLSID(guid, rclsid)) { return CreateFactory(riid, ppv, State_Warning); } + + return CLASS_E_CLASSNOTAVAILABLE; +} + +STDAPI DllCanUnloadNow(void) +{ + return dllReferenceCount > 0 ? S_FALSE : S_OK; +} + +HRESULT RegisterCLSID(LPCOLESTR guidStr, PCWSTR overlayStr, PCWSTR szModule) +{ + HRESULT hResult = S_OK; + + GUID guid; + hResult = CLSIDFromString(guidStr, (LPCLSID)&guid); + + if (hResult != S_OK) { + return hResult; + } + + hResult = NCOverlayRegistrationHandler::RegisterCOMObject(szModule, OVERLAY_DESCRIPTION, guid); + + if (!SUCCEEDED(hResult)) { + return hResult; + } + + hResult = NCOverlayRegistrationHandler::MakeRegistryEntries(guid, overlayStr); + + return hResult; +} + +HRESULT UnregisterCLSID(LPCOLESTR guidStr, PCWSTR overlayStr) +{ + HRESULT hResult = S_OK; + GUID guid; + + hResult = CLSIDFromString(guidStr, (LPCLSID)&guid); + + if (hResult != S_OK) { + return hResult; + } + + hResult = NCOverlayRegistrationHandler::UnregisterCOMObject(guid); + + if (!SUCCEEDED(hResult)) { + return hResult; + } + + hResult = NCOverlayRegistrationHandler::RemoveRegistryEntries(overlayStr); + + return hResult; +} + +HRESULT _stdcall DllRegisterServer(void) +{ + HRESULT hResult = S_OK; + + wchar_t szModule[MAX_PATH]; + + if (GetModuleFileName(instanceHandle, szModule, ARRAYSIZE(szModule)) == 0) { + hResult = HRESULT_FROM_WIN32(GetLastError()); + return hResult; + } + + hResult = RegisterCLSID(OVERLAY_GUID_ERROR, OVERLAY_NAME_ERROR, szModule); + if (!SUCCEEDED(hResult)) { return hResult; } + hResult = RegisterCLSID(OVERLAY_GUID_OK, OVERLAY_NAME_OK, szModule); + if (!SUCCEEDED(hResult)) { return hResult; } + hResult = RegisterCLSID(OVERLAY_GUID_OK_SHARED, OVERLAY_NAME_OK_SHARED, szModule); + if (!SUCCEEDED(hResult)) { return hResult; } + hResult = RegisterCLSID(OVERLAY_GUID_SYNC, OVERLAY_NAME_SYNC, szModule); + if (!SUCCEEDED(hResult)) { return hResult; } + hResult = RegisterCLSID(OVERLAY_GUID_WARNING, OVERLAY_NAME_WARNING, szModule); + + return hResult; +} + +STDAPI DllUnregisterServer(void) +{ + HRESULT hResult = S_OK; + + wchar_t szModule[MAX_PATH]; + + if (GetModuleFileNameW(instanceHandle, szModule, ARRAYSIZE(szModule)) == 0) + { + hResult = HRESULT_FROM_WIN32(GetLastError()); + return hResult; + } + + hResult = UnregisterCLSID(OVERLAY_GUID_ERROR, OVERLAY_NAME_ERROR); + if (!SUCCEEDED(hResult)) { return hResult; } + hResult = UnregisterCLSID(OVERLAY_GUID_OK, OVERLAY_NAME_OK); + if (!SUCCEEDED(hResult)) { return hResult; } + hResult = UnregisterCLSID(OVERLAY_GUID_OK_SHARED, OVERLAY_NAME_OK_SHARED); + if (!SUCCEEDED(hResult)) { return hResult; } + hResult = UnregisterCLSID(OVERLAY_GUID_SYNC, OVERLAY_NAME_SYNC); + if (!SUCCEEDED(hResult)) { return hResult; } + hResult = UnregisterCLSID(OVERLAY_GUID_WARNING, OVERLAY_NAME_WARNING); + + return hResult; +} diff --git a/shell_integration/windows/NCOverlays/NCOverlay.cpp b/shell_integration/windows/NCOverlays/NCOverlay.cpp new file mode 100644 index 000000000..de1098648 --- /dev/null +++ b/shell_integration/windows/NCOverlays/NCOverlay.cpp @@ -0,0 +1,162 @@ +/** + * Copyright (c) 2000-2013 Liferay, Inc. All rights reserved. + * + * This library is free software; you can redistribute it and/or modify it under + * the terms of the GNU Lesser General Public License as published by the Free + * Software Foundation; either version 2.1 of the License, or (at your option) + * any later version. + * + * This library 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 Lesser General Public License for more + * details. + */ + +#include "NCOverlay.h" +#include "NCOverlayFactory.h" +#include "StringUtil.h" +#include "RemotePathChecker.h" + +#include +#include +#include +#include + +using namespace std; + +#pragma comment(lib, "shlwapi.lib") + +extern HINSTANCE instanceHandle; + +#define IDM_DISPLAY 0 +#define IDB_OK 101 + +namespace { + +unique_ptr s_instance; + +RemotePathChecker *getGlobalChecker() +{ + // On Vista we'll run into issue #2680 if we try to create the thread+pipe connection + // on any DllGetClassObject of our registered classes. + // Work around the issue by creating the static RemotePathChecker only once actually needed. + static once_flag s_onceFlag; + call_once(s_onceFlag, [] { s_instance.reset(new RemotePathChecker); }); + + return s_instance.get(); +} + +} +NCOverlay::NCOverlay(int state) + : _referenceCount(1) + , _state(state) +{ +} + +NCOverlay::~NCOverlay(void) +{ +} + + +IFACEMETHODIMP_(ULONG) NCOverlay::AddRef() +{ + return InterlockedIncrement(&_referenceCount); +} + +IFACEMETHODIMP NCOverlay::QueryInterface(REFIID riid, void **ppv) +{ + HRESULT hr = S_OK; + + if (IsEqualIID(IID_IUnknown, riid) || IsEqualIID(IID_IShellIconOverlayIdentifier, riid)) + { + *ppv = static_cast(this); + } + else + { + hr = E_NOINTERFACE; + *ppv = nullptr; + } + + if (*ppv) + { + AddRef(); + } + + return hr; +} + +IFACEMETHODIMP_(ULONG) NCOverlay::Release() +{ + ULONG cRef = InterlockedDecrement(&_referenceCount); + if (0 == cRef) + { + delete this; + } + + return cRef; +} + +IFACEMETHODIMP NCOverlay::GetPriority(int *pPriority) +{ + // this defines which handler has prededence, so + // we order this in terms of likelyhood + switch (_state) { + case State_OK: + *pPriority = 0; break; + case State_OKShared: + *pPriority = 1; break; + case State_Warning: + *pPriority = 2; break; + case State_Sync: + *pPriority = 3; break; + case State_Error: + *pPriority = 4; break; + default: + *pPriority = 5; break; + } + + return S_OK; +} + +IFACEMETHODIMP NCOverlay::IsMemberOf(PCWSTR pwszPath, DWORD dwAttrib) +{ + RemotePathChecker* checker = getGlobalChecker(); + std::shared_ptr> watchedDirectories = checker->WatchedDirectories(); + + if (watchedDirectories->empty()) { + return MAKE_HRESULT(S_FALSE, 0, 0); + } + + bool watched = false; + size_t pathLength = wcslen(pwszPath); + for (auto it = watchedDirectories->begin(); it != watchedDirectories->end(); ++it) { + if (StringUtil::isDescendantOf(pwszPath, pathLength, *it)) { + watched = true; + } + } + + if (!watched) { + return MAKE_HRESULT(S_FALSE, 0, 0); + } + + int state = 0; + if (!checker->IsMonitoredPath(pwszPath, &state)) { + return MAKE_HRESULT(S_FALSE, 0, 0); + } + return MAKE_HRESULT(state == _state ? S_OK : S_FALSE, 0, 0); +} + +IFACEMETHODIMP NCOverlay::GetOverlayInfo(PWSTR pwszIconFile, int cchMax, int *pIndex, DWORD *pdwFlags) +{ + *pIndex = 0; + *pdwFlags = ISIOI_ICONFILE | ISIOI_ICONINDEX; + *pIndex = _state; + + if (GetModuleFileName(instanceHandle, pwszIconFile, cchMax) == 0) { + HRESULT hResult = HRESULT_FROM_WIN32(GetLastError()); + wcerr << L"IsOK? " << (hResult == S_OK) << L" with path " << pwszIconFile << L", index " << *pIndex << endl; + return hResult; + } + + return S_OK; +} diff --git a/shell_integration/windows/NCOverlays/NCOverlay.h b/shell_integration/windows/NCOverlays/NCOverlay.h new file mode 100644 index 000000000..688a6b095 --- /dev/null +++ b/shell_integration/windows/NCOverlays/NCOverlay.h @@ -0,0 +1,43 @@ +/** + * Copyright (c) 2000-2013 Liferay, Inc. All rights reserved. + * + * This library is free software; you can redistribute it and/or modify it under + * the terms of the GNU Lesser General Public License as published by the Free + * Software Foundation; either version 2.1 of the License, or (at your option) + * any later version. + * + * This library 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 Lesser General Public License for more + * details. + */ + +#ifndef NCOVERLAY_H +#define NCOVERLAY_H + +#pragma once + +#include + +class NCOverlay : public IShellIconOverlayIdentifier + +{ +public: + NCOverlay(int state); + + IFACEMETHODIMP_(ULONG) AddRef(); + IFACEMETHODIMP GetOverlayInfo(PWSTR pwszIconFile, int cchMax, int *pIndex, DWORD *pdwFlags); + IFACEMETHODIMP GetPriority(int *pPriority); + IFACEMETHODIMP IsMemberOf(PCWSTR pwszPath, DWORD dwAttrib); + IFACEMETHODIMP QueryInterface(REFIID riid, void **ppv); + IFACEMETHODIMP_(ULONG) Release(); + +protected: + ~NCOverlay(); + +private: + long _referenceCount; + int _state; +}; + +#endif \ No newline at end of file diff --git a/shell_integration/windows/NCOverlays/NCOverlay.rc b/shell_integration/windows/NCOverlays/NCOverlay.rc new file mode 100644 index 000000000..69bf79b9f Binary files /dev/null and b/shell_integration/windows/NCOverlays/NCOverlay.rc differ diff --git a/shell_integration/windows/NCOverlays/NCOverlayFactory.cpp b/shell_integration/windows/NCOverlays/NCOverlayFactory.cpp new file mode 100644 index 000000000..2c063a866 --- /dev/null +++ b/shell_integration/windows/NCOverlays/NCOverlayFactory.cpp @@ -0,0 +1,94 @@ +/** + * Copyright (c) 2000-2013 Liferay, Inc. All rights reserved. + * + * This library is free software; you can redistribute it and/or modify it under + * the terms of the GNU Lesser General Public License as published by the Free + * Software Foundation; either version 2.1 of the License, or (at your option) + * any later version. + * + * This library 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 Lesser General Public License for more + * details. + */ + +#include +#include + +#include "NCOverlayFactory.h" +#include "NCOverlay.h" + +extern long dllReferenceCount; + +NCOverlayFactory::NCOverlayFactory(int state) + : _referenceCount(1), _state(state) +{ + InterlockedIncrement(&dllReferenceCount); +} + +NCOverlayFactory::~NCOverlayFactory() +{ + InterlockedDecrement(&dllReferenceCount); +} + +IFACEMETHODIMP NCOverlayFactory::QueryInterface(REFIID riid, void **ppv) +{ + HRESULT hResult = S_OK; + + if (IsEqualIID(IID_IUnknown, riid) || + IsEqualIID(IID_IClassFactory, riid)) + { + *ppv = static_cast(this); + AddRef(); + } + else + { + hResult = E_NOINTERFACE; + *ppv = nullptr; + } + + return hResult; +} + +IFACEMETHODIMP_(ULONG) NCOverlayFactory::AddRef() +{ + return InterlockedIncrement(&_referenceCount); +} + +IFACEMETHODIMP_(ULONG) NCOverlayFactory::Release() +{ + ULONG cRef = InterlockedDecrement(&_referenceCount); + + if (0 == cRef) + { + delete this; + } + return cRef; +} + +IFACEMETHODIMP NCOverlayFactory::CreateInstance( + IUnknown *pUnkOuter, REFIID riid, void **ppv) +{ + HRESULT hResult = CLASS_E_NOAGGREGATION; + + if (pUnkOuter) { return hResult; } + + hResult = E_OUTOFMEMORY; + NCOverlay *lrOverlay = new (std::nothrow) NCOverlay(_state); + if (!lrOverlay) { return hResult; } + + hResult = lrOverlay->QueryInterface(riid, ppv); + lrOverlay->Release(); + + return hResult; +} + +IFACEMETHODIMP NCOverlayFactory::LockServer(BOOL fLock) +{ + if (fLock) { + InterlockedIncrement(&dllReferenceCount); + } else { + InterlockedDecrement(&dllReferenceCount); + } + return S_OK; +} diff --git a/shell_integration/windows/NCOverlays/NCOverlayFactory.h b/shell_integration/windows/NCOverlays/NCOverlayFactory.h new file mode 100644 index 000000000..74962cc02 --- /dev/null +++ b/shell_integration/windows/NCOverlays/NCOverlayFactory.h @@ -0,0 +1,48 @@ +/** + * Copyright (c) 2000-2013 Liferay, Inc. All rights reserved. + * + * This library is free software; you can redistribute it and/or modify it under + * the terms of the GNU Lesser General Public License as published by the Free + * Software Foundation; either version 2.1 of the License, or (at your option) + * any later version. + * + * This library 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 Lesser General Public License for more + * details. + */ + +#ifndef NCOVERLAYFACTORY_H +#define NCOVERLAYFACTORY_H + +#pragma once + +#include + +enum State { + State_Error = 0, + State_OK, State_OKShared, + State_Sync, + State_Warning +}; + +class NCOverlayFactory : public IClassFactory +{ +public: + NCOverlayFactory(int state); + + IFACEMETHODIMP_(ULONG) AddRef(); + IFACEMETHODIMP CreateInstance(IUnknown *pUnkOuter, REFIID riid, void **ppv); + IFACEMETHODIMP LockServer(BOOL fLock); + IFACEMETHODIMP QueryInterface(REFIID riid, void **ppv); + IFACEMETHODIMP_(ULONG) Release(); + +protected: + ~NCOverlayFactory(); + +private: + long _referenceCount; + int _state; +}; + +#endif \ No newline at end of file diff --git a/shell_integration/windows/NCOverlays/NCOverlayRegistrationHandler.cpp b/shell_integration/windows/NCOverlays/NCOverlayRegistrationHandler.cpp new file mode 100644 index 000000000..08586f1d9 --- /dev/null +++ b/shell_integration/windows/NCOverlays/NCOverlayRegistrationHandler.cpp @@ -0,0 +1,171 @@ +/** + * Copyright (c) 2000-2013 Liferay, Inc. All rights reserved. + * + * This library is free software; you can redistribute it and/or modify it under + * the terms of the GNU Lesser General Public License as published by the Free + * Software Foundation; either version 2.1 of the License, or (at your option) + * any later version. + * + * This library 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 Lesser General Public License for more + * details. + */ + +#include "NCOverlayRegistrationHandler.h" + +#include +#include +#include +#include + +#define REGISTRY_OVERLAY_KEY LR"(SOFTWARE\Microsoft\Windows\CurrentVersion\Explorer\ShellIconOverlayIdentifiers)" +#define REGISTRY_CLSID L"CLSID" +#define REGISTRY_IN_PROCESS L"InprocServer32" +#define REGISTRY_THREADING L"ThreadingModel" +#define REGISTRY_APARTMENT L"Apartment" +#define REGISTRY_VERSION L"Version" +#define REGISTRY_VERSION_NUMBER L"1.0" + +using namespace std; + +HRESULT NCOverlayRegistrationHandler::MakeRegistryEntries(const CLSID& clsid, PCWSTR friendlyName) +{ + HRESULT hResult; + HKEY shellOverlayKey = nullptr; + // the key may not exist yet + hResult = HRESULT_FROM_WIN32(RegCreateKeyEx(HKEY_LOCAL_MACHINE, REGISTRY_OVERLAY_KEY, 0, nullptr, REG_OPTION_NON_VOLATILE, KEY_WRITE, nullptr, &shellOverlayKey, nullptr)); + if (!SUCCEEDED(hResult)) { + hResult = RegCreateKey(HKEY_LOCAL_MACHINE, REGISTRY_OVERLAY_KEY, &shellOverlayKey); + if(!SUCCEEDED(hResult)) { + return hResult; + } + } + + HKEY syncExOverlayKey = nullptr; + hResult = HRESULT_FROM_WIN32(RegCreateKeyEx(shellOverlayKey, friendlyName, 0, nullptr, REG_OPTION_NON_VOLATILE, KEY_WRITE, nullptr, &syncExOverlayKey, nullptr)); + + if (!SUCCEEDED(hResult)) { + return hResult; + } + + wchar_t stringCLSID[MAX_PATH]; + StringFromGUID2(clsid, stringCLSID, ARRAYSIZE(stringCLSID)); + LPCTSTR value = stringCLSID; + hResult = RegSetValueEx(syncExOverlayKey, nullptr, 0, REG_SZ, (LPBYTE)value, (DWORD)((wcslen(value)+1) * sizeof(TCHAR))); + if (!SUCCEEDED(hResult)) { + return hResult; + } + + return hResult; +} + +HRESULT NCOverlayRegistrationHandler::RemoveRegistryEntries(PCWSTR friendlyName) +{ + HRESULT hResult; + HKEY shellOverlayKey = nullptr; + hResult = HRESULT_FROM_WIN32(RegOpenKeyEx(HKEY_LOCAL_MACHINE, REGISTRY_OVERLAY_KEY, 0, KEY_WRITE, &shellOverlayKey)); + + if (!SUCCEEDED(hResult)) { + return hResult; + } + + HKEY syncExOverlayKey = nullptr; + hResult = HRESULT_FROM_WIN32(RegDeleteKey(shellOverlayKey, friendlyName)); + if (!SUCCEEDED(hResult)) { + return hResult; + } + + return hResult; +} + +HRESULT NCOverlayRegistrationHandler::RegisterCOMObject(PCWSTR modulePath, PCWSTR friendlyName, const CLSID& clsid) +{ + if (!modulePath) { + return E_FAIL; + } + + wchar_t stringCLSID[MAX_PATH]; + StringFromGUID2(clsid, stringCLSID, ARRAYSIZE(stringCLSID)); + HRESULT hResult; + HKEY hKey = nullptr; + + hResult = HRESULT_FROM_WIN32(RegOpenKeyEx(HKEY_CLASSES_ROOT, REGISTRY_CLSID, 0, KEY_WRITE, &hKey)); + if (!SUCCEEDED(hResult)) { + return hResult; + } + + HKEY clsidKey = nullptr; + hResult = HRESULT_FROM_WIN32(RegCreateKeyEx(hKey, stringCLSID, 0, nullptr, REG_OPTION_NON_VOLATILE, KEY_WRITE, nullptr, &clsidKey, nullptr)); + if (!SUCCEEDED(hResult)) { + return hResult; + } + + hResult = HRESULT_FROM_WIN32(RegSetValue(clsidKey, nullptr, REG_SZ, friendlyName, (DWORD) wcslen(friendlyName))); + + HKEY inprocessKey = nullptr; + hResult = HRESULT_FROM_WIN32(RegCreateKeyEx(clsidKey, REGISTRY_IN_PROCESS, 0, nullptr, REG_OPTION_NON_VOLATILE, KEY_WRITE, nullptr, &inprocessKey, nullptr)); + if (!SUCCEEDED(hResult)) { + return hResult; + } + + hResult = HRESULT_FROM_WIN32(RegSetValue(inprocessKey, nullptr, REG_SZ, modulePath, (DWORD) wcslen(modulePath))); + + if (!SUCCEEDED(hResult)) { + return hResult; + } + + hResult = HRESULT_FROM_WIN32(RegSetValueEx(inprocessKey, REGISTRY_THREADING, 0, REG_SZ, (LPBYTE)REGISTRY_APARTMENT, (DWORD)((wcslen(REGISTRY_APARTMENT)+1) * sizeof(TCHAR)))); + if (!SUCCEEDED(hResult)) { + return hResult; + } + + HKEY versionKey = nullptr; + hResult = HRESULT_FROM_WIN32(RegCreateKeyEx(clsidKey, REGISTRY_VERSION, 0, nullptr, REG_OPTION_NON_VOLATILE, KEY_WRITE, nullptr, &versionKey, nullptr)); + if (!SUCCEEDED(hResult)) { + return hResult; + } + + hResult = HRESULT_FROM_WIN32(RegSetValueEx(versionKey, nullptr, 0, REG_SZ, (LPBYTE)REGISTRY_VERSION_NUMBER, (DWORD)(wcslen(REGISTRY_VERSION_NUMBER)+1) * sizeof(TCHAR))); + if (!SUCCEEDED(hResult)) { + return hResult; + } + + return S_OK; +} + +HRESULT NCOverlayRegistrationHandler::UnregisterCOMObject(const CLSID& clsid) +{ + wchar_t stringCLSID[MAX_PATH]; + + StringFromGUID2(clsid, stringCLSID, ARRAYSIZE(stringCLSID)); + HRESULT hResult; + HKEY hKey = nullptr; + hResult = HRESULT_FROM_WIN32(RegOpenKeyEx(HKEY_CLASSES_ROOT, REGISTRY_CLSID, 0, DELETE, &hKey)); + if (!SUCCEEDED(hResult)) { + return hResult; + } + + HKEY clsidKey = nullptr; + hResult = HRESULT_FROM_WIN32(RegOpenKeyEx(hKey, stringCLSID, 0, DELETE, &clsidKey)); + if (!SUCCEEDED(hResult)) { + return hResult; + } + + hResult = HRESULT_FROM_WIN32(RegDeleteKey(clsidKey, REGISTRY_IN_PROCESS)); + if (!SUCCEEDED(hResult)) { + return hResult; + } + + hResult = HRESULT_FROM_WIN32(RegDeleteKey(clsidKey, REGISTRY_VERSION)); + if (!SUCCEEDED(hResult)) { + return hResult; + } + + hResult = HRESULT_FROM_WIN32(RegDeleteKey(hKey, stringCLSID)); + if (!SUCCEEDED(hResult)) { + return hResult; + } + + return S_OK; +} diff --git a/shell_integration/windows/NCOverlays/NCOverlayRegistrationHandler.h b/shell_integration/windows/NCOverlays/NCOverlayRegistrationHandler.h new file mode 100644 index 000000000..473d4217d --- /dev/null +++ b/shell_integration/windows/NCOverlays/NCOverlayRegistrationHandler.h @@ -0,0 +1,31 @@ +/** + * Copyright (c) 2000-2013 Liferay, Inc. All rights reserved. + * + * This library is free software; you can redistribute it and/or modify it under + * the terms of the GNU Lesser General Public License as published by the Free + * Software Foundation; either version 2.1 of the License, or (at your option) + * any later version. + * + * This library 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 Lesser General Public License for more + * details. + */ + +#ifndef NCOVERLAYREGISTRATIONHANDLER_H +#define NCOVERLAYREGISTRATIONHANDLER_H + +#pragma once + +#include + +class __declspec(dllexport) NCOverlayRegistrationHandler +{ + public: + static HRESULT MakeRegistryEntries(const CLSID& clsid, PCWSTR fileType); + static HRESULT RegisterCOMObject(PCWSTR modulePath, PCWSTR friendlyName, const CLSID& clsid); + static HRESULT RemoveRegistryEntries(PCWSTR friendlyName); + static HRESULT UnregisterCOMObject(const CLSID& clsid); +}; + +#endif \ No newline at end of file diff --git a/shell_integration/windows/NCOverlays/NCOverlays.def b/shell_integration/windows/NCOverlays/NCOverlays.def new file mode 100644 index 000000000..8cde2bd02 --- /dev/null +++ b/shell_integration/windows/NCOverlays/NCOverlays.def @@ -0,0 +1,6 @@ +LIBRARY +EXPORTS + DllGetClassObject PRIVATE + DllCanUnloadNow PRIVATE + DllRegisterServer PRIVATE + DllUnregisterServer PRIVATE \ No newline at end of file diff --git a/shell_integration/windows/NCOverlays/ico/Error.ico b/shell_integration/windows/NCOverlays/ico/Error.ico new file mode 100644 index 000000000..641363a8d Binary files /dev/null and b/shell_integration/windows/NCOverlays/ico/Error.ico differ diff --git a/shell_integration/windows/NCOverlays/ico/OK.ico b/shell_integration/windows/NCOverlays/ico/OK.ico new file mode 100644 index 000000000..8ebbff426 Binary files /dev/null and b/shell_integration/windows/NCOverlays/ico/OK.ico differ diff --git a/shell_integration/windows/NCOverlays/ico/OK_Shared.ico b/shell_integration/windows/NCOverlays/ico/OK_Shared.ico new file mode 100644 index 000000000..c95e1f97e Binary files /dev/null and b/shell_integration/windows/NCOverlays/ico/OK_Shared.ico differ diff --git a/shell_integration/windows/NCOverlays/ico/Sync.ico b/shell_integration/windows/NCOverlays/ico/Sync.ico new file mode 100644 index 000000000..5ba1c3b2a Binary files /dev/null and b/shell_integration/windows/NCOverlays/ico/Sync.ico differ diff --git a/shell_integration/windows/NCOverlays/ico/Warning.ico b/shell_integration/windows/NCOverlays/ico/Warning.ico new file mode 100644 index 000000000..2bae6710d Binary files /dev/null and b/shell_integration/windows/NCOverlays/ico/Warning.ico differ diff --git a/shell_integration/windows/NCOverlays/resource.h b/shell_integration/windows/NCOverlays/resource.h new file mode 100644 index 000000000..b092fe27c Binary files /dev/null and b/shell_integration/windows/NCOverlays/resource.h differ diff --git a/shell_integration/windows/NCUtil/CMakeLists.txt b/shell_integration/windows/NCUtil/CMakeLists.txt new file mode 100644 index 000000000..fa75e1593 --- /dev/null +++ b/shell_integration/windows/NCUtil/CMakeLists.txt @@ -0,0 +1,11 @@ +add_library(NCUtil STATIC + CommunicationSocket.cpp + RemotePathChecker.cpp + StringUtil.cpp + NCUtil.rc +) + +target_include_directories(NCUtil + PUBLIC + "${CMAKE_CURRENT_SOURCE_DIR}" +) diff --git a/shell_integration/windows/NCUtil/CommunicationSocket.cpp b/shell_integration/windows/NCUtil/CommunicationSocket.cpp new file mode 100644 index 000000000..cda36c1b8 --- /dev/null +++ b/shell_integration/windows/NCUtil/CommunicationSocket.cpp @@ -0,0 +1,141 @@ +/** + * Copyright (c) 2000-2013 Liferay, Inc. All rights reserved. + * + * This library is free software; you can redistribute it and/or modify it under + * the terms of the GNU Lesser General Public License as published by the Free + * Software Foundation; either version 2.1 of the License, or (at your option) + * any later version. + * + * This library 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 Lesser General Public License for more + * details. + */ + +#include "CommunicationSocket.h" +#include "StringUtil.h" + +#include +#include +#include + +#include + +#define DEFAULT_BUFLEN 4096 + +using namespace std; + +namespace { + +std::wstring getUserName() { + DWORD len = DEFAULT_BUFLEN; + TCHAR buf[DEFAULT_BUFLEN]; + if (GetUserName(buf, &len)) { + return std::wstring(&buf[0], len); + } else { + return std::wstring(); + } +} + +} + +std::wstring CommunicationSocket::DefaultPipePath() +{ + auto pipename = std::wstring(LR"(\\.\pipe\)"); + pipename += L"ownCloud-"; + pipename += getUserName(); + return pipename; +} + +CommunicationSocket::CommunicationSocket() + : _pipe(INVALID_HANDLE_VALUE) +{ +} + +CommunicationSocket::~CommunicationSocket() +{ + Close(); +} + +bool CommunicationSocket::Close() +{ + if (_pipe == INVALID_HANDLE_VALUE) { + return false; + } + CloseHandle(_pipe); + _pipe = INVALID_HANDLE_VALUE; + return true; +} + + +bool CommunicationSocket::Connect(const std::wstring &pipename) +{ + _pipe = CreateFile(pipename.data(), GENERIC_READ | GENERIC_WRITE, 0, nullptr, OPEN_EXISTING, 0, nullptr); + + if (_pipe == INVALID_HANDLE_VALUE) { + return false; + } + + return true; +} + +bool CommunicationSocket::SendMsg(const wchar_t* message) const +{ + auto utf8_msg = StringUtil::toUtf8(message); + + DWORD numBytesWritten = 0; + auto result = WriteFile( _pipe, utf8_msg.c_str(), DWORD(utf8_msg.size()), &numBytesWritten, nullptr); + + if (result) { + return true; + } else { + const_cast(this)->Close(); + + return false; + } +} + +bool CommunicationSocket::ReadLine(wstring* response) +{ + if (!response) { + return false; + } + + response->clear(); + + if (_pipe == INVALID_HANDLE_VALUE) { + return false; + } + + while (true) { + int lbPos = 0; + auto it = std::find(_buffer.begin() + lbPos, _buffer.end(), '\n'); + if (it != _buffer.end()) { + *response = StringUtil::toUtf16(_buffer.data(), DWORD(it - _buffer.begin())); + _buffer.erase(_buffer.begin(), it + 1); + return true; + } + + std::array resp_utf8; + DWORD numBytesRead = 0; + DWORD totalBytesAvailable = 0; + + if (!PeekNamedPipe(_pipe, nullptr, 0, 0, &totalBytesAvailable, 0)) { + Close(); + return false; + } + if (totalBytesAvailable == 0) { + return false; + } + + if (!ReadFile(_pipe, resp_utf8.data(), DWORD(resp_utf8.size()), &numBytesRead, nullptr)) { + Close(); + return false; + } + if (numBytesRead <= 0) { + return false; + } + _buffer.insert(_buffer.end(), resp_utf8.begin(), resp_utf8.begin()+numBytesRead); + continue; + } +} diff --git a/shell_integration/windows/NCUtil/CommunicationSocket.h b/shell_integration/windows/NCUtil/CommunicationSocket.h new file mode 100644 index 000000000..68414ef98 --- /dev/null +++ b/shell_integration/windows/NCUtil/CommunicationSocket.h @@ -0,0 +1,48 @@ +/** + * Copyright (c) 2000-2013 Liferay, Inc. All rights reserved. + * + * This library is free software; you can redistribute it and/or modify it under + * the terms of the GNU Lesser General Public License as published by the Free + * Software Foundation; either version 2.1 of the License, or (at your option) + * any later version. + * + * This library 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 Lesser General Public License for more + * details. + */ + +#ifndef COMMUNICATIONSOCKET_H +#define COMMUNICATIONSOCKET_H + +#pragma once + +#pragma warning (disable : 4251) + +#include +#include +#include + +class __declspec(dllexport) CommunicationSocket +{ +public: + static std::wstring DefaultPipePath(); + + CommunicationSocket(); + ~CommunicationSocket(); + + bool Connect(const std::wstring& pipename); + bool Close(); + + bool SendMsg(const wchar_t*) const; + bool ReadLine(std::wstring*); + + HANDLE Event() { return _pipe; } + +private: + HANDLE _pipe; + std::vector _buffer; + bool _connected; +}; + +#endif diff --git a/shell_integration/windows/NCUtil/NCUtil.rc b/shell_integration/windows/NCUtil/NCUtil.rc new file mode 100644 index 000000000..fc3700847 Binary files /dev/null and b/shell_integration/windows/NCUtil/NCUtil.rc differ diff --git a/shell_integration/windows/NCUtil/RemotePathChecker.cpp b/shell_integration/windows/NCUtil/RemotePathChecker.cpp new file mode 100644 index 000000000..5d004d567 --- /dev/null +++ b/shell_integration/windows/NCUtil/RemotePathChecker.cpp @@ -0,0 +1,236 @@ +/** +* Copyright (c) 2014 ownCloud GmbH. All rights reserved. +* +* This library is free software; you can redistribute it and/or modify it under +* the terms of the GNU Lesser General Public License as published by the Free +* Software Foundation; version 2.1 of the License +* +* This library 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 Lesser General Public License for more +* details. +*/ + +#include "CommunicationSocket.h" + +#include "RemotePathChecker.h" +#include "StringUtil.h" + +#include + +#include +#include +#include +#include +#include +#include + +#include + +using namespace std; + +// This code is run in a thread +void RemotePathChecker::workerThreadLoop() +{ + auto pipename = CommunicationSocket::DefaultPipePath(); + bool connected = false; + CommunicationSocket socket; + std::unordered_set asked; + + while(!_stop) { + Sleep(50); + + if (!connected) { + asked.clear(); + if (!WaitNamedPipe(pipename.data(), 100)) { + continue; + } + if (!socket.Connect(pipename)) { + continue; + } + connected = true; + std::unique_lock lock(_mutex); + _connected = true; + } + + { + std::unique_lock lock(_mutex); + while (!_pending.empty() && !_stop) { + auto filePath = _pending.front(); + _pending.pop(); + + lock.unlock(); + if (!asked.count(filePath)) { + asked.insert(filePath); + socket.SendMsg(wstring(L"RETRIEVE_FILE_STATUS:" + filePath + L'\n').data()); + } + lock.lock(); + } + } + + std::wstring response; + while (!_stop && socket.ReadLine(&response)) { + if (StringUtil::begins_with(response, wstring(L"REGISTER_PATH:"))) { + wstring responsePath = response.substr(14); // length of REGISTER_PATH: + + auto sharedPtrCopy = atomic_load(&_watchedDirectories); + auto vectorCopy = make_shared>(*sharedPtrCopy); + vectorCopy->push_back(responsePath); + atomic_store(&_watchedDirectories, shared_ptr>(vectorCopy)); + + // We don't keep track of all files and can't know which file is currently visible + // to the user, but at least reload the root dir so that any shortcut to the root + // is updated without the user needing to refresh. + SHChangeNotify(SHCNE_UPDATEDIR, SHCNF_PATH | SHCNF_FLUSHNOWAIT, responsePath.data(), nullptr); + } else if (StringUtil::begins_with(response, wstring(L"UNREGISTER_PATH:"))) { + wstring responsePath = response.substr(16); // length of UNREGISTER_PATH: + + auto sharedPtrCopy = atomic_load(&_watchedDirectories); + auto vectorCopy = make_shared>(*sharedPtrCopy); + vectorCopy->erase( + std::remove(vectorCopy->begin(), vectorCopy->end(), responsePath), + vectorCopy->end()); + atomic_store(&_watchedDirectories, shared_ptr>(vectorCopy)); + + vector removedPaths; + { std::unique_lock lock(_mutex); + // Remove any item from the cache + for (auto it = _cache.begin(); it != _cache.end() ; ) { + if (StringUtil::isDescendantOf(it->first, responsePath)) { + removedPaths.emplace_back(move(it->first)); + it = _cache.erase(it); + } else { + ++it; + } + } + } + for (auto& path : removedPaths) + SHChangeNotify(SHCNE_UPDATEITEM, SHCNF_PATH | SHCNF_FLUSHNOWAIT, path.data(), nullptr); + } else if (StringUtil::begins_with(response, wstring(L"STATUS:")) || + StringUtil::begins_with(response, wstring(L"BROADCAST:"))) { + + wstring responseStatus, responsePath; + if (!StringUtil::extractChunks(response, responseStatus, responsePath)) + continue; + + auto state = _StrToFileState(responseStatus); + bool wasAsked = asked.erase(responsePath) > 0; + + bool updateView = false; + { std::unique_lock lock(_mutex); + auto it = _cache.find(responsePath); + if (it == _cache.end()) { + // The client only approximates requested files, if the bloom + // filter becomes saturated after navigating multiple directories we'll start getting + // status pushes that we never requested and fill our cache. Ignore those. + if (!wasAsked) { + continue; + } + it = _cache.insert(make_pair(responsePath, StateNone)).first; + } + + updateView = it->second != state; + it->second = state; + } + if (updateView) { + SHChangeNotify(SHCNE_UPDATEITEM, SHCNF_PATH | SHCNF_FLUSHNOWAIT, responsePath.data(), nullptr); + } + } + } + + if (socket.Event() == INVALID_HANDLE_VALUE) { + atomic_store(&_watchedDirectories, make_shared>()); + std::unique_lock lock(_mutex); + _connected = connected = false; + + // Swap to make a copy of the cache under the mutex and clear the one stored. + std::unordered_map cache; + swap(cache, _cache); + lock.unlock(); + // Let explorer know about each invalidated cache entry that needs to get its icon removed. + for (auto it = cache.begin(); it != cache.end(); ++it) { + SHChangeNotify(SHCNE_UPDATEITEM, SHCNF_PATH | SHCNF_FLUSHNOWAIT, it->first.data(), nullptr); + } + } + + if (_stop) return; + + HANDLE handles[2] = { _newQueries, socket.Event() }; + WaitForMultipleObjects(2, handles, false, 0); + } +} + + + +RemotePathChecker::RemotePathChecker() + : _stop(false) + , _watchedDirectories(make_shared>()) + , _connected(false) + , _newQueries(CreateEvent(nullptr, FALSE, FALSE, nullptr)) + , _thread([this]{ this->workerThreadLoop(); }) +{ +} + +RemotePathChecker::~RemotePathChecker() +{ + _stop = true; + //_newQueries.notify_all(); + SetEvent(_newQueries); + _thread.join(); + CloseHandle(_newQueries); +} + +std::shared_ptr> RemotePathChecker::WatchedDirectories() const +{ + return atomic_load(&_watchedDirectories); +} + +bool RemotePathChecker::IsMonitoredPath(const wchar_t* filePath, int* state) +{ + assert(state); assert(filePath); + + std::unique_lock lock(_mutex); + if (!_connected) { + return false; + } + + auto path = std::wstring(filePath); + + auto it = _cache.find(path); + if (it != _cache.end()) { + // The path is in our cache, and we'll get updates pushed if the status changes. + *state = it->second; + return true; + } + + _pending.push(filePath); + + lock.unlock(); + SetEvent(_newQueries); + return false; +} + +RemotePathChecker::FileState RemotePathChecker::_StrToFileState(const std::wstring &str) +{ + if (str == L"NOP" || str == L"NONE") { + return StateNone; + } else if (str == L"SYNC" || str == L"NEW") { + return StateSync; + } else if (str == L"SYNC+SWM" || str == L"NEW+SWM") { + return StateSync; + } else if (str == L"OK") { + return StateOk; + } else if (str == L"OK+SWM") { + return StateOkSWM; + } else if (str == L"IGNORE") { + return StateWarning; + } else if (str == L"IGNORE+SWM") { + return StateWarning; + } else if (str == L"ERROR") { + return StateError; + } else if (str == L"ERROR+SWM") { + return StateError; + } + + return StateNone; +} diff --git a/shell_integration/windows/NCUtil/RemotePathChecker.h b/shell_integration/windows/NCUtil/RemotePathChecker.h new file mode 100644 index 000000000..5758a9a5c --- /dev/null +++ b/shell_integration/windows/NCUtil/RemotePathChecker.h @@ -0,0 +1,70 @@ +/** +* Copyright (c) 2014 ownCloud GmbH. All rights reserved. +* +* This library is free software; you can redistribute it and/or modify it under +* the terms of the GNU Lesser General Public License as published by the Free +* Software Foundation; version 2.1 of the License +* +* This library 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 Lesser General Public License for more +* details. +*/ + +#ifndef PATHCHECKER_H +#define PATHCHECKER_H + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#pragma once + +class __declspec(dllexport) RemotePathChecker { +public: + enum FileState { + // Order synced with NCOverlay + StateError = 0, + StateOk, StateOkSWM, + StateSync, + StateWarning, + StateNone + }; + RemotePathChecker(); + ~RemotePathChecker(); + std::shared_ptr> WatchedDirectories() const; + bool IsMonitoredPath(const wchar_t* filePath, int* state); + +private: + FileState _StrToFileState(const std::wstring &str); + std::mutex _mutex; + std::atomic _stop; + + // Everything here is protected by the _mutex + + /** The list of paths we need to query. The main thread fill this, and the worker thread + * send that to the socket. */ + std::queue _pending; + + std::unordered_map _cache; + // The vector is const since it will be accessed from multiple threads through NCOverlay::IsMemberOf. + // Each modification needs to be made onto a copy and then atomically replaced in the shared_ptr. + std::shared_ptr> _watchedDirectories; + bool _connected; + + + // The main thread notifies when there are new items in _pending + //std::condition_variable _newQueries; + HANDLE _newQueries; + + std::thread _thread; + void workerThreadLoop(); +}; + +#endif \ No newline at end of file diff --git a/shell_integration/windows/NCUtil/StringUtil.cpp b/shell_integration/windows/NCUtil/StringUtil.cpp new file mode 100644 index 000000000..e23030e02 --- /dev/null +++ b/shell_integration/windows/NCUtil/StringUtil.cpp @@ -0,0 +1,36 @@ +/** +* Copyright (c) 2014 ownCloud GmbH. All rights reserved. +* +* This library is free software; you can redistribute it and/or modify it under +* the terms of the GNU Lesser General Public License as published by the Free +* Software Foundation; version 2.1 of the License +* +* This library 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 Lesser General Public License for more +* details. +*/ + +#include +#include +#include + +#include "StringUtil.h" + +std::string StringUtil::toUtf8(const wchar_t *utf16, int len) +{ + if (len < 0) { + len = (int) wcslen(utf16); + } + std::wstring_convert > converter; + return converter.to_bytes(utf16, utf16+len); +} + +std::wstring StringUtil::toUtf16(const char *utf8, int len) +{ + if (len < 0) { + len = (int) strlen(utf8); + } + std::wstring_convert > converter; + return converter.from_bytes(utf8, utf8+len); +} diff --git a/shell_integration/windows/NCUtil/StringUtil.h b/shell_integration/windows/NCUtil/StringUtil.h new file mode 100644 index 000000000..180d7c80a --- /dev/null +++ b/shell_integration/windows/NCUtil/StringUtil.h @@ -0,0 +1,91 @@ +/** +* Copyright (c) 2014 ownCloud GmbH. All rights reserved. +* +* This library is free software; you can redistribute it and/or modify it under +* the terms of the GNU Lesser General Public License as published by the Free +* Software Foundation; version 2.1 of the License +* +* This library 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 Lesser General Public License for more +* details. +*/ + +#ifndef STRINGUTIL_H +#define STRINGUTIL_H + +#pragma once + +#include +#include +#include + +class __declspec(dllexport) StringUtil { +public: + static std::string toUtf8(const wchar_t* utf16, int len = -1); + static std::wstring toUtf16(const char* utf8, int len = -1); + + template + static bool begins_with(const T& input, const T& match) + { + return input.size() >= match.size() + && std::equal(match.begin(), match.end(), input.begin()); + } + + static bool isDescendantOf(const std::wstring& child, const std::wstring& parent) { + return isDescendantOf(child.c_str(), child.size(), parent.c_str(), parent.size()); + } + + static bool isDescendantOf(PCWSTR child, size_t childLength, const std::wstring& parent) { + return isDescendantOf(child, childLength, parent.c_str(), parent.size()); + } + + static bool isDescendantOf(PCWSTR child, size_t childLength, PCWSTR parent, size_t parentLength) { + if (!parentLength) + return false; + return (childLength == parentLength || childLength > parentLength && (child[parentLength] == L'\\' || child[parentLength - 1] == L'\\')) + && wcsncmp(child, parent, parentLength) == 0; + } + + static bool extractChunks(const std::wstring &source, std::wstring &secondChunk, std::wstring &thirdChunk) { + auto statusBegin = source.find(L':', 0); + assert(statusBegin != std::wstring::npos); + + auto statusEnd = source.find(L':', statusBegin + 1); + if (statusEnd == std::wstring::npos) { + // the command do not contains two colon? + return false; + } + + // Assume the caller extracted the chunk before the first colon. + secondChunk = source.substr(statusBegin + 1, statusEnd - statusBegin - 1); + thirdChunk = source.substr(statusEnd + 1); + return true; + } + + static bool extractChunks(const std::wstring &source, std::wstring &secondChunk, std::wstring &thirdChunk, std::wstring &forthChunk) + { + auto statusBegin = source.find(L':', 0); + assert(statusBegin != std::wstring::npos); + + auto statusEnd = source.find(L':', statusBegin + 1); + if (statusEnd == std::wstring::npos) { + // the command do not contains two colon? + return false; + } + + auto thirdColon = source.find(L':', statusEnd + 1); + if (statusEnd == std::wstring::npos) { + // the command do not contains three colon? + return false; + } + + // Assume the caller extracted the chunk before the first colon. + secondChunk = source.substr(statusBegin + 1, statusEnd - statusBegin - 1); + thirdChunk = source.substr(statusEnd + 1, thirdColon - statusEnd - 1); + forthChunk = source.substr(thirdColon + 1); + return true; + } +}; + +#endif // STRINGUTIL_H diff --git a/shell_integration/windows/NCUtil/Version.h b/shell_integration/windows/NCUtil/Version.h new file mode 100644 index 000000000..365156919 --- /dev/null +++ b/shell_integration/windows/NCUtil/Version.h @@ -0,0 +1,11 @@ +#pragma once + +// This is the number that will end up in the version window of the DLLs. +// Increment this version before committing a new build if you are today's shell_integration build master. +#define NCEXT_BUILD_NUM 47 + +#define STRINGIZE2(s) #s +#define STRINGIZE(s) STRINGIZE2(s) + +#define NCEXT_VERSION 3,0,0,NCEXT_BUILD_NUM +#define NCEXT_VERSION_STRING STRINGIZE(NCEXT_VERSION) diff --git a/shell_integration/windows/NCUtil/resource.h b/shell_integration/windows/NCUtil/resource.h new file mode 100644 index 000000000..c80f97834 --- /dev/null +++ b/shell_integration/windows/NCUtil/resource.h @@ -0,0 +1,14 @@ +//{{NO_DEPENDENCIES}} +// Microsoft Visual C++ generated include file. +// Used by NCContextMenu.rc + +// Next default values for new objects +// +#ifdef APSTUDIO_INVOKED +#ifndef APSTUDIO_READONLY_SYMBOLS +#define _APS_NEXT_RESOURCE_VALUE 101 +#define _APS_NEXT_COMMAND_VALUE 40001 +#define _APS_NEXT_CONTROL_VALUE 1001 +#define _APS_NEXT_SYMED_VALUE 101 +#endif +#endif diff --git a/shell_integration/windows/OCContextMenu/CMakeLists.txt b/shell_integration/windows/OCContextMenu/CMakeLists.txt deleted file mode 100644 index 74c12621b..000000000 --- a/shell_integration/windows/OCContextMenu/CMakeLists.txt +++ /dev/null @@ -1,17 +0,0 @@ -add_library(OCContextMenu MODULE - dllmain.cpp - OCClientInterface.cpp - OCContextMenu.cpp - OCContextMenuFactory.cpp - OCContextMenuRegHandler.cpp - OCContextMenu.rc - OCContextMenu.def -) - -target_link_libraries(OCContextMenu - OCUtil) - -install(TARGETS OCContextMenu - RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR} - LIBRARY DESTINATION ${CMAKE_INSTALL_BINDIR} -) diff --git a/shell_integration/windows/OCContextMenu/OCClientInterface.cpp b/shell_integration/windows/OCContextMenu/OCClientInterface.cpp deleted file mode 100644 index ad7a35564..000000000 --- a/shell_integration/windows/OCContextMenu/OCClientInterface.cpp +++ /dev/null @@ -1,93 +0,0 @@ -/** -* Copyright (c) 2015 Daniel Molkentin . All rights reserved. -* -* This library is free software; you can redistribute it and/or modify it under -* the terms of the GNU Lesser General Public License as published by the Free -* Software Foundation; either version 2.1 of the License, or (at your option) -* any later version. -* -* This library 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 Lesser General Public License for more -* details. -*/ - -#include "OCClientInterface.h" - -#include "CommunicationSocket.h" -#include "StringUtil.h" - -#include - -#include - -#include -#include -#include -#include -#include - -using namespace std; - -#define PIPE_TIMEOUT 5*1000 //ms - -OCClientInterface::ContextMenuInfo OCClientInterface::FetchInfo(const std::wstring &files) -{ - auto pipename = CommunicationSocket::DefaultPipePath(); - - CommunicationSocket socket; - if (!WaitNamedPipe(pipename.data(), PIPE_TIMEOUT)) { - return {}; - } - if (!socket.Connect(pipename)) { - return {}; - } - socket.SendMsg(L"GET_STRINGS:CONTEXT_MENU_TITLE\n"); - socket.SendMsg((L"GET_MENU_ITEMS:" + files + L"\n").data()); - - ContextMenuInfo info; - std::wstring response; - int sleptCount = 0; - while (sleptCount < 5) { - if (socket.ReadLine(&response)) { - if (StringUtil::begins_with(response, wstring(L"REGISTER_PATH:"))) { - wstring responsePath = response.substr(14); // length of REGISTER_PATH - info.watchedDirectories.push_back(responsePath); - } - else if (StringUtil::begins_with(response, wstring(L"STRING:"))) { - wstring stringName, stringValue; - if (!StringUtil::extractChunks(response, stringName, stringValue)) - continue; - if (stringName == L"CONTEXT_MENU_TITLE") - info.contextMenuTitle = move(stringValue); - } else if (StringUtil::begins_with(response, wstring(L"MENU_ITEM:"))) { - wstring commandName, flags, title; - if (!StringUtil::extractChunks(response, commandName, flags, title)) - continue; - info.menuItems.push_back({ commandName, flags, title }); - } else if (StringUtil::begins_with(response, wstring(L"GET_MENU_ITEMS:END"))) { - break; // Stop once we completely received the last sent request - } - } - else { - Sleep(50); - ++sleptCount; - } - } - return info; -} - -void OCClientInterface::SendRequest(const wchar_t *verb, const std::wstring &path) -{ - auto pipename = CommunicationSocket::DefaultPipePath(); - - CommunicationSocket socket; - if (!WaitNamedPipe(pipename.data(), PIPE_TIMEOUT)) { - return; - } - if (!socket.Connect(pipename)) { - return; - } - - socket.SendMsg((verb + (L":" + path + L"\n")).data()); -} diff --git a/shell_integration/windows/OCContextMenu/OCClientInterface.h b/shell_integration/windows/OCContextMenu/OCClientInterface.h deleted file mode 100644 index 586a03f2f..000000000 --- a/shell_integration/windows/OCContextMenu/OCClientInterface.h +++ /dev/null @@ -1,59 +0,0 @@ -/** -* Copyright (c) 2015 ownCloud GmbH. All rights reserved. -* -* This library is free software; you can redistribute it and/or modify it under -* the terms of the GNU Lesser General Public License as published by the Free -* Software Foundation; version 2.1 of the License -* -* This library 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 Lesser General Public License for more -* details. -*/ - -/** -* Copyright (c) 2014 ownCloud GmbH. All rights reserved. -* -* This library is free software; you can redistribute it and/or modify it under -* the terms of the GNU Lesser General Public License as published by the Free -* Software Foundation; version 2.1 of the License -* -* This library 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 Lesser General Public License for more -* details. -*/ - -#ifndef AbstractSocketHandler_H -#define AbstractSocketHandler_H - -#pragma once - -#include -#include -#include -#include -#include -#include -#include -#include - -class CommunicationSocket; - -class OCClientInterface -{ -public: - struct ContextMenuInfo { - std::vector watchedDirectories; - std::wstring contextMenuTitle; - struct MenuItem - { - std::wstring command, flags, title; - }; - std::vector menuItems; - }; - static ContextMenuInfo FetchInfo(const std::wstring &files); - static void SendRequest(const wchar_t *verb, const std::wstring &path); -}; - -#endif //ABSTRACTSOCKETHANDLER_H diff --git a/shell_integration/windows/OCContextMenu/OCContextMenu.cpp b/shell_integration/windows/OCContextMenu/OCContextMenu.cpp deleted file mode 100644 index 1e9168af5..000000000 --- a/shell_integration/windows/OCContextMenu/OCContextMenu.cpp +++ /dev/null @@ -1,232 +0,0 @@ -/** -* Copyright (c) 2015 Daniel Molkentin . All rights reserved. -* -* This library is free software; you can redistribute it and/or modify it under -* the terms of the GNU Lesser General Public License as published by the Free -* Software Foundation; either version 2.1 of the License, or (at your option) -* any later version. -* -* This library 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 Lesser General Public License for more -* details. -*/ - -#include "OCContextMenu.h" -#include "OCClientInterface.h" - -#include -#include -#include -#include -#include - -extern long g_cDllRef; - -OCContextMenu::OCContextMenu(void) - : m_cRef(1) -{ - InterlockedIncrement(&g_cDllRef); -} - -OCContextMenu::~OCContextMenu(void) -{ - InterlockedDecrement(&g_cDllRef); -} - -#pragma region IUnknown - -// Query to the interface the component supported. -IFACEMETHODIMP OCContextMenu::QueryInterface(REFIID riid, void **ppv) -{ - static const QITAB qit[] = - { - QITABENT(OCContextMenu, IContextMenu), - QITABENT(OCContextMenu, IShellExtInit), - { 0 }, - }; - return QISearch(this, qit, riid, ppv); -} - -// Increase the reference count for an interface on an object. -IFACEMETHODIMP_(ULONG) OCContextMenu::AddRef() -{ - return InterlockedIncrement(&m_cRef); -} - -// Decrease the reference count for an interface on an object. -IFACEMETHODIMP_(ULONG) OCContextMenu::Release() -{ - ULONG cRef = InterlockedDecrement(&m_cRef); - if (0 == cRef) { - delete this; - } - - return cRef; -} - -#pragma endregion - - -#pragma region IShellExtInit - -// Initialize the context menu handler. -IFACEMETHODIMP OCContextMenu::Initialize( - LPCITEMIDLIST pidlFolder, LPDATAOBJECT pDataObj, HKEY hKeyProgID) -{ - m_selectedFiles.clear(); - - if (!pDataObj) { - return E_INVALIDARG; - } - - FORMATETC fe = { CF_HDROP, nullptr, DVASPECT_CONTENT, -1, TYMED_HGLOBAL }; - STGMEDIUM stm; - - if (SUCCEEDED(pDataObj->GetData(&fe, &stm))) { - // Get an HDROP handle. - HDROP hDrop = static_cast(GlobalLock(stm.hGlobal)); - if (hDrop) { - UINT nFiles = DragQueryFile(hDrop, 0xFFFFFFFF, nullptr, 0); - for (UINT i = 0; i < nFiles; ++i) { - // Get the path of the file. - wchar_t buffer[MAX_PATH]; - - if (!DragQueryFile(hDrop, i, buffer, ARRAYSIZE(buffer))) { - m_selectedFiles.clear(); - break; - } - - if (i) - m_selectedFiles += L'\x1e'; - m_selectedFiles += buffer; - } - - GlobalUnlock(stm.hGlobal); - } - - ReleaseStgMedium(&stm); - } - - // If any value other than S_OK is returned from the method, the context - // menu item is not displayed. - return m_selectedFiles.empty() ? E_FAIL : S_OK; -} - -#pragma endregion - - -#pragma region IContextMenu - -void InsertSeperator(HMENU hMenu, UINT indexMenu) -{ - // Add a separator. - MENUITEMINFO sep = { sizeof(sep) }; - sep.fMask = MIIM_TYPE; - sep.fType = MFT_SEPARATOR; - InsertMenuItem(hMenu, indexMenu, TRUE, &sep); -} - -IFACEMETHODIMP OCContextMenu::QueryContextMenu(HMENU hMenu, UINT indexMenu, UINT idCmdFirst, UINT idCmdLast, UINT uFlags) -{ - // If uFlags include CMF_DEFAULTONLY then we should not do anything. - if (CMF_DEFAULTONLY & uFlags) - { - return MAKE_HRESULT(SEVERITY_SUCCESS, 0, USHORT(0)); - } - - m_info = OCClientInterface::FetchInfo(m_selectedFiles); - if (m_info.menuItems.empty()) { - return MAKE_HRESULT(SEVERITY_SUCCESS, 0, USHORT(0)); - } - - InsertSeperator(hMenu, indexMenu++); - - HMENU hSubmenu = CreateMenu(); - { - MENUITEMINFO mii = { sizeof(mii) }; - mii.fMask = MIIM_SUBMENU | MIIM_FTYPE | MIIM_STRING; - mii.hSubMenu = hSubmenu; - mii.fType = MFT_STRING; - mii.dwTypeData = &m_info.contextMenuTitle[0]; - - if (!InsertMenuItem(hMenu, indexMenu++, TRUE, &mii)) - return HRESULT_FROM_WIN32(GetLastError()); - } - InsertSeperator(hMenu, indexMenu++); - - UINT indexSubMenu = 0; - for (auto &item : m_info.menuItems) { - bool disabled = item.flags.find(L'd') != std::string::npos; - - MENUITEMINFO mii = { sizeof(mii) }; - mii.fMask = MIIM_ID | MIIM_FTYPE | MIIM_STRING | MIIM_STATE; - mii.wID = idCmdFirst + indexSubMenu; - mii.fType = MFT_STRING; - mii.dwTypeData = &item.title[0]; - mii.fState = disabled ? MFS_DISABLED : MFS_ENABLED; - - if (!InsertMenuItem(hSubmenu, indexSubMenu, true, &mii)) - return HRESULT_FROM_WIN32(GetLastError()); - indexSubMenu++; - } - - // Return an HRESULT value with the severity set to SEVERITY_SUCCESS. - // Set the code value to the offset of the largest command identifier - // that was assigned, plus one (1). - return MAKE_HRESULT(SEVERITY_SUCCESS, 0, USHORT(indexSubMenu)); -} - -IFACEMETHODIMP OCContextMenu::InvokeCommand(LPCMINVOKECOMMANDINFO pici) -{ - std::wstring command; - - CMINVOKECOMMANDINFOEX *piciEx = nullptr; - if (pici->cbSize == sizeof(CMINVOKECOMMANDINFOEX)) - piciEx = (CMINVOKECOMMANDINFOEX*)pici; - - // For the Unicode case, if the high-order word is not zero, the - // command's verb string is in lpcmi->lpVerbW. - if (piciEx - && (piciEx->fMask & CMIC_MASK_UNICODE) - && HIWORD(((CMINVOKECOMMANDINFOEX*)pici)->lpVerbW)) { - - command = piciEx->lpVerbW; - - // Verify that we handle the verb - bool handled = false; - for (auto &item : m_info.menuItems) { - if (item.command == command) { - handled = true; - break; - } - } - if (!handled) - return E_FAIL; - } else if (IS_INTRESOURCE(pici->lpVerb)) { - // If the command cannot be identified through the verb string, then - // check the identifier offset. - auto offset = LOWORD(pici->lpVerb); - if (offset >= m_info.menuItems.size()) - return E_FAIL; - - command = m_info.menuItems[offset].command; - } else { - return E_FAIL; - } - - OCClientInterface::SendRequest(command.data(), m_selectedFiles); - return S_OK; -} - -IFACEMETHODIMP OCContextMenu::GetCommandString(UINT_PTR idCommand, - UINT uFlags, UINT *pwReserved, LPSTR pszName, UINT cchMax) -{ - if (idCommand < m_info.menuItems.size() && uFlags == GCS_VERBW) { - return StringCchCopyW(reinterpret_cast(pszName), cchMax, - m_info.menuItems[idCommand].command.data()); - } - return E_INVALIDARG; -} - -#pragma endregion diff --git a/shell_integration/windows/OCContextMenu/OCContextMenu.def b/shell_integration/windows/OCContextMenu/OCContextMenu.def deleted file mode 100644 index 8cde2bd02..000000000 --- a/shell_integration/windows/OCContextMenu/OCContextMenu.def +++ /dev/null @@ -1,6 +0,0 @@ -LIBRARY -EXPORTS - DllGetClassObject PRIVATE - DllCanUnloadNow PRIVATE - DllRegisterServer PRIVATE - DllUnregisterServer PRIVATE \ No newline at end of file diff --git a/shell_integration/windows/OCContextMenu/OCContextMenu.h b/shell_integration/windows/OCContextMenu/OCContextMenu.h deleted file mode 100644 index e8836d6fe..000000000 --- a/shell_integration/windows/OCContextMenu/OCContextMenu.h +++ /dev/null @@ -1,53 +0,0 @@ -/** -* Copyright (c) 2015 Daniel Molkentin . All rights reserved. -* -* This library is free software; you can redistribute it and/or modify it under -* the terms of the GNU Lesser General Public License as published by the Free -* Software Foundation; either version 2.1 of the License, or (at your option) -* any later version. -* -* This library 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 Lesser General Public License for more -* details. -*/ - -#ifndef OCCONTEXTMENU_H -#define OCCONTEXTMENU_H - -#pragma once -#include // For IShellExtInit and IContextMenu -#include -#include "OCClientInterface.h" - -class OCContextMenu : public IShellExtInit, public IContextMenu -{ -public: - // IUnknown - IFACEMETHODIMP QueryInterface(REFIID riid, void **ppv); - IFACEMETHODIMP_(ULONG) AddRef(); - IFACEMETHODIMP_(ULONG) Release(); - - // IShellExtInit - IFACEMETHODIMP Initialize(LPCITEMIDLIST pidlFolder, LPDATAOBJECT pDataObj, HKEY hKeyProgID); - - // IContextMenu - IFACEMETHODIMP QueryContextMenu(HMENU hMenu, UINT indexMenu, UINT idCmdFirst, UINT idCmdLast, UINT uFlags); - IFACEMETHODIMP InvokeCommand(LPCMINVOKECOMMANDINFO pici); - IFACEMETHODIMP GetCommandString(UINT_PTR idCommand, UINT uFlags, UINT *pwReserved, LPSTR pszName, UINT cchMax); - - OCContextMenu(); - -protected: - ~OCContextMenu(); - -private: - // Reference count of component. - long m_cRef; - - // The name of the selected files (separated by '\x1e') - std::wstring m_selectedFiles; - OCClientInterface::ContextMenuInfo m_info; -}; - -#endif //OCCONTEXTMENU_H diff --git a/shell_integration/windows/OCContextMenu/OCContextMenu.rc b/shell_integration/windows/OCContextMenu/OCContextMenu.rc deleted file mode 100644 index c09944f14..000000000 Binary files a/shell_integration/windows/OCContextMenu/OCContextMenu.rc and /dev/null differ diff --git a/shell_integration/windows/OCContextMenu/OCContextMenuFactory.cpp b/shell_integration/windows/OCContextMenu/OCContextMenuFactory.cpp deleted file mode 100644 index e3e6ff6b6..000000000 --- a/shell_integration/windows/OCContextMenu/OCContextMenuFactory.cpp +++ /dev/null @@ -1,89 +0,0 @@ -/** -* Copyright (c) 2015 Daniel Molkentin . All rights reserved. -* -* This library is free software; you can redistribute it and/or modify it under -* the terms of the GNU Lesser General Public License as published by the Free -* Software Foundation; either version 2.1 of the License, or (at your option) -* any later version. -* -* This library 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 Lesser General Public License for more -* details. -*/ - -#include "OCContextMenuFactory.h" -#include "OCContextMenu.h" -#include -#include -#pragma comment(lib, "shlwapi.lib") - - -extern long g_cDllRef; - - -OCContextMenuFactory::OCContextMenuFactory() : m_cRef(1) -{ - InterlockedIncrement(&g_cDllRef); -} - -OCContextMenuFactory::~OCContextMenuFactory() -{ - InterlockedDecrement(&g_cDllRef); -} - - -// IUnknown methods - -IFACEMETHODIMP OCContextMenuFactory::QueryInterface(REFIID riid, void **ppv) -{ - static const QITAB qit[] = { QITABENT(OCContextMenuFactory, IClassFactory), { 0 }, }; - return QISearch(this, qit, riid, ppv); -} - -IFACEMETHODIMP_(ULONG) OCContextMenuFactory::AddRef() -{ - return InterlockedIncrement(&m_cRef); -} - -IFACEMETHODIMP_(ULONG) OCContextMenuFactory::Release() -{ - ULONG cRef = InterlockedDecrement(&m_cRef); - if (0 == cRef) { - delete this; - } - return cRef; -} - - -// IClassFactory methods - -IFACEMETHODIMP OCContextMenuFactory::CreateInstance(IUnknown *pUnkOuter, REFIID riid, void **ppv) -{ - HRESULT hr = CLASS_E_NOAGGREGATION; - - // pUnkOuter is used for aggregation. We do not support it in the sample. - if (!pUnkOuter) { - hr = E_OUTOFMEMORY; - - // Create the COM component. - OCContextMenu *pExt = new (std::nothrow) OCContextMenu(); - if (pExt) { - // Query the specified interface. - hr = pExt->QueryInterface(riid, ppv); - pExt->Release(); - } - } - - return hr; -} - -IFACEMETHODIMP OCContextMenuFactory::LockServer(BOOL fLock) -{ - if (fLock) { - InterlockedIncrement(&g_cDllRef); - } else { - InterlockedDecrement(&g_cDllRef); - } - return S_OK; -} diff --git a/shell_integration/windows/OCContextMenu/OCContextMenuFactory.h b/shell_integration/windows/OCContextMenu/OCContextMenuFactory.h deleted file mode 100644 index 13f4d6759..000000000 --- a/shell_integration/windows/OCContextMenu/OCContextMenuFactory.h +++ /dev/null @@ -1,42 +0,0 @@ -/** -* Copyright (c) 2015 Daniel Molkentin . All rights reserved. -* -* This library is free software; you can redistribute it and/or modify it under -* the terms of the GNU Lesser General Public License as published by the Free -* Software Foundation; either version 2.1 of the License, or (at your option) -* any later version. -* -* This library 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 Lesser General Public License for more -* details. -*/ - - -#ifndef OCCONTEXTMENUFACTORY_H -#define OCCONTEXTMENUFACTORY_H - -#pragma once - -#include // For IClassFactory - -class OCContextMenuFactory : public IClassFactory -{ -public: - // IUnknown - IFACEMETHODIMP QueryInterface(REFIID riid, void **ppv); - IFACEMETHODIMP_(ULONG) AddRef(); - IFACEMETHODIMP_(ULONG) Release(); - - // IClassFactory - IFACEMETHODIMP CreateInstance(IUnknown *pUnkOuter, REFIID riid, void **ppv); - IFACEMETHODIMP LockServer(BOOL fLock); - - OCContextMenuFactory(); - -private: - ~OCContextMenuFactory(); - long m_cRef; -}; - -#endif //OCCONTEXTMENUFACTORY_H \ No newline at end of file diff --git a/shell_integration/windows/OCContextMenu/OCContextMenuRegHandler.cpp b/shell_integration/windows/OCContextMenu/OCContextMenuRegHandler.cpp deleted file mode 100644 index 43fb46a3b..000000000 --- a/shell_integration/windows/OCContextMenu/OCContextMenuRegHandler.cpp +++ /dev/null @@ -1,216 +0,0 @@ -/** -* Copyright (c) 2015 Daniel Molkentin . All rights reserved. -* -* This library is free software; you can redistribute it and/or modify it under -* the terms of the GNU Lesser General Public License as published by the Free -* Software Foundation; either version 2.1 of the License, or (at your option) -* any later version. -* -* This library 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 Lesser General Public License for more -* details. -*/ - -#include "OCContextMenuRegHandler.h" -#include "RegDelnode.h" -#include -#include - -namespace { - -HRESULT SetHKCRRegistryKeyAndValue(PCWSTR pszSubKey, PCWSTR pszValueName, PCWSTR pszData) -{ - HRESULT hr; - HKEY hKey = nullptr; - - // Creates the specified registry key. If the key already exists, the - // function opens it. - hr = HRESULT_FROM_WIN32(RegCreateKeyEx(HKEY_CLASSES_ROOT, pszSubKey, 0, - nullptr, REG_OPTION_NON_VOLATILE, KEY_WRITE, nullptr, &hKey, nullptr)); - - if (SUCCEEDED(hr)) - { - if (pszData) - { - // Set the specified value of the key. - DWORD cbData = lstrlen(pszData) * sizeof(*pszData); - hr = HRESULT_FROM_WIN32(RegSetValueEx(hKey, pszValueName, 0, - REG_SZ, reinterpret_cast(pszData), cbData)); - } - - RegCloseKey(hKey); - } - - return hr; -} - -HRESULT GetHKCRRegistryKeyAndValue(PCWSTR pszSubKey, PCWSTR pszValueName, PWSTR pszData, DWORD cbData) -{ - HRESULT hr; - HKEY hKey = nullptr; - - // Try to open the specified registry key. - hr = HRESULT_FROM_WIN32(RegOpenKeyEx(HKEY_CLASSES_ROOT, pszSubKey, 0, - KEY_READ, &hKey)); - - if (SUCCEEDED(hr)) - { - // Get the data for the specified value name. - hr = HRESULT_FROM_WIN32(RegQueryValueEx(hKey, pszValueName, nullptr, - nullptr, reinterpret_cast(pszData), &cbData)); - - RegCloseKey(hKey); - } - - return hr; -} - -} - -HRESULT OCContextMenuRegHandler::RegisterInprocServer(PCWSTR pszModule, const CLSID& clsid, PCWSTR pszFriendlyName, PCWSTR pszThreadModel) -{ - if (!pszModule || !pszThreadModel) - { - return E_INVALIDARG; - } - - HRESULT hr; - - wchar_t szCLSID[MAX_PATH]; - StringFromGUID2(clsid, szCLSID, ARRAYSIZE(szCLSID)); - - wchar_t szSubkey[MAX_PATH]; - - // Create the HKCR\CLSID\{} key. - hr = StringCchPrintf(szSubkey, ARRAYSIZE(szSubkey), LR"(CLSID\%s)", szCLSID); - if (SUCCEEDED(hr)) - { - hr = SetHKCRRegistryKeyAndValue(szSubkey, nullptr, pszFriendlyName); - - // Create the HKCR\CLSID\{}\InprocServer32 key. - if (SUCCEEDED(hr)) - { - hr = StringCchPrintf(szSubkey, ARRAYSIZE(szSubkey), - LR"(CLSID\%s\InprocServer32)", szCLSID); - if (SUCCEEDED(hr)) - { - // Set the default value of the InprocServer32 key to the - // path of the COM module. - hr = SetHKCRRegistryKeyAndValue(szSubkey, nullptr, pszModule); - if (SUCCEEDED(hr)) - { - // Set the threading model of the component. - hr = SetHKCRRegistryKeyAndValue(szSubkey, - L"ThreadingModel", pszThreadModel); - } - } - } - } - - return hr; -} - -HRESULT OCContextMenuRegHandler::UnregisterInprocServer(const CLSID& clsid) -{ - HRESULT hr = S_OK; - - wchar_t szCLSID[MAX_PATH]; - StringFromGUID2(clsid, szCLSID, ARRAYSIZE(szCLSID)); - - wchar_t szSubkey[MAX_PATH]; - - // Delete the HKCR\CLSID\{} key. - hr = StringCchPrintf(szSubkey, ARRAYSIZE(szSubkey), LR"(CLSID\%s)", szCLSID); - if (SUCCEEDED(hr)) - { - hr = HRESULT_FROM_WIN32(RegDelnode(HKEY_CLASSES_ROOT, szSubkey)); - } - - return hr; -} - - -HRESULT OCContextMenuRegHandler::RegisterShellExtContextMenuHandler( - PCWSTR pszFileType, const CLSID& clsid, PCWSTR pszFriendlyName) -{ - if (!pszFileType) - { - return E_INVALIDARG; - } - - HRESULT hr; - - wchar_t szCLSID[MAX_PATH]; - StringFromGUID2(clsid, szCLSID, ARRAYSIZE(szCLSID)); - - wchar_t szSubkey[MAX_PATH]; - - // If pszFileType starts with '.', try to read the default value of the - // HKCR\ key which contains the ProgID to which the file type - // is linked. - if (*pszFileType == L'.') - { - wchar_t szDefaultVal[260]; - hr = GetHKCRRegistryKeyAndValue(pszFileType, nullptr, szDefaultVal, - sizeof(szDefaultVal)); - - // If the key exists and its default value is not empty, use the - // ProgID as the file type. - if (SUCCEEDED(hr) && szDefaultVal[0] != L'\0') - { - pszFileType = szDefaultVal; - } - } - - // Create the key HKCR\\shellex\ContextMenuHandlers\{friendlyName>} - hr = StringCchPrintf(szSubkey, ARRAYSIZE(szSubkey), - LR"(%s\shellex\ContextMenuHandlers\%s)", pszFileType, pszFriendlyName); - if (SUCCEEDED(hr)) - { - // Set the default value of the key. - hr = SetHKCRRegistryKeyAndValue(szSubkey, nullptr, szCLSID); - } - - return hr; -} - -HRESULT OCContextMenuRegHandler::UnregisterShellExtContextMenuHandler( - PCWSTR pszFileType, PCWSTR pszFriendlyName) -{ - if (!pszFileType) - { - return E_INVALIDARG; - } - - HRESULT hr; - - wchar_t szSubkey[MAX_PATH]; - - // If pszFileType starts with '.', try to read the default value of the - // HKCR\ key which contains the ProgID to which the file type - // is linked. - if (*pszFileType == L'.') - { - wchar_t szDefaultVal[260]; - hr = GetHKCRRegistryKeyAndValue(pszFileType, nullptr, szDefaultVal, - sizeof(szDefaultVal)); - - // If the key exists and its default value is not empty, use the - // ProgID as the file type. - if (SUCCEEDED(hr) && szDefaultVal[0] != L'\0') - { - pszFileType = szDefaultVal; - } - } - - // Remove the HKCR\\shellex\ContextMenuHandlers\{friendlyName} key. - hr = StringCchPrintf(szSubkey, ARRAYSIZE(szSubkey), - LR"(%s\shellex\ContextMenuHandlers\%s)", pszFileType, pszFriendlyName); - if (SUCCEEDED(hr)) - { - hr = HRESULT_FROM_WIN32(RegDelnode(HKEY_CLASSES_ROOT, szSubkey)); - } - - return hr; -} diff --git a/shell_integration/windows/OCContextMenu/OCContextMenuRegHandler.h b/shell_integration/windows/OCContextMenu/OCContextMenuRegHandler.h deleted file mode 100644 index 91c2c9e81..000000000 --- a/shell_integration/windows/OCContextMenu/OCContextMenuRegHandler.h +++ /dev/null @@ -1,38 +0,0 @@ -/** -* Copyright (c) 2015 Daniel Molkentin . All rights reserved. -* -* This library is free software; you can redistribute it and/or modify it under -* the terms of the GNU Lesser General Public License as published by the Free -* Software Foundation; either version 2.1 of the License, or (at your option) -* any later version. -* -* This library 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 Lesser General Public License for more -* details. -*/ - - -#ifndef OCCONTEXTMENUREGHANDLER_H -#define OCCONTEXTMENUREGHANDLER_H - -#pragma once - -#include - -class __declspec(dllexport) OCContextMenuRegHandler -{ -public: - static HRESULT MakeRegistryEntries(const CLSID& clsid, PCWSTR fileType); - static HRESULT RegisterCOMObject(PCWSTR modulePath, PCWSTR friendlyName, const CLSID& clsid); - static HRESULT RemoveRegistryEntries(PCWSTR friendlyName); - static HRESULT UnregisterCOMObject(const CLSID& clsid); - - static HRESULT RegisterInprocServer(PCWSTR pszModule, const CLSID& clsid, PCWSTR pszFriendlyName, PCWSTR pszThreadModel); - static HRESULT UnregisterInprocServer(const CLSID& clsid); - - static HRESULT RegisterShellExtContextMenuHandler(PCWSTR pszFileType, const CLSID& clsid, PCWSTR pszFriendlyName); - static HRESULT UnregisterShellExtContextMenuHandler(PCWSTR pszFileType, PCWSTR pszFriendlyName); -}; - -#endif //OCCONTEXTMENUREGHANDLER_H \ No newline at end of file diff --git a/shell_integration/windows/OCContextMenu/RegDelnode.h b/shell_integration/windows/OCContextMenu/RegDelnode.h deleted file mode 100644 index f79d1dcca..000000000 --- a/shell_integration/windows/OCContextMenu/RegDelnode.h +++ /dev/null @@ -1,114 +0,0 @@ -#pragma once - -#include -#include -#include - -// Stolen from the "Deleting a Key with Subkeys" example to replace -// RegDeleteTree which isn't available on WinXP. -// https://msdn.microsoft.com/en-us/library/ms724235(VS.85).aspx - -//************************************************************* -// -// RegDelnodeRecurse() -// -// Purpose: Deletes a registry key and all its subkeys / values. -// -// Parameters: hKeyRoot - Root key -// lpSubKey - SubKey to delete -// -// Return: TRUE if successful. -// FALSE if an error occurs. -// -//************************************************************* - -HRESULT RegDelnodeRecurse(HKEY hKeyRoot, LPTSTR lpSubKey) -{ - LPTSTR lpEnd; - LONG lResult; - DWORD dwSize; - TCHAR szName[MAX_PATH]; - HKEY hKey; - FILETIME ftWrite; - - // First, see if we can delete the key without having - // to recurse. - - lResult = RegDeleteKey(hKeyRoot, lpSubKey); - - if (lResult == ERROR_SUCCESS) - return lResult; - - lResult = RegOpenKeyEx(hKeyRoot, lpSubKey, 0, KEY_READ, &hKey); - - if (lResult != ERROR_SUCCESS) - return lResult; - - // Check for an ending slash and add one if it is missing. - - lpEnd = lpSubKey + lstrlen(lpSubKey); - - if (*(lpEnd - 1) != TEXT('\\')) - { - *lpEnd = TEXT('\\'); - lpEnd++; - *lpEnd = TEXT('\0'); - } - - // Enumerate the keys - - dwSize = MAX_PATH; - lResult = RegEnumKeyEx(hKey, 0, szName, &dwSize, nullptr, - nullptr, nullptr, &ftWrite); - - if (lResult == ERROR_SUCCESS) - { - do { - - StringCchCopy(lpEnd, MAX_PATH * 2, szName); - - if (RegDelnodeRecurse(hKeyRoot, lpSubKey) != ERROR_SUCCESS) { - break; - } - - dwSize = MAX_PATH; - - lResult = RegEnumKeyEx(hKey, 0, szName, &dwSize, nullptr, - nullptr, nullptr, &ftWrite); - - } while (lResult == ERROR_SUCCESS); - } - - lpEnd--; - *lpEnd = TEXT('\0'); - - RegCloseKey(hKey); - - // Try again to delete the key. - - lResult = RegDeleteKey(hKeyRoot, lpSubKey); - return lResult; -} - -//************************************************************* -// -// RegDelnode() -// -// Purpose: Deletes a registry key and all its subkeys / values. -// -// Parameters: hKeyRoot - Root key -// lpSubKey - SubKey to delete -// -// Return: TRUE if successful. -// FALSE if an error occurs. -// -//************************************************************* - -HRESULT RegDelnode(HKEY hKeyRoot, LPTSTR lpSubKey) -{ - TCHAR szDelKey[MAX_PATH * 2]; - - StringCchCopy(szDelKey, MAX_PATH * 2, lpSubKey); - return RegDelnodeRecurse(hKeyRoot, szDelKey); - -} diff --git a/shell_integration/windows/OCContextMenu/dllmain.cpp b/shell_integration/windows/OCContextMenu/dllmain.cpp deleted file mode 100644 index b6f1a11db..000000000 --- a/shell_integration/windows/OCContextMenu/dllmain.cpp +++ /dev/null @@ -1,110 +0,0 @@ -/** -* Copyright (c) 2015 Daniel Molkentin . All rights reserved. -* -* This library is free software; you can redistribute it and/or modify it under -* the terms of the GNU Lesser General Public License as published by the Free -* Software Foundation; either version 2.1 of the License, or (at your option) -* any later version. -* -* This library 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 Lesser General Public License for more -* details. -*/ - -#include -#include -#include "OCContextMenuRegHandler.h" -#include "OCContextMenuFactory.h" -#include "WinShellExtConstants.h" - -HINSTANCE g_hInst = nullptr; -long g_cDllRef = 0; - -BOOL APIENTRY DllMain(HMODULE hModule, DWORD dwReason, LPVOID lpReserved) -{ - switch (dwReason) - { - case DLL_PROCESS_ATTACH: - // Hold the instance of this DLL module, we will use it to get the - // path of the DLL to register the component. - g_hInst = hModule; - DisableThreadLibraryCalls(hModule); - break; - case DLL_THREAD_ATTACH: - case DLL_THREAD_DETACH: - case DLL_PROCESS_DETACH: - break; - } - return TRUE; -} - -STDAPI DllGetClassObject(REFCLSID rclsid, REFIID riid, void **ppv) -{ - HRESULT hr = CLASS_E_CLASSNOTAVAILABLE; - GUID guid; - - hr = CLSIDFromString(CONTEXT_MENU_GUID, (LPCLSID)&guid); - if (!SUCCEEDED(hr)) { - return hr; - } - - if (IsEqualCLSID(guid, rclsid)) { - hr = E_OUTOFMEMORY; - - OCContextMenuFactory *pClassFactory = new OCContextMenuFactory(); - if (pClassFactory) { - hr = pClassFactory->QueryInterface(riid, ppv); - pClassFactory->Release(); - } - } - - return hr; -} - -STDAPI DllCanUnloadNow(void) -{ - return g_cDllRef > 0 ? S_FALSE : S_OK; -} - -STDAPI DllRegisterServer(void) -{ - HRESULT hr; - - wchar_t szModule[MAX_PATH]; - if (GetModuleFileName(g_hInst, szModule, ARRAYSIZE(szModule)) == 0) { - hr = HRESULT_FROM_WIN32(GetLastError()); - return hr; - } - - // Register the component. - hr = OCContextMenuRegHandler::RegisterInprocServer(szModule, CLSID_FileContextMenuExt, - L"OCContextMenuHandler Class", L"Apartment"); - if (SUCCEEDED(hr)) { - // Register the context menu handler. The context menu handler is - // associated with the .cpp file class. - hr = OCContextMenuRegHandler::RegisterShellExtContextMenuHandler(L"AllFileSystemObjects", CLSID_FileContextMenuExt, L"OCContextMenuHandler"); - } - - return hr; -} - -STDAPI DllUnregisterServer(void) -{ - HRESULT hr = S_OK; - - wchar_t szModule[MAX_PATH]; - if (GetModuleFileName(g_hInst, szModule, ARRAYSIZE(szModule)) == 0) { - hr = HRESULT_FROM_WIN32(GetLastError()); - return hr; - } - - // Unregister the component. - hr = OCContextMenuRegHandler::UnregisterInprocServer(CLSID_FileContextMenuExt); - if (SUCCEEDED(hr)) { - // Unregister the context menu handler. - hr = OCContextMenuRegHandler::UnregisterShellExtContextMenuHandler(L"AllFileSystemObjects", L"OCContextMenuHandler"); - } - - return hr; -} diff --git a/shell_integration/windows/OCContextMenu/resource.h b/shell_integration/windows/OCContextMenu/resource.h deleted file mode 100644 index b9407b5bc..000000000 --- a/shell_integration/windows/OCContextMenu/resource.h +++ /dev/null @@ -1,14 +0,0 @@ -//{{NO_DEPENDENCIES}} -// Microsoft Visual C++ generated include file. -// Used by OCContextMenu.rc - -// Next default values for new objects -// -#ifdef APSTUDIO_INVOKED -#ifndef APSTUDIO_READONLY_SYMBOLS -#define _APS_NEXT_RESOURCE_VALUE 101 -#define _APS_NEXT_COMMAND_VALUE 40001 -#define _APS_NEXT_CONTROL_VALUE 1001 -#define _APS_NEXT_SYMED_VALUE 101 -#endif -#endif diff --git a/shell_integration/windows/OCOverlays/CMakeLists.txt b/shell_integration/windows/OCOverlays/CMakeLists.txt deleted file mode 100644 index 60d4a3748..000000000 --- a/shell_integration/windows/OCOverlays/CMakeLists.txt +++ /dev/null @@ -1,16 +0,0 @@ -add_library(OCOverlays MODULE - DllMain.cpp - OCOverlay.cpp - OCOverlayFactory.cpp - OCOverlayRegistrationHandler.cpp - OCOverlay.rc - OCOverlays.def -) - -target_link_libraries(OCOverlays - OCUtil) - -install(TARGETS OCOverlays - RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR} - LIBRARY DESTINATION ${CMAKE_INSTALL_BINDIR} -) diff --git a/shell_integration/windows/OCOverlays/DllMain.cpp b/shell_integration/windows/OCOverlays/DllMain.cpp deleted file mode 100644 index 8f6cff497..000000000 --- a/shell_integration/windows/OCOverlays/DllMain.cpp +++ /dev/null @@ -1,184 +0,0 @@ -/** - * Copyright (c) 2000-2013 Liferay, Inc. All rights reserved. - * - * This library is free software; you can redistribute it and/or modify it under - * the terms of the GNU Lesser General Public License as published by the Free - * Software Foundation; either version 2.1 of the License, or (at your option) - * any later version. - * - * This library 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 Lesser General Public License for more - * details. - */ - -#include "OCOverlayRegistrationHandler.h" -#include "OCOverlayFactory.h" -#include "WinShellExtConstants.h" - -HINSTANCE instanceHandle = nullptr; - -long dllReferenceCount = 0; - -BOOL APIENTRY DllMain(HMODULE hModule, DWORD dwReason, LPVOID lpReserved) -{ - switch (dwReason) - { - case DLL_PROCESS_ATTACH: - instanceHandle = hModule; - DisableThreadLibraryCalls(hModule); - break; - case DLL_THREAD_ATTACH: - case DLL_THREAD_DETACH: - case DLL_PROCESS_DETACH: - break; - } - - return TRUE; -} - -HRESULT CreateFactory(REFIID riid, void **ppv, int state) -{ - HRESULT hResult = E_OUTOFMEMORY; - - OCOverlayFactory* ocOverlayFactory = new OCOverlayFactory(state); - - if (ocOverlayFactory) { - hResult = ocOverlayFactory->QueryInterface(riid, ppv); - ocOverlayFactory->Release(); - } - return hResult; -} - -STDAPI DllGetClassObject(REFCLSID rclsid, REFIID riid, void **ppv) -{ - HRESULT hResult = CLASS_E_CLASSNOTAVAILABLE; - GUID guid; - - hResult = CLSIDFromString(OVERLAY_GUID_ERROR, (LPCLSID)&guid); - if (!SUCCEEDED(hResult)) { return hResult; } - if (IsEqualCLSID(guid, rclsid)) { return CreateFactory(riid, ppv, State_Error); } - - hResult = CLSIDFromString(OVERLAY_GUID_OK, (LPCLSID)&guid); - if (!SUCCEEDED(hResult)) { return hResult; } - if (IsEqualCLSID(guid, rclsid)) { return CreateFactory(riid, ppv, State_OK); } - - hResult = CLSIDFromString(OVERLAY_GUID_OK_SHARED, (LPCLSID)&guid); - if (!SUCCEEDED(hResult)) { return hResult; } - if (IsEqualCLSID(guid, rclsid)) { return CreateFactory(riid, ppv, State_OKShared); } - - hResult = CLSIDFromString(OVERLAY_GUID_SYNC, (LPCLSID)&guid); - if (!SUCCEEDED(hResult)) { return hResult; } - if (IsEqualCLSID(guid, rclsid)) { return CreateFactory(riid, ppv, State_Sync); } - - hResult = CLSIDFromString(OVERLAY_GUID_WARNING, (LPCLSID)&guid); - if (!SUCCEEDED(hResult)) { return hResult; } - if (IsEqualCLSID(guid, rclsid)) { return CreateFactory(riid, ppv, State_Warning); } - - return CLASS_E_CLASSNOTAVAILABLE; -} - -STDAPI DllCanUnloadNow(void) -{ - return dllReferenceCount > 0 ? S_FALSE : S_OK; -} - -HRESULT RegisterCLSID(LPCOLESTR guidStr, PCWSTR overlayStr, PCWSTR szModule) -{ - HRESULT hResult = S_OK; - - GUID guid; - hResult = CLSIDFromString(guidStr, (LPCLSID)&guid); - - if (hResult != S_OK) { - return hResult; - } - - hResult = OCOverlayRegistrationHandler::RegisterCOMObject(szModule, OVERLAY_GENERIC_NAME, guid); - - if (!SUCCEEDED(hResult)) { - return hResult; - } - - hResult = OCOverlayRegistrationHandler::MakeRegistryEntries(guid, overlayStr); - - return hResult; -} - -HRESULT UnregisterCLSID(LPCOLESTR guidStr, PCWSTR overlayStr) -{ - HRESULT hResult = S_OK; - GUID guid; - - hResult = CLSIDFromString(guidStr, (LPCLSID)&guid); - - if (hResult != S_OK) { - return hResult; - } - - hResult = OCOverlayRegistrationHandler::UnregisterCOMObject(guid); - - if (!SUCCEEDED(hResult)) { - return hResult; - } - - hResult = OCOverlayRegistrationHandler::RemoveRegistryEntries(overlayStr); - - return hResult; -} - -HRESULT _stdcall DllRegisterServer(void) -{ - HRESULT hResult = S_OK; - - wchar_t szModule[MAX_PATH]; - - if (GetModuleFileName(instanceHandle, szModule, ARRAYSIZE(szModule)) == 0) { - hResult = HRESULT_FROM_WIN32(GetLastError()); - return hResult; - } - - // Unregister any obsolete CLSID when we register here - // Those CLSID were removed in 2.1, but we need to make sure to prevent any previous version - // of the extension on the system from loading at the same time as a new version to avoid crashing explorer. - UnregisterCLSID(OVERLAY_GUID_ERROR_SHARED, OVERLAY_NAME_ERROR_SHARED); - UnregisterCLSID(OVERLAY_GUID_SYNC_SHARED, OVERLAY_NAME_SYNC_SHARED); - UnregisterCLSID(OVERLAY_GUID_WARNING_SHARED, OVERLAY_NAME_WARNING_SHARED); - - hResult = RegisterCLSID(OVERLAY_GUID_ERROR, OVERLAY_NAME_ERROR, szModule); - if (!SUCCEEDED(hResult)) { return hResult; } - hResult = RegisterCLSID(OVERLAY_GUID_OK, OVERLAY_NAME_OK, szModule); - if (!SUCCEEDED(hResult)) { return hResult; } - hResult = RegisterCLSID(OVERLAY_GUID_OK_SHARED, OVERLAY_NAME_OK_SHARED, szModule); - if (!SUCCEEDED(hResult)) { return hResult; } - hResult = RegisterCLSID(OVERLAY_GUID_SYNC, OVERLAY_NAME_SYNC, szModule); - if (!SUCCEEDED(hResult)) { return hResult; } - hResult = RegisterCLSID(OVERLAY_GUID_WARNING, OVERLAY_NAME_WARNING, szModule); - - return hResult; -} - -STDAPI DllUnregisterServer(void) -{ - HRESULT hResult = S_OK; - - wchar_t szModule[MAX_PATH]; - - if (GetModuleFileNameW(instanceHandle, szModule, ARRAYSIZE(szModule)) == 0) - { - hResult = HRESULT_FROM_WIN32(GetLastError()); - return hResult; - } - - hResult = UnregisterCLSID(OVERLAY_GUID_ERROR, OVERLAY_NAME_ERROR); - if (!SUCCEEDED(hResult)) { return hResult; } - hResult = UnregisterCLSID(OVERLAY_GUID_OK, OVERLAY_NAME_OK); - if (!SUCCEEDED(hResult)) { return hResult; } - hResult = UnregisterCLSID(OVERLAY_GUID_OK_SHARED, OVERLAY_NAME_OK_SHARED); - if (!SUCCEEDED(hResult)) { return hResult; } - hResult = UnregisterCLSID(OVERLAY_GUID_SYNC, OVERLAY_NAME_SYNC); - if (!SUCCEEDED(hResult)) { return hResult; } - hResult = UnregisterCLSID(OVERLAY_GUID_WARNING, OVERLAY_NAME_WARNING); - - return hResult; -} diff --git a/shell_integration/windows/OCOverlays/OCOverlay.cpp b/shell_integration/windows/OCOverlays/OCOverlay.cpp deleted file mode 100644 index 985faec54..000000000 --- a/shell_integration/windows/OCOverlays/OCOverlay.cpp +++ /dev/null @@ -1,165 +0,0 @@ -/** - * Copyright (c) 2000-2013 Liferay, Inc. All rights reserved. - * - * This library is free software; you can redistribute it and/or modify it under - * the terms of the GNU Lesser General Public License as published by the Free - * Software Foundation; either version 2.1 of the License, or (at your option) - * any later version. - * - * This library 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 Lesser General Public License for more - * details. - */ - -#include "OCOverlay.h" - -#include "OCOverlayFactory.h" -#include "StringUtil.h" - -#include "UtilConstants.h" -#include "RemotePathChecker.h" - -#include -#include -#include -#include - -using namespace std; - -#pragma comment(lib, "shlwapi.lib") - -extern HINSTANCE instanceHandle; - -#define IDM_DISPLAY 0 -#define IDB_OK 101 - -namespace { - -unique_ptr s_instance; - -RemotePathChecker *getGlobalChecker() -{ - // On Vista we'll run into issue #2680 if we try to create the thread+pipe connection - // on any DllGetClassObject of our registered classes. - // Work around the issue by creating the static RemotePathChecker only once actually needed. - static once_flag s_onceFlag; - call_once(s_onceFlag, [] { s_instance.reset(new RemotePathChecker); }); - - return s_instance.get(); -} - -} -OCOverlay::OCOverlay(int state) - : _referenceCount(1) - , _state(state) -{ -} - -OCOverlay::~OCOverlay(void) -{ -} - - -IFACEMETHODIMP_(ULONG) OCOverlay::AddRef() -{ - return InterlockedIncrement(&_referenceCount); -} - -IFACEMETHODIMP OCOverlay::QueryInterface(REFIID riid, void **ppv) -{ - HRESULT hr = S_OK; - - if (IsEqualIID(IID_IUnknown, riid) || IsEqualIID(IID_IShellIconOverlayIdentifier, riid)) - { - *ppv = static_cast(this); - } - else - { - hr = E_NOINTERFACE; - *ppv = nullptr; - } - - if (*ppv) - { - AddRef(); - } - - return hr; -} - -IFACEMETHODIMP_(ULONG) OCOverlay::Release() -{ - ULONG cRef = InterlockedDecrement(&_referenceCount); - if (0 == cRef) - { - delete this; - } - - return cRef; -} - -IFACEMETHODIMP OCOverlay::GetPriority(int *pPriority) -{ - // this defines which handler has prededence, so - // we order this in terms of likelyhood - switch (_state) { - case State_OK: - *pPriority = 0; break; - case State_OKShared: - *pPriority = 1; break; - case State_Warning: - *pPriority = 2; break; - case State_Sync: - *pPriority = 3; break; - case State_Error: - *pPriority = 4; break; - default: - *pPriority = 5; break; - } - - return S_OK; -} - -IFACEMETHODIMP OCOverlay::IsMemberOf(PCWSTR pwszPath, DWORD dwAttrib) -{ - RemotePathChecker* checker = getGlobalChecker(); - std::shared_ptr> watchedDirectories = checker->WatchedDirectories(); - - if (watchedDirectories->empty()) { - return MAKE_HRESULT(S_FALSE, 0, 0); - } - - bool watched = false; - size_t pathLength = wcslen(pwszPath); - for (auto it = watchedDirectories->begin(); it != watchedDirectories->end(); ++it) { - if (StringUtil::isDescendantOf(pwszPath, pathLength, *it)) { - watched = true; - } - } - - if (!watched) { - return MAKE_HRESULT(S_FALSE, 0, 0); - } - - int state = 0; - if (!checker->IsMonitoredPath(pwszPath, &state)) { - return MAKE_HRESULT(S_FALSE, 0, 0); - } - return MAKE_HRESULT(state == _state ? S_OK : S_FALSE, 0, 0); -} - -IFACEMETHODIMP OCOverlay::GetOverlayInfo(PWSTR pwszIconFile, int cchMax, int *pIndex, DWORD *pdwFlags) -{ - *pIndex = 0; - *pdwFlags = ISIOI_ICONFILE | ISIOI_ICONINDEX; - *pIndex = _state; - - if (GetModuleFileName(instanceHandle, pwszIconFile, cchMax) == 0) { - HRESULT hResult = HRESULT_FROM_WIN32(GetLastError()); - wcerr << L"IsOK? " << (hResult == S_OK) << L" with path " << pwszIconFile << L", index " << *pIndex << endl; - return hResult; - } - - return S_OK; -} diff --git a/shell_integration/windows/OCOverlays/OCOverlay.h b/shell_integration/windows/OCOverlays/OCOverlay.h deleted file mode 100644 index 80aaa7882..000000000 --- a/shell_integration/windows/OCOverlays/OCOverlay.h +++ /dev/null @@ -1,43 +0,0 @@ -/** - * Copyright (c) 2000-2013 Liferay, Inc. All rights reserved. - * - * This library is free software; you can redistribute it and/or modify it under - * the terms of the GNU Lesser General Public License as published by the Free - * Software Foundation; either version 2.1 of the License, or (at your option) - * any later version. - * - * This library 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 Lesser General Public License for more - * details. - */ - -#ifndef OCOVERLAY_H -#define OCOVERLAY_H - -#pragma once - -#include - -class OCOverlay : public IShellIconOverlayIdentifier - -{ -public: - OCOverlay(int state); - - IFACEMETHODIMP_(ULONG) AddRef(); - IFACEMETHODIMP GetOverlayInfo(PWSTR pwszIconFile, int cchMax, int *pIndex, DWORD *pdwFlags); - IFACEMETHODIMP GetPriority(int *pPriority); - IFACEMETHODIMP IsMemberOf(PCWSTR pwszPath, DWORD dwAttrib); - IFACEMETHODIMP QueryInterface(REFIID riid, void **ppv); - IFACEMETHODIMP_(ULONG) Release(); - -protected: - ~OCOverlay(); - -private: - long _referenceCount; - int _state; -}; - -#endif \ No newline at end of file diff --git a/shell_integration/windows/OCOverlays/OCOverlay.rc b/shell_integration/windows/OCOverlays/OCOverlay.rc deleted file mode 100644 index c8f0ef988..000000000 Binary files a/shell_integration/windows/OCOverlays/OCOverlay.rc and /dev/null differ diff --git a/shell_integration/windows/OCOverlays/OCOverlayFactory.cpp b/shell_integration/windows/OCOverlays/OCOverlayFactory.cpp deleted file mode 100644 index 58b569e1c..000000000 --- a/shell_integration/windows/OCOverlays/OCOverlayFactory.cpp +++ /dev/null @@ -1,94 +0,0 @@ -/** - * Copyright (c) 2000-2013 Liferay, Inc. All rights reserved. - * - * This library is free software; you can redistribute it and/or modify it under - * the terms of the GNU Lesser General Public License as published by the Free - * Software Foundation; either version 2.1 of the License, or (at your option) - * any later version. - * - * This library 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 Lesser General Public License for more - * details. - */ - -#include -#include - -#include "OCOverlayFactory.h" -#include "OCOverlay.h" - -extern long dllReferenceCount; - -OCOverlayFactory::OCOverlayFactory(int state) - : _referenceCount(1), _state(state) -{ - InterlockedIncrement(&dllReferenceCount); -} - -OCOverlayFactory::~OCOverlayFactory() -{ - InterlockedDecrement(&dllReferenceCount); -} - -IFACEMETHODIMP OCOverlayFactory::QueryInterface(REFIID riid, void **ppv) -{ - HRESULT hResult = S_OK; - - if (IsEqualIID(IID_IUnknown, riid) || - IsEqualIID(IID_IClassFactory, riid)) - { - *ppv = static_cast(this); - AddRef(); - } - else - { - hResult = E_NOINTERFACE; - *ppv = nullptr; - } - - return hResult; -} - -IFACEMETHODIMP_(ULONG) OCOverlayFactory::AddRef() -{ - return InterlockedIncrement(&_referenceCount); -} - -IFACEMETHODIMP_(ULONG) OCOverlayFactory::Release() -{ - ULONG cRef = InterlockedDecrement(&_referenceCount); - - if (0 == cRef) - { - delete this; - } - return cRef; -} - -IFACEMETHODIMP OCOverlayFactory::CreateInstance( - IUnknown *pUnkOuter, REFIID riid, void **ppv) -{ - HRESULT hResult = CLASS_E_NOAGGREGATION; - - if (pUnkOuter) { return hResult; } - - hResult = E_OUTOFMEMORY; - OCOverlay *lrOverlay = new (std::nothrow) OCOverlay(_state); - if (!lrOverlay) { return hResult; } - - hResult = lrOverlay->QueryInterface(riid, ppv); - lrOverlay->Release(); - - return hResult; -} - -IFACEMETHODIMP OCOverlayFactory::LockServer(BOOL fLock) -{ - if (fLock) { - InterlockedIncrement(&dllReferenceCount); - } else { - InterlockedDecrement(&dllReferenceCount); - } - return S_OK; -} diff --git a/shell_integration/windows/OCOverlays/OCOverlayFactory.h b/shell_integration/windows/OCOverlays/OCOverlayFactory.h deleted file mode 100644 index 5ce881d24..000000000 --- a/shell_integration/windows/OCOverlays/OCOverlayFactory.h +++ /dev/null @@ -1,48 +0,0 @@ -/** - * Copyright (c) 2000-2013 Liferay, Inc. All rights reserved. - * - * This library is free software; you can redistribute it and/or modify it under - * the terms of the GNU Lesser General Public License as published by the Free - * Software Foundation; either version 2.1 of the License, or (at your option) - * any later version. - * - * This library 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 Lesser General Public License for more - * details. - */ - -#ifndef OCOVERLAYFACTORY_H -#define OCOVERLAYFACTORY_H - -#pragma once - -#include - -enum State { - State_Error = 0, - State_OK, State_OKShared, - State_Sync, - State_Warning -}; - -class OCOverlayFactory : public IClassFactory -{ -public: - OCOverlayFactory(int state); - - IFACEMETHODIMP_(ULONG) AddRef(); - IFACEMETHODIMP CreateInstance(IUnknown *pUnkOuter, REFIID riid, void **ppv); - IFACEMETHODIMP LockServer(BOOL fLock); - IFACEMETHODIMP QueryInterface(REFIID riid, void **ppv); - IFACEMETHODIMP_(ULONG) Release(); - -protected: - ~OCOverlayFactory(); - -private: - long _referenceCount; - int _state; -}; - -#endif \ No newline at end of file diff --git a/shell_integration/windows/OCOverlays/OCOverlayRegistrationHandler.cpp b/shell_integration/windows/OCOverlays/OCOverlayRegistrationHandler.cpp deleted file mode 100644 index ffb2d4507..000000000 --- a/shell_integration/windows/OCOverlays/OCOverlayRegistrationHandler.cpp +++ /dev/null @@ -1,153 +0,0 @@ -/** - * Copyright (c) 2000-2013 Liferay, Inc. All rights reserved. - * - * This library is free software; you can redistribute it and/or modify it under - * the terms of the GNU Lesser General Public License as published by the Free - * Software Foundation; either version 2.1 of the License, or (at your option) - * any later version. - * - * This library 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 Lesser General Public License for more - * details. - */ - -#include "OCOverlayRegistrationHandler.h" -#include "OverlayConstants.h" - -#include -#include -#include -#include - -using namespace std; - -HRESULT OCOverlayRegistrationHandler::MakeRegistryEntries(const CLSID& clsid, PCWSTR friendlyName) -{ - HRESULT hResult; - HKEY shellOverlayKey = nullptr; - // the key may not exist yet - hResult = HRESULT_FROM_WIN32(RegCreateKeyEx(HKEY_LOCAL_MACHINE, REGISTRY_OVERLAY_KEY, 0, nullptr, REG_OPTION_NON_VOLATILE, KEY_WRITE, nullptr, &shellOverlayKey, nullptr)); - if (!SUCCEEDED(hResult)) { - hResult = RegCreateKey(HKEY_LOCAL_MACHINE, REGISTRY_OVERLAY_KEY, &shellOverlayKey); - if(!SUCCEEDED(hResult)) { - return hResult; - } - } - - HKEY syncExOverlayKey = nullptr; - hResult = HRESULT_FROM_WIN32(RegCreateKeyEx(shellOverlayKey, friendlyName, 0, nullptr, REG_OPTION_NON_VOLATILE, KEY_WRITE, nullptr, &syncExOverlayKey, nullptr)); - - if (!SUCCEEDED(hResult)) { - return hResult; - } - - wchar_t stringCLSID[MAX_PATH]; - StringFromGUID2(clsid, stringCLSID, ARRAYSIZE(stringCLSID)); - LPCTSTR value = stringCLSID; - hResult = RegSetValueEx(syncExOverlayKey, nullptr, 0, REG_SZ, (LPBYTE)value, (DWORD)((wcslen(value)+1) * sizeof(TCHAR))); - if (!SUCCEEDED(hResult)) { - return hResult; - } - - return hResult; -} - -HRESULT OCOverlayRegistrationHandler::RemoveRegistryEntries(PCWSTR friendlyName) -{ - HRESULT hResult; - HKEY shellOverlayKey = nullptr; - hResult = HRESULT_FROM_WIN32(RegOpenKeyEx(HKEY_LOCAL_MACHINE, REGISTRY_OVERLAY_KEY, 0, KEY_WRITE, &shellOverlayKey)); - - if (!SUCCEEDED(hResult)) { - return hResult; - } - - HKEY syncExOverlayKey = nullptr; - hResult = HRESULT_FROM_WIN32(RegDeleteKey(shellOverlayKey, friendlyName)); - if (!SUCCEEDED(hResult)) { - return hResult; - } - - return hResult; -} - -HRESULT OCOverlayRegistrationHandler::RegisterCOMObject(PCWSTR modulePath, PCWSTR friendlyName, const CLSID& clsid) -{ - if (!modulePath) { - return E_FAIL; - } - - wchar_t stringCLSID[MAX_PATH]; - StringFromGUID2(clsid, stringCLSID, ARRAYSIZE(stringCLSID)); - HRESULT hResult; - HKEY hKey = nullptr; - - hResult = HRESULT_FROM_WIN32(RegOpenKeyEx(HKEY_CLASSES_ROOT, REGISTRY_CLSID, 0, KEY_WRITE, &hKey)); - if (!SUCCEEDED(hResult)) { - return hResult; - } - - HKEY clsidKey = nullptr; - hResult = HRESULT_FROM_WIN32(RegCreateKeyEx(hKey, stringCLSID, 0, nullptr, REG_OPTION_NON_VOLATILE, KEY_WRITE, nullptr, &clsidKey, nullptr)); - if(!SUCCEEDED(hResult)) { - return hResult; - } - - hResult = HRESULT_FROM_WIN32(RegSetValue(clsidKey, nullptr, REG_SZ, friendlyName, (DWORD) wcslen(friendlyName))); - - HKEY inprocessKey = nullptr; - hResult = HRESULT_FROM_WIN32(RegCreateKeyEx(clsidKey, REGISTRY_IN_PROCESS, 0, nullptr, REG_OPTION_NON_VOLATILE, KEY_WRITE, nullptr, &inprocessKey, nullptr)); - if(!SUCCEEDED(hResult)) { - return hResult; - } - - hResult = HRESULT_FROM_WIN32(RegSetValue(inprocessKey, nullptr, REG_SZ, modulePath, (DWORD) wcslen(modulePath))); - - if(!SUCCEEDED(hResult)) { - return hResult; - } - - hResult = HRESULT_FROM_WIN32(RegSetValueEx(inprocessKey, REGISTRY_THREADING, 0, REG_SZ, (LPBYTE)REGISTRY_APARTMENT, (DWORD)((wcslen(REGISTRY_APARTMENT)+1) * sizeof(TCHAR)))); - if(!SUCCEEDED(hResult)) { - return hResult; - } - - hResult = HRESULT_FROM_WIN32(RegSetValueEx(inprocessKey, REGISTRY_VERSION, 0, REG_SZ, (LPBYTE)REGISTRY_VERSION_NUMBER, (DWORD)(wcslen(REGISTRY_VERSION_NUMBER)+1) * sizeof(TCHAR))); - if(!SUCCEEDED(hResult)) { - return hResult; - } - - return S_OK; -} - -HRESULT OCOverlayRegistrationHandler::UnregisterCOMObject(const CLSID& clsid) -{ - wchar_t stringCLSID[MAX_PATH]; - - StringFromGUID2(clsid, stringCLSID, ARRAYSIZE(stringCLSID)); - HRESULT hResult; - HKEY hKey = nullptr; - hResult = HRESULT_FROM_WIN32(RegOpenKeyEx(HKEY_CLASSES_ROOT, REGISTRY_CLSID, 0, DELETE, &hKey)); - if (!SUCCEEDED(hResult)) { - return hResult; - } - - HKEY clsidKey = nullptr; - hResult = HRESULT_FROM_WIN32(RegOpenKeyEx(hKey, stringCLSID, 0, DELETE, &clsidKey)); - if(!SUCCEEDED(hResult)) { - return hResult; - } - - hResult = HRESULT_FROM_WIN32(RegDeleteKey(clsidKey, REGISTRY_IN_PROCESS)); - if(!SUCCEEDED(hResult)) { - return hResult; - } - - hResult = HRESULT_FROM_WIN32(RegDeleteKey(hKey, stringCLSID)); - if(!SUCCEEDED(hResult)) { - return hResult; - } - - return S_OK; -} diff --git a/shell_integration/windows/OCOverlays/OCOverlayRegistrationHandler.h b/shell_integration/windows/OCOverlays/OCOverlayRegistrationHandler.h deleted file mode 100644 index 2ab8f702f..000000000 --- a/shell_integration/windows/OCOverlays/OCOverlayRegistrationHandler.h +++ /dev/null @@ -1,31 +0,0 @@ -/** - * Copyright (c) 2000-2013 Liferay, Inc. All rights reserved. - * - * This library is free software; you can redistribute it and/or modify it under - * the terms of the GNU Lesser General Public License as published by the Free - * Software Foundation; either version 2.1 of the License, or (at your option) - * any later version. - * - * This library 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 Lesser General Public License for more - * details. - */ - -#ifndef OCOVERLAYREGISTRATIONHANDLER_H -#define OCOVERLAYREGISTRATIONHANDLER_H - -#pragma once - -#include - -class __declspec(dllexport) OCOverlayRegistrationHandler -{ - public: - static HRESULT MakeRegistryEntries(const CLSID& clsid, PCWSTR fileType); - static HRESULT RegisterCOMObject(PCWSTR modulePath, PCWSTR friendlyName, const CLSID& clsid); - static HRESULT RemoveRegistryEntries(PCWSTR friendlyName); - static HRESULT UnregisterCOMObject(const CLSID& clsid); -}; - -#endif \ No newline at end of file diff --git a/shell_integration/windows/OCOverlays/OCOverlays.def b/shell_integration/windows/OCOverlays/OCOverlays.def deleted file mode 100644 index 8cde2bd02..000000000 --- a/shell_integration/windows/OCOverlays/OCOverlays.def +++ /dev/null @@ -1,6 +0,0 @@ -LIBRARY -EXPORTS - DllGetClassObject PRIVATE - DllCanUnloadNow PRIVATE - DllRegisterServer PRIVATE - DllUnregisterServer PRIVATE \ No newline at end of file diff --git a/shell_integration/windows/OCOverlays/ico/Error.ico b/shell_integration/windows/OCOverlays/ico/Error.ico deleted file mode 100644 index 641363a8d..000000000 Binary files a/shell_integration/windows/OCOverlays/ico/Error.ico and /dev/null differ diff --git a/shell_integration/windows/OCOverlays/ico/OK.ico b/shell_integration/windows/OCOverlays/ico/OK.ico deleted file mode 100644 index 8ebbff426..000000000 Binary files a/shell_integration/windows/OCOverlays/ico/OK.ico and /dev/null differ diff --git a/shell_integration/windows/OCOverlays/ico/OK_Shared.ico b/shell_integration/windows/OCOverlays/ico/OK_Shared.ico deleted file mode 100644 index c95e1f97e..000000000 Binary files a/shell_integration/windows/OCOverlays/ico/OK_Shared.ico and /dev/null differ diff --git a/shell_integration/windows/OCOverlays/ico/Sync.ico b/shell_integration/windows/OCOverlays/ico/Sync.ico deleted file mode 100644 index 5ba1c3b2a..000000000 Binary files a/shell_integration/windows/OCOverlays/ico/Sync.ico and /dev/null differ diff --git a/shell_integration/windows/OCOverlays/ico/Warning.ico b/shell_integration/windows/OCOverlays/ico/Warning.ico deleted file mode 100644 index 2bae6710d..000000000 Binary files a/shell_integration/windows/OCOverlays/ico/Warning.ico and /dev/null differ diff --git a/shell_integration/windows/OCOverlays/resource.h b/shell_integration/windows/OCOverlays/resource.h deleted file mode 100644 index 3a3dab356..000000000 Binary files a/shell_integration/windows/OCOverlays/resource.h and /dev/null differ diff --git a/shell_integration/windows/OCUtil/CMakeLists.txt b/shell_integration/windows/OCUtil/CMakeLists.txt deleted file mode 100644 index 13a9f6f53..000000000 --- a/shell_integration/windows/OCUtil/CMakeLists.txt +++ /dev/null @@ -1,11 +0,0 @@ -add_library(OCUtil STATIC - CommunicationSocket.cpp - RemotePathChecker.cpp - StringUtil.cpp - OCUtil.rc -) - -target_include_directories(OCUtil - PUBLIC - "${CMAKE_CURRENT_SOURCE_DIR}" -) diff --git a/shell_integration/windows/OCUtil/CommunicationSocket.cpp b/shell_integration/windows/OCUtil/CommunicationSocket.cpp deleted file mode 100644 index 10f95159e..000000000 --- a/shell_integration/windows/OCUtil/CommunicationSocket.cpp +++ /dev/null @@ -1,142 +0,0 @@ -/** - * Copyright (c) 2000-2013 Liferay, Inc. All rights reserved. - * - * This library is free software; you can redistribute it and/or modify it under - * the terms of the GNU Lesser General Public License as published by the Free - * Software Foundation; either version 2.1 of the License, or (at your option) - * any later version. - * - * This library 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 Lesser General Public License for more - * details. - */ - -#include "CommunicationSocket.h" -#include "UtilConstants.h" -#include "StringUtil.h" - -#include -#include -#include - -#include - -#define DEFAULT_BUFLEN 4096 - -using namespace std; - -namespace { - -std::wstring getUserName() { - DWORD len = DEFAULT_BUFLEN; - TCHAR buf[DEFAULT_BUFLEN]; - if (GetUserName(buf, &len)) { - return std::wstring(&buf[0], len); - } else { - return std::wstring(); - } -} - -} - -std::wstring CommunicationSocket::DefaultPipePath() -{ - auto pipename = std::wstring(LR"(\\.\pipe\)"); - pipename += L"ownCloud-"; - pipename += getUserName(); - return pipename; -} - -CommunicationSocket::CommunicationSocket() - : _pipe(INVALID_HANDLE_VALUE) -{ -} - -CommunicationSocket::~CommunicationSocket() -{ - Close(); -} - -bool CommunicationSocket::Close() -{ - if (_pipe == INVALID_HANDLE_VALUE) { - return false; - } - CloseHandle(_pipe); - _pipe = INVALID_HANDLE_VALUE; - return true; -} - - -bool CommunicationSocket::Connect(const std::wstring &pipename) -{ - _pipe = CreateFile(pipename.data(), GENERIC_READ | GENERIC_WRITE, 0, nullptr, OPEN_EXISTING, 0, nullptr); - - if (_pipe == INVALID_HANDLE_VALUE) { - return false; - } - - return true; -} - -bool CommunicationSocket::SendMsg(const wchar_t* message) const -{ - auto utf8_msg = StringUtil::toUtf8(message); - - DWORD numBytesWritten = 0; - auto result = WriteFile( _pipe, utf8_msg.c_str(), DWORD(utf8_msg.size()), &numBytesWritten, nullptr); - - if (result) { - return true; - } else { - const_cast(this)->Close(); - - return false; - } -} - -bool CommunicationSocket::ReadLine(wstring* response) -{ - if (!response) { - return false; - } - - response->clear(); - - if (_pipe == INVALID_HANDLE_VALUE) { - return false; - } - - while (true) { - int lbPos = 0; - auto it = std::find(_buffer.begin() + lbPos, _buffer.end(), '\n'); - if (it != _buffer.end()) { - *response = StringUtil::toUtf16(_buffer.data(), DWORD(it - _buffer.begin())); - _buffer.erase(_buffer.begin(), it + 1); - return true; - } - - std::array resp_utf8; - DWORD numBytesRead = 0; - DWORD totalBytesAvailable = 0; - - if (!PeekNamedPipe(_pipe, nullptr, 0, 0, &totalBytesAvailable, 0)) { - Close(); - return false; - } - if (totalBytesAvailable == 0) { - return false; - } - - if (!ReadFile(_pipe, resp_utf8.data(), DWORD(resp_utf8.size()), &numBytesRead, nullptr)) { - Close(); - return false; - } - if (numBytesRead <= 0) { - return false; - } - _buffer.insert(_buffer.end(), resp_utf8.begin(), resp_utf8.begin()+numBytesRead); - continue; - } -} diff --git a/shell_integration/windows/OCUtil/CommunicationSocket.h b/shell_integration/windows/OCUtil/CommunicationSocket.h deleted file mode 100644 index 68414ef98..000000000 --- a/shell_integration/windows/OCUtil/CommunicationSocket.h +++ /dev/null @@ -1,48 +0,0 @@ -/** - * Copyright (c) 2000-2013 Liferay, Inc. All rights reserved. - * - * This library is free software; you can redistribute it and/or modify it under - * the terms of the GNU Lesser General Public License as published by the Free - * Software Foundation; either version 2.1 of the License, or (at your option) - * any later version. - * - * This library 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 Lesser General Public License for more - * details. - */ - -#ifndef COMMUNICATIONSOCKET_H -#define COMMUNICATIONSOCKET_H - -#pragma once - -#pragma warning (disable : 4251) - -#include -#include -#include - -class __declspec(dllexport) CommunicationSocket -{ -public: - static std::wstring DefaultPipePath(); - - CommunicationSocket(); - ~CommunicationSocket(); - - bool Connect(const std::wstring& pipename); - bool Close(); - - bool SendMsg(const wchar_t*) const; - bool ReadLine(std::wstring*); - - HANDLE Event() { return _pipe; } - -private: - HANDLE _pipe; - std::vector _buffer; - bool _connected; -}; - -#endif diff --git a/shell_integration/windows/OCUtil/OCUtil.rc b/shell_integration/windows/OCUtil/OCUtil.rc deleted file mode 100644 index 4fa556679..000000000 Binary files a/shell_integration/windows/OCUtil/OCUtil.rc and /dev/null differ diff --git a/shell_integration/windows/OCUtil/RemotePathChecker.cpp b/shell_integration/windows/OCUtil/RemotePathChecker.cpp deleted file mode 100644 index 5d004d567..000000000 --- a/shell_integration/windows/OCUtil/RemotePathChecker.cpp +++ /dev/null @@ -1,236 +0,0 @@ -/** -* Copyright (c) 2014 ownCloud GmbH. All rights reserved. -* -* This library is free software; you can redistribute it and/or modify it under -* the terms of the GNU Lesser General Public License as published by the Free -* Software Foundation; version 2.1 of the License -* -* This library 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 Lesser General Public License for more -* details. -*/ - -#include "CommunicationSocket.h" - -#include "RemotePathChecker.h" -#include "StringUtil.h" - -#include - -#include -#include -#include -#include -#include -#include - -#include - -using namespace std; - -// This code is run in a thread -void RemotePathChecker::workerThreadLoop() -{ - auto pipename = CommunicationSocket::DefaultPipePath(); - bool connected = false; - CommunicationSocket socket; - std::unordered_set asked; - - while(!_stop) { - Sleep(50); - - if (!connected) { - asked.clear(); - if (!WaitNamedPipe(pipename.data(), 100)) { - continue; - } - if (!socket.Connect(pipename)) { - continue; - } - connected = true; - std::unique_lock lock(_mutex); - _connected = true; - } - - { - std::unique_lock lock(_mutex); - while (!_pending.empty() && !_stop) { - auto filePath = _pending.front(); - _pending.pop(); - - lock.unlock(); - if (!asked.count(filePath)) { - asked.insert(filePath); - socket.SendMsg(wstring(L"RETRIEVE_FILE_STATUS:" + filePath + L'\n').data()); - } - lock.lock(); - } - } - - std::wstring response; - while (!_stop && socket.ReadLine(&response)) { - if (StringUtil::begins_with(response, wstring(L"REGISTER_PATH:"))) { - wstring responsePath = response.substr(14); // length of REGISTER_PATH: - - auto sharedPtrCopy = atomic_load(&_watchedDirectories); - auto vectorCopy = make_shared>(*sharedPtrCopy); - vectorCopy->push_back(responsePath); - atomic_store(&_watchedDirectories, shared_ptr>(vectorCopy)); - - // We don't keep track of all files and can't know which file is currently visible - // to the user, but at least reload the root dir so that any shortcut to the root - // is updated without the user needing to refresh. - SHChangeNotify(SHCNE_UPDATEDIR, SHCNF_PATH | SHCNF_FLUSHNOWAIT, responsePath.data(), nullptr); - } else if (StringUtil::begins_with(response, wstring(L"UNREGISTER_PATH:"))) { - wstring responsePath = response.substr(16); // length of UNREGISTER_PATH: - - auto sharedPtrCopy = atomic_load(&_watchedDirectories); - auto vectorCopy = make_shared>(*sharedPtrCopy); - vectorCopy->erase( - std::remove(vectorCopy->begin(), vectorCopy->end(), responsePath), - vectorCopy->end()); - atomic_store(&_watchedDirectories, shared_ptr>(vectorCopy)); - - vector removedPaths; - { std::unique_lock lock(_mutex); - // Remove any item from the cache - for (auto it = _cache.begin(); it != _cache.end() ; ) { - if (StringUtil::isDescendantOf(it->first, responsePath)) { - removedPaths.emplace_back(move(it->first)); - it = _cache.erase(it); - } else { - ++it; - } - } - } - for (auto& path : removedPaths) - SHChangeNotify(SHCNE_UPDATEITEM, SHCNF_PATH | SHCNF_FLUSHNOWAIT, path.data(), nullptr); - } else if (StringUtil::begins_with(response, wstring(L"STATUS:")) || - StringUtil::begins_with(response, wstring(L"BROADCAST:"))) { - - wstring responseStatus, responsePath; - if (!StringUtil::extractChunks(response, responseStatus, responsePath)) - continue; - - auto state = _StrToFileState(responseStatus); - bool wasAsked = asked.erase(responsePath) > 0; - - bool updateView = false; - { std::unique_lock lock(_mutex); - auto it = _cache.find(responsePath); - if (it == _cache.end()) { - // The client only approximates requested files, if the bloom - // filter becomes saturated after navigating multiple directories we'll start getting - // status pushes that we never requested and fill our cache. Ignore those. - if (!wasAsked) { - continue; - } - it = _cache.insert(make_pair(responsePath, StateNone)).first; - } - - updateView = it->second != state; - it->second = state; - } - if (updateView) { - SHChangeNotify(SHCNE_UPDATEITEM, SHCNF_PATH | SHCNF_FLUSHNOWAIT, responsePath.data(), nullptr); - } - } - } - - if (socket.Event() == INVALID_HANDLE_VALUE) { - atomic_store(&_watchedDirectories, make_shared>()); - std::unique_lock lock(_mutex); - _connected = connected = false; - - // Swap to make a copy of the cache under the mutex and clear the one stored. - std::unordered_map cache; - swap(cache, _cache); - lock.unlock(); - // Let explorer know about each invalidated cache entry that needs to get its icon removed. - for (auto it = cache.begin(); it != cache.end(); ++it) { - SHChangeNotify(SHCNE_UPDATEITEM, SHCNF_PATH | SHCNF_FLUSHNOWAIT, it->first.data(), nullptr); - } - } - - if (_stop) return; - - HANDLE handles[2] = { _newQueries, socket.Event() }; - WaitForMultipleObjects(2, handles, false, 0); - } -} - - - -RemotePathChecker::RemotePathChecker() - : _stop(false) - , _watchedDirectories(make_shared>()) - , _connected(false) - , _newQueries(CreateEvent(nullptr, FALSE, FALSE, nullptr)) - , _thread([this]{ this->workerThreadLoop(); }) -{ -} - -RemotePathChecker::~RemotePathChecker() -{ - _stop = true; - //_newQueries.notify_all(); - SetEvent(_newQueries); - _thread.join(); - CloseHandle(_newQueries); -} - -std::shared_ptr> RemotePathChecker::WatchedDirectories() const -{ - return atomic_load(&_watchedDirectories); -} - -bool RemotePathChecker::IsMonitoredPath(const wchar_t* filePath, int* state) -{ - assert(state); assert(filePath); - - std::unique_lock lock(_mutex); - if (!_connected) { - return false; - } - - auto path = std::wstring(filePath); - - auto it = _cache.find(path); - if (it != _cache.end()) { - // The path is in our cache, and we'll get updates pushed if the status changes. - *state = it->second; - return true; - } - - _pending.push(filePath); - - lock.unlock(); - SetEvent(_newQueries); - return false; -} - -RemotePathChecker::FileState RemotePathChecker::_StrToFileState(const std::wstring &str) -{ - if (str == L"NOP" || str == L"NONE") { - return StateNone; - } else if (str == L"SYNC" || str == L"NEW") { - return StateSync; - } else if (str == L"SYNC+SWM" || str == L"NEW+SWM") { - return StateSync; - } else if (str == L"OK") { - return StateOk; - } else if (str == L"OK+SWM") { - return StateOkSWM; - } else if (str == L"IGNORE") { - return StateWarning; - } else if (str == L"IGNORE+SWM") { - return StateWarning; - } else if (str == L"ERROR") { - return StateError; - } else if (str == L"ERROR+SWM") { - return StateError; - } - - return StateNone; -} diff --git a/shell_integration/windows/OCUtil/RemotePathChecker.h b/shell_integration/windows/OCUtil/RemotePathChecker.h deleted file mode 100644 index 36bcf1ae9..000000000 --- a/shell_integration/windows/OCUtil/RemotePathChecker.h +++ /dev/null @@ -1,70 +0,0 @@ -/** -* Copyright (c) 2014 ownCloud GmbH. All rights reserved. -* -* This library is free software; you can redistribute it and/or modify it under -* the terms of the GNU Lesser General Public License as published by the Free -* Software Foundation; version 2.1 of the License -* -* This library 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 Lesser General Public License for more -* details. -*/ - -#ifndef PATHCHECKER_H -#define PATHCHECKER_H - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#pragma once - -class __declspec(dllexport) RemotePathChecker { -public: - enum FileState { - // Order synced with OCOverlay - StateError = 0, - StateOk, StateOkSWM, - StateSync, - StateWarning, - StateNone - }; - RemotePathChecker(); - ~RemotePathChecker(); - std::shared_ptr> WatchedDirectories() const; - bool IsMonitoredPath(const wchar_t* filePath, int* state); - -private: - FileState _StrToFileState(const std::wstring &str); - std::mutex _mutex; - std::atomic _stop; - - // Everything here is protected by the _mutex - - /** The list of paths we need to query. The main thread fill this, and the worker thread - * send that to the socket. */ - std::queue _pending; - - std::unordered_map _cache; - // The vector is const since it will be accessed from multiple threads through OCOverlay::IsMemberOf. - // Each modification needs to be made onto a copy and then atomically replaced in the shared_ptr. - std::shared_ptr> _watchedDirectories; - bool _connected; - - - // The main thread notifies when there are new items in _pending - //std::condition_variable _newQueries; - HANDLE _newQueries; - - std::thread _thread; - void workerThreadLoop(); -}; - -#endif \ No newline at end of file diff --git a/shell_integration/windows/OCUtil/StringUtil.cpp b/shell_integration/windows/OCUtil/StringUtil.cpp deleted file mode 100644 index e23030e02..000000000 --- a/shell_integration/windows/OCUtil/StringUtil.cpp +++ /dev/null @@ -1,36 +0,0 @@ -/** -* Copyright (c) 2014 ownCloud GmbH. All rights reserved. -* -* This library is free software; you can redistribute it and/or modify it under -* the terms of the GNU Lesser General Public License as published by the Free -* Software Foundation; version 2.1 of the License -* -* This library 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 Lesser General Public License for more -* details. -*/ - -#include -#include -#include - -#include "StringUtil.h" - -std::string StringUtil::toUtf8(const wchar_t *utf16, int len) -{ - if (len < 0) { - len = (int) wcslen(utf16); - } - std::wstring_convert > converter; - return converter.to_bytes(utf16, utf16+len); -} - -std::wstring StringUtil::toUtf16(const char *utf8, int len) -{ - if (len < 0) { - len = (int) strlen(utf8); - } - std::wstring_convert > converter; - return converter.from_bytes(utf8, utf8+len); -} diff --git a/shell_integration/windows/OCUtil/StringUtil.h b/shell_integration/windows/OCUtil/StringUtil.h deleted file mode 100644 index 180d7c80a..000000000 --- a/shell_integration/windows/OCUtil/StringUtil.h +++ /dev/null @@ -1,91 +0,0 @@ -/** -* Copyright (c) 2014 ownCloud GmbH. All rights reserved. -* -* This library is free software; you can redistribute it and/or modify it under -* the terms of the GNU Lesser General Public License as published by the Free -* Software Foundation; version 2.1 of the License -* -* This library 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 Lesser General Public License for more -* details. -*/ - -#ifndef STRINGUTIL_H -#define STRINGUTIL_H - -#pragma once - -#include -#include -#include - -class __declspec(dllexport) StringUtil { -public: - static std::string toUtf8(const wchar_t* utf16, int len = -1); - static std::wstring toUtf16(const char* utf8, int len = -1); - - template - static bool begins_with(const T& input, const T& match) - { - return input.size() >= match.size() - && std::equal(match.begin(), match.end(), input.begin()); - } - - static bool isDescendantOf(const std::wstring& child, const std::wstring& parent) { - return isDescendantOf(child.c_str(), child.size(), parent.c_str(), parent.size()); - } - - static bool isDescendantOf(PCWSTR child, size_t childLength, const std::wstring& parent) { - return isDescendantOf(child, childLength, parent.c_str(), parent.size()); - } - - static bool isDescendantOf(PCWSTR child, size_t childLength, PCWSTR parent, size_t parentLength) { - if (!parentLength) - return false; - return (childLength == parentLength || childLength > parentLength && (child[parentLength] == L'\\' || child[parentLength - 1] == L'\\')) - && wcsncmp(child, parent, parentLength) == 0; - } - - static bool extractChunks(const std::wstring &source, std::wstring &secondChunk, std::wstring &thirdChunk) { - auto statusBegin = source.find(L':', 0); - assert(statusBegin != std::wstring::npos); - - auto statusEnd = source.find(L':', statusBegin + 1); - if (statusEnd == std::wstring::npos) { - // the command do not contains two colon? - return false; - } - - // Assume the caller extracted the chunk before the first colon. - secondChunk = source.substr(statusBegin + 1, statusEnd - statusBegin - 1); - thirdChunk = source.substr(statusEnd + 1); - return true; - } - - static bool extractChunks(const std::wstring &source, std::wstring &secondChunk, std::wstring &thirdChunk, std::wstring &forthChunk) - { - auto statusBegin = source.find(L':', 0); - assert(statusBegin != std::wstring::npos); - - auto statusEnd = source.find(L':', statusBegin + 1); - if (statusEnd == std::wstring::npos) { - // the command do not contains two colon? - return false; - } - - auto thirdColon = source.find(L':', statusEnd + 1); - if (statusEnd == std::wstring::npos) { - // the command do not contains three colon? - return false; - } - - // Assume the caller extracted the chunk before the first colon. - secondChunk = source.substr(statusBegin + 1, statusEnd - statusBegin - 1); - thirdChunk = source.substr(statusEnd + 1, thirdColon - statusEnd - 1); - forthChunk = source.substr(thirdColon + 1); - return true; - } -}; - -#endif // STRINGUTIL_H diff --git a/shell_integration/windows/OCUtil/UtilConstants.h b/shell_integration/windows/OCUtil/UtilConstants.h deleted file mode 100644 index 04ca7d3ba..000000000 --- a/shell_integration/windows/OCUtil/UtilConstants.h +++ /dev/null @@ -1,30 +0,0 @@ -/** - * Copyright (c) 2000-2013 Liferay, Inc. All rights reserved. - * - * This library is free software; you can redistribute it and/or modify it under - * the terms of the GNU Lesser General Public License as published by the Free - * Software Foundation; either version 2.1 of the License, or (at your option) - * any later version. - * - * This library 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 Lesser General Public License for more - * details. - */ - -#define PLUG_IN_SOCKET_ADDRESS "127.0.0.1" - -#define BACK_SLASH L"\\" -#define CLOSE_BRACE L"]" -#define CLOSE_CURLY_BRACE L"}" -#define COLON L":" -#define COMMAND L"command" -#define COMMA L"," -#define OPEN_BRACE L"[" -#define OPEN_CURLY_BRACE L"{" -#define QUOTE L"\"" -#define VALUE L"value" - -#define REGISTRY_ROOT_KEY L"SOFTWARE\\ownCloud Inc\\ownCloud" -#define REGISTRY_ENABLE_OVERLAY L"EnableOverlay" -#define REGISTRY_FILTER_FOLDER L"FilterFolder" diff --git a/shell_integration/windows/OCUtil/Version.h b/shell_integration/windows/OCUtil/Version.h deleted file mode 100644 index d2c83b060..000000000 --- a/shell_integration/windows/OCUtil/Version.h +++ /dev/null @@ -1,11 +0,0 @@ -#pragma once - -// This is the number that will end up in the version window of the DLLs. -// Increment this version before committing a new build if you are today's shell_integration build master. -#define OCEXT_BUILD_NUM 46 - -#define STRINGIZE2(s) #s -#define STRINGIZE(s) STRINGIZE2(s) - -#define OCEXT_VERSION 1,0,0,OCEXT_BUILD_NUM -#define OCEXT_VERSION_STRING STRINGIZE(OCEXT_VERSION) diff --git a/shell_integration/windows/OCUtil/resource.h b/shell_integration/windows/OCUtil/resource.h deleted file mode 100644 index b9407b5bc..000000000 --- a/shell_integration/windows/OCUtil/resource.h +++ /dev/null @@ -1,14 +0,0 @@ -//{{NO_DEPENDENCIES}} -// Microsoft Visual C++ generated include file. -// Used by OCContextMenu.rc - -// Next default values for new objects -// -#ifdef APSTUDIO_INVOKED -#ifndef APSTUDIO_READONLY_SYMBOLS -#define _APS_NEXT_RESOURCE_VALUE 101 -#define _APS_NEXT_COMMAND_VALUE 40001 -#define _APS_NEXT_CONTROL_VALUE 1001 -#define _APS_NEXT_SYMED_VALUE 101 -#endif -#endif diff --git a/shell_integration/windows/WinShellExtConstants.h.in b/shell_integration/windows/WinShellExtConstants.h.in index 4c8a16597..cc0b4e32f 100644 --- a/shell_integration/windows/WinShellExtConstants.h.in +++ b/shell_integration/windows/WinShellExtConstants.h.in @@ -14,8 +14,13 @@ #pragma once +// IMPORTANT: Keep this file in sync with WinShellExtConstants.wxi.in + // Context Menu #define CONTEXT_MENU_GUID L"@WIN_SHELLEXT_CONTEXT_MENU_GUID@" +#define CONTEXT_MENU_REGKEY_NAME L"@APPLICATION_SHORTNAME@ContextMenuHandler" + +#define CONTEXT_MENU_DESCRIPTION L"@APPLICATION_SHORTNAME@ context menu handler" // Overlays #define OVERLAY_GUID_ERROR L"@WIN_SHELLEXT_OVERLAY_GUID_ERROR@" @@ -23,3 +28,17 @@ #define OVERLAY_GUID_OK_SHARED L"@WIN_SHELLEXT_OVERLAY_GUID_OK_SHARED@" #define OVERLAY_GUID_SYNC L"@WIN_SHELLEXT_OVERLAY_GUID_SYNC@" #define OVERLAY_GUID_WARNING L"@WIN_SHELLEXT_OVERLAY_GUID_WARNING@" + +// +// Preceeding spaces are intended, two spaces to put us ahead of the competition :/ +// +// There is a limit in Windows (oh wonder^^) so that only the first 15 extensions get invoked, this is why to use that dirty little trick to get ahead ;) +// See: https://docs.microsoft.com/en-us/windows/win32/shell/context-menu-handlers?redirectedfrom=MSDN#employing-the-verb-selection-model +// +#define OVERLAY_NAME_ERROR L" @APPLICATION_SHORTNAME@Error" +#define OVERLAY_NAME_OK L" @APPLICATION_SHORTNAME@OK" +#define OVERLAY_NAME_OK_SHARED L" @APPLICATION_SHORTNAME@OKShared" +#define OVERLAY_NAME_SYNC L" @APPLICATION_SHORTNAME@Sync" +#define OVERLAY_NAME_WARNING L" @APPLICATION_SHORTNAME@Warning" + +#define OVERLAY_DESCRIPTION L"@APPLICATION_SHORTNAME@ overlay handler" diff --git a/shell_integration/windows/WinShellExtConstants.wxi.in b/shell_integration/windows/WinShellExtConstants.wxi.in index 788ca3239..9e65fd0e7 100644 --- a/shell_integration/windows/WinShellExtConstants.wxi.in +++ b/shell_integration/windows/WinShellExtConstants.wxi.in @@ -16,6 +16,10 @@ --> + + @@ -29,7 +33,12 @@ - +