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)
--- /dev/null
+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}
+)
--- /dev/null
+/**
+* Copyright (c) 2015 Daniel Molkentin <danimo@owncloud.com>. 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 <shlobj.h>
+
+#include <Strsafe.h>
+
+#include <algorithm>
+#include <iostream>
+#include <sstream>
+#include <iterator>
+#include <unordered_set>
+
+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());
+}
--- /dev/null
+/**
+* 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 <string>
+#include <vector>
+#include <unordered_map>
+#include <queue>
+#include <thread>
+#include <mutex>
+#include <atomic>
+#include <condition_variable>
+
+class CommunicationSocket;
+
+class NCClientInterface
+{
+public:
+ struct ContextMenuInfo {
+ std::vector<std::wstring> watchedDirectories;
+ std::wstring contextMenuTitle;
+ struct MenuItem
+ {
+ std::wstring command, flags, title;
+ };
+ std::vector<MenuItem> menuItems;
+ };
+ static ContextMenuInfo FetchInfo(const std::wstring &files);
+ static void SendRequest(const wchar_t *verb, const std::wstring &path);
+};
+
+#endif //ABSTRACTSOCKETHANDLER_H
--- /dev/null
+/**
+* Copyright (c) 2015 Daniel Molkentin <danimo@owncloud.com>. 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 <shobjidl.h>
+#include <shlwapi.h>
+#include <shellapi.h>
+#include <StringUtil.h>
+#include <strsafe.h>
+
+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<HDROP>(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<PWSTR>(pszName), cchMax,
+ m_info.menuItems[idCommand].command.data());
+ }
+ return E_INVALIDARG;
+}
+
+#pragma endregion
--- /dev/null
+LIBRARY
+EXPORTS
+ DllGetClassObject PRIVATE
+ DllCanUnloadNow PRIVATE
+ DllRegisterServer PRIVATE
+ DllUnregisterServer PRIVATE
\ No newline at end of file
--- /dev/null
+/**
+* Copyright (c) 2015 Daniel Molkentin <danimo@owncloud.com>. 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 <shlobj.h> // For IShellExtInit and IContextMenu
+#include <string>
+#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
--- /dev/null
+/**
+* Copyright (c) 2015 Daniel Molkentin <danimo@owncloud.com>. 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 <new>
+#include <Shlwapi.h>
+#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;
+}
--- /dev/null
+/**
+* Copyright (c) 2015 Daniel Molkentin <danimo@owncloud.com>. 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 <unknwn.h> // 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
--- /dev/null
+/**
+* Copyright (c) 2015 Daniel Molkentin <danimo@owncloud.com>. 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 <strsafe.h>
+#include <objbase.h>
+
+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<const BYTE *>(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<LPBYTE>(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\{<CLSID>} key.
+ hr = StringCchPrintf(szSubkey, ARRAYSIZE(szSubkey), LR"(CLSID\%s)", szCLSID);
+ if (SUCCEEDED(hr))
+ {
+ hr = SetHKCRRegistryKeyAndValue(szSubkey, nullptr, pszFriendlyName);
+
+ // Create the HKCR\CLSID\{<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\{<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\<File Type> 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\<File Type>\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\<File Type> 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\<File Type>\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;
+}
--- /dev/null
+/**
+* Copyright (c) 2015 Daniel Molkentin <danimo@owncloud.com>. 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 <windows.h>
+
+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
--- /dev/null
+#pragma once
+
+#include <windows.h>
+#include <stdio.h>
+#include <strsafe.h>
+
+// 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);
+
+}
--- /dev/null
+/**
+* Copyright (c) 2015 Daniel Molkentin <danimo@owncloud.com>. 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 <windows.h>
+#include <Guiddef.h>
+#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;
+}
--- /dev/null
+//{{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
--- /dev/null
+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}
+)
--- /dev/null
+/**
+ * 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;
+}
--- /dev/null
+/**
+ * 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 <algorithm>
+#include <iostream>
+#include <fstream>
+#include <memory>
+
+using namespace std;
+
+#pragma comment(lib, "shlwapi.lib")
+
+extern HINSTANCE instanceHandle;
+
+#define IDM_DISPLAY 0
+#define IDB_OK 101
+
+namespace {
+
+unique_ptr<RemotePathChecker> 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<IShellIconOverlayIdentifier *>(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<const std::vector<std::wstring>> 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;
+}
--- /dev/null
+/**
+ * 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 <shlobj.h>
+
+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
--- /dev/null
+/**
+ * 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 <windows.h>
+#include <new>
+
+#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<IUnknown *>(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;
+}
--- /dev/null
+/**
+ * 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 <unknwn.h>
+
+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
--- /dev/null
+/**
+ * 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 <windows.h>
+#include <objbase.h>
+#include <iostream>
+#include <fstream>
+
+#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;
+}
--- /dev/null
+/**
+ * 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 <windows.h>
+
+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
--- /dev/null
+LIBRARY
+EXPORTS
+ DllGetClassObject PRIVATE
+ DllCanUnloadNow PRIVATE
+ DllRegisterServer PRIVATE
+ DllUnregisterServer PRIVATE
\ No newline at end of file
--- /dev/null
+add_library(NCUtil STATIC
+ CommunicationSocket.cpp
+ RemotePathChecker.cpp
+ StringUtil.cpp
+ NCUtil.rc
+)
+
+target_include_directories(NCUtil
+ PUBLIC
+ "${CMAKE_CURRENT_SOURCE_DIR}"
+)
--- /dev/null
+/**
+ * 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 <iostream>
+#include <vector>
+#include <array>
+
+#include <fstream>
+
+#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<CommunicationSocket*>(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<char, 128> 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;
+ }
+}
--- /dev/null
+/**
+ * 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 <string>
+#include <vector>
+#include <WinSock2.h>
+
+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<char> _buffer;
+ bool _connected;
+};
+
+#endif
--- /dev/null
+/**
+* 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 <shlobj.h>
+
+#include <algorithm>
+#include <iostream>
+#include <sstream>
+#include <iterator>
+#include <unordered_set>
+#include <cassert>
+
+#include <shlobj.h>
+
+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<std::wstring> 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<std::mutex> lock(_mutex);
+ _connected = true;
+ }
+
+ {
+ std::unique_lock<std::mutex> 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<vector<wstring>>(*sharedPtrCopy);
+ vectorCopy->push_back(responsePath);
+ atomic_store(&_watchedDirectories, shared_ptr<const vector<wstring>>(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<vector<wstring>>(*sharedPtrCopy);
+ vectorCopy->erase(
+ std::remove(vectorCopy->begin(), vectorCopy->end(), responsePath),
+ vectorCopy->end());
+ atomic_store(&_watchedDirectories, shared_ptr<const vector<wstring>>(vectorCopy));
+
+ vector<wstring> removedPaths;
+ { std::unique_lock<std::mutex> 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<std::mutex> 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<const vector<wstring>>());
+ std::unique_lock<std::mutex> lock(_mutex);
+ _connected = connected = false;
+
+ // Swap to make a copy of the cache under the mutex and clear the one stored.
+ std::unordered_map<std::wstring, FileState> 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<const vector<wstring>>())
+ , _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<const std::vector<std::wstring>> RemotePathChecker::WatchedDirectories() const
+{
+ return atomic_load(&_watchedDirectories);
+}
+
+bool RemotePathChecker::IsMonitoredPath(const wchar_t* filePath, int* state)
+{
+ assert(state); assert(filePath);
+
+ std::unique_lock<std::mutex> 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;
+}
--- /dev/null
+/**
+* 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 <string>
+#include <vector>
+#include <unordered_map>
+#include <queue>
+#include <thread>
+#include <memory>
+#include <mutex>
+#include <atomic>
+#include <condition_variable>
+
+#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<const std::vector<std::wstring>> WatchedDirectories() const;
+ bool IsMonitoredPath(const wchar_t* filePath, int* state);
+
+private:
+ FileState _StrToFileState(const std::wstring &str);
+ std::mutex _mutex;
+ std::atomic<bool> _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<std::wstring> _pending;
+
+ std::unordered_map<std::wstring, FileState> _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<const std::vector<std::wstring>> _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
--- /dev/null
+/**
+* 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 <locale>
+#include <string>
+#include <codecvt>
+
+#include "StringUtil.h"
+
+std::string StringUtil::toUtf8(const wchar_t *utf16, int len)
+{
+ if (len < 0) {
+ len = (int) wcslen(utf16);
+ }
+ std::wstring_convert<std::codecvt_utf8_utf16<wchar_t> > 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<std::codecvt_utf8_utf16<wchar_t> > converter;
+ return converter.from_bytes(utf8, utf8+len);
+}
--- /dev/null
+/**
+* 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 <windows.h>
+#include <string>
+#include <cassert>
+
+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<class T>
+ 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
--- /dev/null
+#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)
--- /dev/null
+//{{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
+++ /dev/null
-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}
-)
+++ /dev/null
-/**
-* Copyright (c) 2015 Daniel Molkentin <danimo@owncloud.com>. 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 <shlobj.h>
-
-#include <Strsafe.h>
-
-#include <algorithm>
-#include <iostream>
-#include <sstream>
-#include <iterator>
-#include <unordered_set>
-
-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());
-}
+++ /dev/null
-/**
-* 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 <string>
-#include <vector>
-#include <unordered_map>
-#include <queue>
-#include <thread>
-#include <mutex>
-#include <atomic>
-#include <condition_variable>
-
-class CommunicationSocket;
-
-class OCClientInterface
-{
-public:
- struct ContextMenuInfo {
- std::vector<std::wstring> watchedDirectories;
- std::wstring contextMenuTitle;
- struct MenuItem
- {
- std::wstring command, flags, title;
- };
- std::vector<MenuItem> menuItems;
- };
- static ContextMenuInfo FetchInfo(const std::wstring &files);
- static void SendRequest(const wchar_t *verb, const std::wstring &path);
-};
-
-#endif //ABSTRACTSOCKETHANDLER_H
+++ /dev/null
-/**
-* Copyright (c) 2015 Daniel Molkentin <danimo@owncloud.com>. 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 <shobjidl.h>
-#include <shlwapi.h>
-#include <shellapi.h>
-#include <StringUtil.h>
-#include <strsafe.h>
-
-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<HDROP>(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<PWSTR>(pszName), cchMax,
- m_info.menuItems[idCommand].command.data());
- }
- return E_INVALIDARG;
-}
-
-#pragma endregion
+++ /dev/null
-LIBRARY
-EXPORTS
- DllGetClassObject PRIVATE
- DllCanUnloadNow PRIVATE
- DllRegisterServer PRIVATE
- DllUnregisterServer PRIVATE
\ No newline at end of file
+++ /dev/null
-/**
-* Copyright (c) 2015 Daniel Molkentin <danimo@owncloud.com>. 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 <shlobj.h> // For IShellExtInit and IContextMenu
-#include <string>
-#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
+++ /dev/null
-/**
-* Copyright (c) 2015 Daniel Molkentin <danimo@owncloud.com>. 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 <new>
-#include <Shlwapi.h>
-#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;
-}
+++ /dev/null
-/**
-* Copyright (c) 2015 Daniel Molkentin <danimo@owncloud.com>. 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 <unknwn.h> // 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
+++ /dev/null
-/**
-* Copyright (c) 2015 Daniel Molkentin <danimo@owncloud.com>. 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 <strsafe.h>
-#include <objbase.h>
-
-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<const BYTE *>(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<LPBYTE>(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\{<CLSID>} key.
- hr = StringCchPrintf(szSubkey, ARRAYSIZE(szSubkey), LR"(CLSID\%s)", szCLSID);
- if (SUCCEEDED(hr))
- {
- hr = SetHKCRRegistryKeyAndValue(szSubkey, nullptr, pszFriendlyName);
-
- // Create the HKCR\CLSID\{<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\{<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\<File Type> 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\<File Type>\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\<File Type> 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\<File Type>\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;
-}
+++ /dev/null
-/**
-* Copyright (c) 2015 Daniel Molkentin <danimo@owncloud.com>. 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 <windows.h>
-
-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
+++ /dev/null
-#pragma once
-
-#include <windows.h>
-#include <stdio.h>
-#include <strsafe.h>
-
-// 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);
-
-}
+++ /dev/null
-/**
-* Copyright (c) 2015 Daniel Molkentin <danimo@owncloud.com>. 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 <windows.h>
-#include <Guiddef.h>
-#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;
-}
+++ /dev/null
-//{{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
+++ /dev/null
-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}
-)
+++ /dev/null
-/**
- * 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;
-}
+++ /dev/null
-/**
- * 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 <algorithm>
-#include <iostream>
-#include <fstream>
-#include <memory>
-
-using namespace std;
-
-#pragma comment(lib, "shlwapi.lib")
-
-extern HINSTANCE instanceHandle;
-
-#define IDM_DISPLAY 0
-#define IDB_OK 101
-
-namespace {
-
-unique_ptr<RemotePathChecker> 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<IShellIconOverlayIdentifier *>(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<const std::vector<std::wstring>> 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;
-}
+++ /dev/null
-/**
- * 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 <shlobj.h>
-
-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
+++ /dev/null
-/**
- * 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 <windows.h>
-#include <new>
-
-#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<IUnknown *>(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;
-}
+++ /dev/null
-/**
- * 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 <unknwn.h>
-
-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
+++ /dev/null
-/**
- * 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 <windows.h>
-#include <objbase.h>
-#include <iostream>
-#include <fstream>
-
-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;
-}
+++ /dev/null
-/**
- * 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 <windows.h>
-
-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
+++ /dev/null
-LIBRARY
-EXPORTS
- DllGetClassObject PRIVATE
- DllCanUnloadNow PRIVATE
- DllRegisterServer PRIVATE
- DllUnregisterServer PRIVATE
\ No newline at end of file
+++ /dev/null
-add_library(OCUtil STATIC
- CommunicationSocket.cpp
- RemotePathChecker.cpp
- StringUtil.cpp
- OCUtil.rc
-)
-
-target_include_directories(OCUtil
- PUBLIC
- "${CMAKE_CURRENT_SOURCE_DIR}"
-)
+++ /dev/null
-/**
- * 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 <iostream>
-#include <vector>
-#include <array>
-
-#include <fstream>
-
-#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<CommunicationSocket*>(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<char, 128> 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;
- }
-}
+++ /dev/null
-/**
- * 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 <string>
-#include <vector>
-#include <WinSock2.h>
-
-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<char> _buffer;
- bool _connected;
-};
-
-#endif
+++ /dev/null
-/**
-* 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 <shlobj.h>
-
-#include <algorithm>
-#include <iostream>
-#include <sstream>
-#include <iterator>
-#include <unordered_set>
-#include <cassert>
-
-#include <shlobj.h>
-
-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<std::wstring> 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<std::mutex> lock(_mutex);
- _connected = true;
- }
-
- {
- std::unique_lock<std::mutex> 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<vector<wstring>>(*sharedPtrCopy);
- vectorCopy->push_back(responsePath);
- atomic_store(&_watchedDirectories, shared_ptr<const vector<wstring>>(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<vector<wstring>>(*sharedPtrCopy);
- vectorCopy->erase(
- std::remove(vectorCopy->begin(), vectorCopy->end(), responsePath),
- vectorCopy->end());
- atomic_store(&_watchedDirectories, shared_ptr<const vector<wstring>>(vectorCopy));
-
- vector<wstring> removedPaths;
- { std::unique_lock<std::mutex> 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<std::mutex> 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<const vector<wstring>>());
- std::unique_lock<std::mutex> lock(_mutex);
- _connected = connected = false;
-
- // Swap to make a copy of the cache under the mutex and clear the one stored.
- std::unordered_map<std::wstring, FileState> 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<const vector<wstring>>())
- , _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<const std::vector<std::wstring>> RemotePathChecker::WatchedDirectories() const
-{
- return atomic_load(&_watchedDirectories);
-}
-
-bool RemotePathChecker::IsMonitoredPath(const wchar_t* filePath, int* state)
-{
- assert(state); assert(filePath);
-
- std::unique_lock<std::mutex> 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;
-}
+++ /dev/null
-/**
-* 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 <string>
-#include <vector>
-#include <unordered_map>
-#include <queue>
-#include <thread>
-#include <memory>
-#include <mutex>
-#include <atomic>
-#include <condition_variable>
-
-#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<const std::vector<std::wstring>> WatchedDirectories() const;
- bool IsMonitoredPath(const wchar_t* filePath, int* state);
-
-private:
- FileState _StrToFileState(const std::wstring &str);
- std::mutex _mutex;
- std::atomic<bool> _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<std::wstring> _pending;
-
- std::unordered_map<std::wstring, FileState> _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<const std::vector<std::wstring>> _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
+++ /dev/null
-/**
-* 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 <locale>
-#include <string>
-#include <codecvt>
-
-#include "StringUtil.h"
-
-std::string StringUtil::toUtf8(const wchar_t *utf16, int len)
-{
- if (len < 0) {
- len = (int) wcslen(utf16);
- }
- std::wstring_convert<std::codecvt_utf8_utf16<wchar_t> > 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<std::codecvt_utf8_utf16<wchar_t> > converter;
- return converter.from_bytes(utf8, utf8+len);
-}
+++ /dev/null
-/**
-* 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 <windows.h>
-#include <string>
-#include <cassert>
-
-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<class T>
- 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
+++ /dev/null
-/**
- * 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"
+++ /dev/null
-#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)
+++ /dev/null
-//{{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
#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@"
#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"
-->
<Include>
+ <!--
+ IMPORTANT: Keep this file in sync with WinShellExtConstants.h.in
+ -->
+
<!-- Context Menu -->
<?define ContextMenuGuid = "@WIN_SHELLEXT_CONTEXT_MENU_GUID@" ?>
<?define ContextMenuRegKeyName = "@APPLICATION_SHORTNAME@ContextMenuHandler" ?>
<?define OverlayGuidSync = "@WIN_SHELLEXT_OVERLAY_GUID_SYNC@" ?>
<?define OverlayGuidWarning = "@WIN_SHELLEXT_OVERLAY_GUID_WARNING@" ?>
- <!-- Preceeding spaces are intended, two spaces to put us ahead of the competition :/ -->
+ <!--
+ 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 OverlayNameError = " @APPLICATION_SHORTNAME@Error" ?>
<?define OverlayNameOK = " @APPLICATION_SHORTNAME@OK" ?>
<?define OverlayNameOKShared = " @APPLICATION_SHORTNAME@OKShared" ?>