diff options
author | Olivier Goffart <ogoffart@woboq.com> | 2015-01-23 20:02:55 +0300 |
---|---|---|
committer | Olivier Goffart <ogoffart@woboq.com> | 2015-01-23 20:02:55 +0300 |
commit | fb79211514c11eb6ec8813dbb4201fce1f309716 (patch) | |
tree | 5cb9f8b83695d2945df77fc1361fd805fd01177f /shell_integration | |
parent | 502e7081cf959273e77ea1e6104f5290e922c2be (diff) | |
parent | 0af97156c974d6aba22bb8bcb8ba0d536d628d1c (diff) |
Merge remote-tracking branch 'remotes/origin/win_context_menu'
Diffstat (limited to 'shell_integration')
19 files changed, 1270 insertions, 9 deletions
diff --git a/shell_integration/windows/OCContextMenu/OCClientInterface.cpp b/shell_integration/windows/OCContextMenu/OCClientInterface.cpp new file mode 100644 index 000000000..d2d9ae8e9 --- /dev/null +++ b/shell_integration/windows/OCContextMenu/OCClientInterface.cpp @@ -0,0 +1,80 @@ +/** +* 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> +#include <cassert> + +using namespace std; + +#define PIPE_TIMEOUT 5*1000 //ms +#define SOCK_BUFFER 4096 + +std::vector<std::wstring> OCClientInterface::WatchedDirectories() +{ + auto pipename = std::wstring(L"\\\\.\\pipe\\"); + pipename += L"ownCloud"; + + CommunicationSocket socket; + if (!WaitNamedPipe(pipename.data(), PIPE_TIMEOUT)) { + return std::vector<std::wstring>(); + } + if (!socket.Connect(pipename)) { + return std::vector<std::wstring>(); + } + std::vector<std::wstring> watchedDirectories; + std::wstring response; + Sleep(50); + while (socket.ReadLine(&response)) { + if (StringUtil::begins_with(response, wstring(L"REGISTER_PATH:"))) { + wstring responsePath = response.substr(14); // length of REGISTER_PATH + watchedDirectories.push_back(responsePath); + } + } + return watchedDirectories; +} + +void OCClientInterface::ShareObject(const std::wstring &path) +{ + auto pipename = std::wstring(L"\\\\.\\pipe\\"); + pipename += L"ownCloud"; + + CommunicationSocket socket; + if (!WaitNamedPipe(pipename.data(), PIPE_TIMEOUT)) { + return; + } + if (!socket.Connect(pipename)) { + return; + } + + wchar_t msg[SOCK_BUFFER] = { 0 }; + if (SUCCEEDED(StringCchPrintf(msg, SOCK_BUFFER, L"SHARE:%s\n", path.c_str()))) + { + socket.SendMsg(msg); + } +} diff --git a/shell_integration/windows/OCContextMenu/OCClientInterface.h b/shell_integration/windows/OCContextMenu/OCClientInterface.h new file mode 100644 index 000000000..7356d1e28 --- /dev/null +++ b/shell_integration/windows/OCContextMenu/OCClientInterface.h @@ -0,0 +1,50 @@ +/** +* Copyright (c) 2015 ownCloud, 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; 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, 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; 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: + static std::vector<std::wstring> WatchedDirectories(); + static void ShareObject(const std::wstring &path); +}; + +#endif //ABSTRACTSOCKETHANDLER_H diff --git a/shell_integration/windows/OCContextMenu/OCContextMenu.cpp b/shell_integration/windows/OCContextMenu/OCContextMenu.cpp new file mode 100644 index 000000000..4a612a9ca --- /dev/null +++ b/shell_integration/windows/OCContextMenu/OCContextMenu.cpp @@ -0,0 +1,267 @@ +/** +* 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 "stdafx.h" + +#include "OCContextMenu.h" +#include "OCClientInterface.h" + +#include <shobjidl.h> +#include <shlwapi.h> +#include <shellapi.h> +#include <StringUtil.h> + +extern HINSTANCE g_hInst; +extern long g_cDllRef; + +#define IDM_SHARE 0 + + + +OCContextMenu::OCContextMenu(void) + : m_cRef(1) + , m_pszMenuText(L"&Share") + , m_pszVerb("ocshare") + , m_pwszVerb(L"ocshare") + , m_pszVerbCanonicalName("OCShareViaOC") + , m_pwszVerbCanonicalName(L"OCShareViaOC") + , m_pszVerbHelpText("Share via ownCloud") + , m_pwszVerbHelpText(L"Share via ownCloud") +{ + InterlockedIncrement(&g_cDllRef); +} + +OCContextMenu::~OCContextMenu(void) +{ + InterlockedDecrement(&g_cDllRef); +} + + +void OCContextMenu::OnVerbDisplayFileName(HWND hWnd) +{ + OCClientInterface::ShareObject(std::wstring(m_szSelectedFile)); +} + + +#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) +{ + if (!pDataObj) { + return E_INVALIDARG; + } + + HRESULT hr = E_FAIL; + + FORMATETC fe = { CF_HDROP, NULL, 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) { + // Ignore multi-selections + UINT nFiles = DragQueryFile(hDrop, 0xFFFFFFFF, NULL, 0); + if (nFiles == 1) { + // Get the path of the file. + if (0 != DragQueryFile(hDrop, 0, m_szSelectedFile, ARRAYSIZE(m_szSelectedFile))) + { + hr = S_OK; + } + } + + 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 hr; +} + +#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)); + } + + bool skip = true; + for (const std::wstring path : OCClientInterface::WatchedDirectories()) { + if (StringUtil::begins_with(std::wstring(m_szSelectedFile), path)) { + skip = false; + break; + } + } + + if (skip) { + return MAKE_HRESULT(SEVERITY_SUCCESS, 0, USHORT(0)); + } + + InsertSeperator(hMenu, indexMenu); + indexMenu++; + + MENUITEMINFO mii = { sizeof(mii) }; + mii.fMask = MIIM_BITMAP | MIIM_STRING | MIIM_FTYPE | MIIM_ID | MIIM_STATE; + mii.wID = idCmdFirst + IDM_SHARE; + mii.fType = MFT_STRING; + mii.dwTypeData = m_pszMenuText; + mii.fState = MFS_ENABLED; + if (!InsertMenuItem(hMenu, indexMenu, TRUE, &mii)) + { + return HRESULT_FROM_WIN32(GetLastError()); + } + + indexMenu++; + InsertSeperator(hMenu, indexMenu); + + + // 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(IDM_SHARE + 1)); +} + +IFACEMETHODIMP OCContextMenu::InvokeCommand(LPCMINVOKECOMMANDINFO pici) +{ + + // For the Unicode case, if the high-order word is not zero, the + // command's verb string is in lpcmi->lpVerbW. + if (HIWORD(((CMINVOKECOMMANDINFOEX*)pici)->lpVerbW)) + { + // Is the verb supported by this context menu extension? + if (StrCmpIW(((CMINVOKECOMMANDINFOEX*)pici)->lpVerbW, m_pwszVerb) == 0) + { + OnVerbDisplayFileName(pici->hwnd); + } + else + { + // If the verb is not recognized by the context menu handler, it + // must return E_FAIL to allow it to be passed on to the other + // context menu handlers that might implement that verb. + return E_FAIL; + } + } + + // If the command cannot be identified through the verb string, then + // check the identifier offset. + else + { + // Is the command identifier offset supported by this context menu + // extension? + if (LOWORD(pici->lpVerb) == IDM_SHARE) + { + OnVerbDisplayFileName(pici->hwnd); + } + else + { + // If the verb is not recognized by the context menu handler, it + // must return E_FAIL to allow it to be passed on to the other + // context menu handlers that might implement that verb. + return E_FAIL; + } + } + + return S_OK; +} + +IFACEMETHODIMP OCContextMenu::GetCommandString(UINT_PTR idCommand, + UINT uFlags, UINT *pwReserved, LPSTR pszName, UINT cchMax) +{ + HRESULT hr = E_INVALIDARG; + + if (idCommand == IDM_SHARE) + { + switch (uFlags) + { + case GCS_HELPTEXTW: + // Only useful for pre-Vista versions of Windows that have a + // Status bar. + hr = StringCchCopy(reinterpret_cast<PWSTR>(pszName), cchMax, + m_pwszVerbHelpText); + break; + + case GCS_VERBW: + // GCS_VERBW is an optional feature that enables a caller to + // discover the canonical name for the verb passed in through + // idCommand. + hr = StringCchCopy(reinterpret_cast<PWSTR>(pszName), cchMax, + m_pwszVerbCanonicalName); + break; + + default: + hr = S_OK; + } + } + + // If the command (idCommand) is not supported by this context menu + // extension handler, return E_INVALIDARG. + + return hr; +} + +#pragma endregion
\ No newline at end of file diff --git a/shell_integration/windows/OCContextMenu/OCContextMenu.def b/shell_integration/windows/OCContextMenu/OCContextMenu.def new file mode 100644 index 000000000..8cde2bd02 --- /dev/null +++ b/shell_integration/windows/OCContextMenu/OCContextMenu.def @@ -0,0 +1,6 @@ +LIBRARY +EXPORTS + DllGetClassObject PRIVATE + DllCanUnloadNow PRIVATE + DllRegisterServer PRIVATE + DllUnregisterServer PRIVATE
\ No newline at end of file diff --git a/shell_integration/windows/OCContextMenu/OCContextMenu.h b/shell_integration/windows/OCContextMenu/OCContextMenu.h new file mode 100644 index 000000000..dab468a14 --- /dev/null +++ b/shell_integration/windows/OCContextMenu/OCContextMenu.h @@ -0,0 +1,64 @@ +/** +* 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 <windows.h> +#include <shlobj.h> // For IShellExtInit and IContextMenu +#include <memory> + +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 file. + wchar_t m_szSelectedFile[MAX_PATH]; + + // The method that handles the "display" verb. + void OnVerbDisplayFileName(HWND hWnd); + + PWSTR m_pszMenuText; + PCSTR m_pszVerb; + PCWSTR m_pwszVerb; + PCSTR m_pszVerbCanonicalName; + PCWSTR m_pwszVerbCanonicalName; + PCSTR m_pszVerbHelpText; + PCWSTR m_pwszVerbHelpText; +}; + +#endif //OCCONTEXTMENU_H diff --git a/shell_integration/windows/OCContextMenu/OCContextMenu.vcxproj b/shell_integration/windows/OCContextMenu/OCContextMenu.vcxproj new file mode 100644 index 000000000..d81b75638 --- /dev/null +++ b/shell_integration/windows/OCContextMenu/OCContextMenu.vcxproj @@ -0,0 +1,148 @@ +<?xml version="1.0" encoding="utf-8"?> +<Project DefaultTargets="Build" ToolsVersion="12.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> + <ItemGroup Label="ProjectConfigurations"> + <ProjectConfiguration Include="Debug|Win32"> + <Configuration>Debug</Configuration> + <Platform>Win32</Platform> + </ProjectConfiguration> + <ProjectConfiguration Include="Debug|x64"> + <Configuration>Debug</Configuration> + <Platform>x64</Platform> + </ProjectConfiguration> + <ProjectConfiguration Include="Release|Win32"> + <Configuration>Release</Configuration> + <Platform>Win32</Platform> + </ProjectConfiguration> + <ProjectConfiguration Include="Release|x64"> + <Configuration>Release</Configuration> + <Platform>x64</Platform> + </ProjectConfiguration> + </ItemGroup> + <PropertyGroup Label="Globals"> + <ProjectGuid>{FF34851F-1346-4809-A68A-B1188D7DFF32}</ProjectGuid> + <Keyword>Win32Proj</Keyword> + <RootNamespace>OCContextMenu</RootNamespace> + </PropertyGroup> + <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" /> + <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration"> + <ConfigurationType>DynamicLibrary</ConfigurationType> + <UseDebugLibraries>true</UseDebugLibraries> + <PlatformToolset>v120_xp</PlatformToolset> + <CharacterSet>Unicode</CharacterSet> + </PropertyGroup> + <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration"> + <ConfigurationType>DynamicLibrary</ConfigurationType> + <UseDebugLibraries>false</UseDebugLibraries> + <PlatformToolset>v120</PlatformToolset> + <WholeProgramOptimization>true</WholeProgramOptimization> + <CharacterSet>Unicode</CharacterSet> + </PropertyGroup> + <PropertyGroup Label="Configuration" Condition="'$(Configuration)|$(Platform)'=='Debug|x64'"> + <PlatformToolset>v120</PlatformToolset> + <ConfigurationType>DynamicLibrary</ConfigurationType> + <CharacterSet>Unicode</CharacterSet> + </PropertyGroup> + <PropertyGroup Label="Configuration" Condition="'$(Configuration)|$(Platform)'=='Release|x64'"> + <PlatformToolset>v120</PlatformToolset> + </PropertyGroup> + <Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" /> + <ImportGroup Label="ExtensionSettings"> + </ImportGroup> + <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'"> + <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" /> + </ImportGroup> + <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|Win32'"> + <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" /> + </ImportGroup> + <PropertyGroup Label="UserMacros" /> + <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'"> + <LinkIncremental>true</LinkIncremental> + </PropertyGroup> + <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'"> + <LinkIncremental>false</LinkIncremental> + </PropertyGroup> + <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'"> + <OutDir>$(SolutionDir)$(Configuration)\$(Platform)\</OutDir> + <IntDir>$(Configuration)\$(Platform)\</IntDir> + </PropertyGroup> + <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'"> + <ClCompile> + <PrecompiledHeader>Use</PrecompiledHeader> + <WarningLevel>Level3</WarningLevel> + <Optimization>Disabled</Optimization> + <PreprocessorDefinitions>WIN32;_DEBUG;_WINDOWS;_USRDLL;OCCONTEXTMENU_EXPORTS;%(PreprocessorDefinitions)</PreprocessorDefinitions> + <SDLCheck>true</SDLCheck> + </ClCompile> + <Link> + <SubSystem>Windows</SubSystem> + <GenerateDebugInformation>true</GenerateDebugInformation> + </Link> + </ItemDefinitionGroup> + <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'"> + <ClCompile> + <WarningLevel>Level3</WarningLevel> + <PrecompiledHeader>Use</PrecompiledHeader> + <Optimization>MaxSpeed</Optimization> + <FunctionLevelLinking>true</FunctionLevelLinking> + <IntrinsicFunctions>true</IntrinsicFunctions> + <PreprocessorDefinitions>WIN32;NDEBUG;_WINDOWS;_USRDLL;OCCONTEXTMENU_EXPORTS;%(PreprocessorDefinitions)</PreprocessorDefinitions> + <SDLCheck>true</SDLCheck> + </ClCompile> + <Link> + <SubSystem>Windows</SubSystem> + <GenerateDebugInformation>true</GenerateDebugInformation> + <EnableCOMDATFolding>true</EnableCOMDATFolding> + <OptimizeReferences>true</OptimizeReferences> + </Link> + </ItemDefinitionGroup> + <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'"> + <Link> + <AdditionalLibraryDirectories>..\$(Configuration)\$(Platform);</AdditionalLibraryDirectories> + <ModuleDefinitionFile>OCContextMenu.def</ModuleDefinitionFile> + <AdditionalDependencies>OCUtil_x64.lib;kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies)</AdditionalDependencies> + <GenerateDebugInformation>true</GenerateDebugInformation> + </Link> + <ClCompile> + <AdditionalIncludeDirectories>..\OCUtil</AdditionalIncludeDirectories> + <RuntimeLibrary>MultiThreadedDebugDLL</RuntimeLibrary> + <WarningLevel>Level3</WarningLevel> + <Optimization>Disabled</Optimization> + <PrecompiledHeader /> + </ClCompile> + </ItemDefinitionGroup> + <ItemGroup> + <Text Include="ReadMe.txt" /> + </ItemGroup> + <ItemGroup> + <ClInclude Include="OCClientInterface.h" /> + <ClInclude Include="OCContextMenuFactory.h" /> + <ClInclude Include="OCContextMenuRegHandler.h" /> + <ClInclude Include="OCContextMenu.h" /> + <ClInclude Include="stdafx.h" /> + <ClInclude Include="targetver.h" /> + </ItemGroup> + <ItemGroup> + <ClCompile Include="dllmain.cpp"> + <CompileAsManaged Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">false</CompileAsManaged> + <PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'"> + </PrecompiledHeader> + <CompileAsManaged Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">false</CompileAsManaged> + <PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Release|Win32'"> + </PrecompiledHeader> + </ClCompile> + <ClCompile Include="OCClientInterface.cpp" /> + <ClCompile Include="OCContextMenu.cpp" /> + <ClCompile Include="OCContextMenuRegHandler.cpp" /> + <ClCompile Include="OCContextMenuFactory.cpp" /> + <ClCompile Include="stdafx.cpp"> + <PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">Create</PrecompiledHeader> + <PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">Create</PrecompiledHeader> + </ClCompile> + </ItemGroup> + <ItemGroup> + <None Include="OCContextMenu.def" /> + </ItemGroup> + <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" /> + <ImportGroup Label="ExtensionTargets"> + </ImportGroup> +</Project>
\ No newline at end of file diff --git a/shell_integration/windows/OCContextMenu/OCContextMenu.vcxproj.filters b/shell_integration/windows/OCContextMenu/OCContextMenu.vcxproj.filters new file mode 100644 index 000000000..227536ed1 --- /dev/null +++ b/shell_integration/windows/OCContextMenu/OCContextMenu.vcxproj.filters @@ -0,0 +1,65 @@ +<?xml version="1.0" encoding="utf-8"?> +<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> + <ItemGroup> + <Filter Include="Source Files"> + <UniqueIdentifier>{4FC737F1-C7A5-4376-A066-2A32D752A2FF}</UniqueIdentifier> + <Extensions>cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx</Extensions> + </Filter> + <Filter Include="Header Files"> + <UniqueIdentifier>{93995380-89BD-4b04-88EB-625FBE52EBFB}</UniqueIdentifier> + <Extensions>h;hh;hpp;hxx;hm;inl;inc;xsd</Extensions> + </Filter> + <Filter Include="Resource Files"> + <UniqueIdentifier>{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}</UniqueIdentifier> + <Extensions>rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms</Extensions> + </Filter> + </ItemGroup> + <ItemGroup> + <Text Include="ReadMe.txt" /> + </ItemGroup> + <ItemGroup> + <ClInclude Include="stdafx.h"> + <Filter>Header Files</Filter> + </ClInclude> + <ClInclude Include="targetver.h"> + <Filter>Header Files</Filter> + </ClInclude> + <ClInclude Include="OCContextMenu.h"> + <Filter>Header Files</Filter> + </ClInclude> + <ClInclude Include="OCContextMenuRegHandler.h"> + <Filter>Header Files</Filter> + </ClInclude> + <ClInclude Include="OCContextMenuFactory.h"> + <Filter>Header Files</Filter> + </ClInclude> + <ClInclude Include="OCClientInterface.h"> + <Filter>Header Files</Filter> + </ClInclude> + </ItemGroup> + <ItemGroup> + <ClCompile Include="stdafx.cpp"> + <Filter>Source Files</Filter> + </ClCompile> + <ClCompile Include="OCContextMenu.cpp"> + <Filter>Source Files</Filter> + </ClCompile> + <ClCompile Include="dllmain.cpp"> + <Filter>Source Files</Filter> + </ClCompile> + <ClCompile Include="OCContextMenuRegHandler.cpp"> + <Filter>Source Files</Filter> + </ClCompile> + <ClCompile Include="OCContextMenuFactory.cpp"> + <Filter>Source Files</Filter> + </ClCompile> + <ClCompile Include="OCClientInterface.cpp"> + <Filter>Source Files</Filter> + </ClCompile> + </ItemGroup> + <ItemGroup> + <None Include="OCContextMenu.def"> + <Filter>Source Files</Filter> + </None> + </ItemGroup> +</Project>
\ No newline at end of file diff --git a/shell_integration/windows/OCContextMenu/OCContextMenuFactory.cpp b/shell_integration/windows/OCContextMenu/OCContextMenuFactory.cpp new file mode 100644 index 000000000..07f61f852 --- /dev/null +++ b/shell_integration/windows/OCContextMenu/OCContextMenuFactory.cpp @@ -0,0 +1,91 @@ +/** +* 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 "stdafx.h" + +#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 == NULL) { + 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; +}
\ No newline at end of file diff --git a/shell_integration/windows/OCContextMenu/OCContextMenuFactory.h b/shell_integration/windows/OCContextMenu/OCContextMenuFactory.h new file mode 100644 index 000000000..44840fe4c --- /dev/null +++ b/shell_integration/windows/OCContextMenu/OCContextMenuFactory.h @@ -0,0 +1,43 @@ +/** +* 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 +#include <minwindef.h> + +class OCContextMenuFactory : public IClassFactory +{ +public: + // IUnknown + IFACEMETHODIMP QueryInterface(REFIID riid, void **ppv); + IFACEMETHODIMP_(ULONG) AddRef(); + IFACEMETHODIMP_(ULONG) Release(); + + // IClassFactory + IFACEMETHODIMP CreateInstance(IUnknown *pUnkOuter, REFIID riid, void **ppv); + IFACEMETHODIMP LockServer(BOOL fLock); + + OCContextMenuFactory(); + +private: + ~OCContextMenuFactory(); + long m_cRef; +}; + +#endif //OCCONTEXTMENUFACTORY_H
\ No newline at end of file diff --git a/shell_integration/windows/OCContextMenu/OCContextMenuRegHandler.cpp b/shell_integration/windows/OCContextMenu/OCContextMenuRegHandler.cpp new file mode 100644 index 000000000..20af1245e --- /dev/null +++ b/shell_integration/windows/OCContextMenu/OCContextMenuRegHandler.cpp @@ -0,0 +1,217 @@ +/** +* 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 "stdafx.h" + +#include "OCContextMenuRegHandler.h" +#include <strsafe.h> +#include <objbase.h> + +namespace { + +HRESULT SetHKCRRegistryKeyAndValue(PCWSTR pszSubKey, PCWSTR pszValueName, PCWSTR pszData) +{ + HRESULT hr; + HKEY hKey = NULL; + + // Creates the specified registry key. If the key already exists, the + // function opens it. + hr = HRESULT_FROM_WIN32(RegCreateKeyEx(HKEY_CLASSES_ROOT, pszSubKey, 0, + NULL, REG_OPTION_NON_VOLATILE, KEY_WRITE, NULL, &hKey, NULL)); + + if (SUCCEEDED(hr)) + { + if (pszData != NULL) + { + // 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 = NULL; + + // 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, NULL, + NULL, reinterpret_cast<LPBYTE>(pszData), &cbData)); + + RegCloseKey(hKey); + } + + return hr; +} + +} + +HRESULT OCContextMenuRegHandler::RegisterInprocServer(PCWSTR pszModule, const CLSID& clsid, PCWSTR pszFriendlyName, PCWSTR pszThreadModel) +{ + if (pszModule == NULL || pszThreadModel == NULL) + { + 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), L"CLSID\\%s", szCLSID); + if (SUCCEEDED(hr)) + { + hr = SetHKCRRegistryKeyAndValue(szSubkey, NULL, pszFriendlyName); + + // Create the HKCR\CLSID\{<CLSID>}\InprocServer32 key. + if (SUCCEEDED(hr)) + { + hr = StringCchPrintf(szSubkey, ARRAYSIZE(szSubkey), + L"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, NULL, 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), L"CLSID\\%s", szCLSID); + if (SUCCEEDED(hr)) + { + hr = HRESULT_FROM_WIN32(RegDeleteTree(HKEY_CLASSES_ROOT, szSubkey)); + } + + return hr; +} + + +HRESULT OCContextMenuRegHandler::RegisterShellExtContextMenuHandler( + PCWSTR pszFileType, const CLSID& clsid, PCWSTR pszFriendlyName) +{ + if (pszFileType == NULL) + { + 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, NULL, 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), + L"%s\\shellex\\ContextMenuHandlers\\%s", pszFileType, pszFriendlyName); + if (SUCCEEDED(hr)) + { + // Set the default value of the key. + hr = SetHKCRRegistryKeyAndValue(szSubkey, NULL, szCLSID); + } + + return hr; +} + +HRESULT OCContextMenuRegHandler::UnregisterShellExtContextMenuHandler( + PCWSTR pszFileType, PCWSTR pszFriendlyName) +{ + if (pszFileType == NULL) + { + 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, NULL, 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), + L"%s\\shellex\\ContextMenuHandlers\\%s", pszFileType, pszFriendlyName); + if (SUCCEEDED(hr)) + { + hr = HRESULT_FROM_WIN32(RegDeleteTree(HKEY_CLASSES_ROOT, szSubkey)); + } + + return hr; +}
\ No newline at end of file diff --git a/shell_integration/windows/OCContextMenu/OCContextMenuRegHandler.h b/shell_integration/windows/OCContextMenu/OCContextMenuRegHandler.h new file mode 100644 index 000000000..b73db2fa4 --- /dev/null +++ b/shell_integration/windows/OCContextMenu/OCContextMenuRegHandler.h @@ -0,0 +1,38 @@ +/** +* 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 "stdafx.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 diff --git a/shell_integration/windows/OCContextMenu/ReadMe.txt b/shell_integration/windows/OCContextMenu/ReadMe.txt new file mode 100644 index 000000000..9b4563b70 --- /dev/null +++ b/shell_integration/windows/OCContextMenu/ReadMe.txt @@ -0,0 +1,40 @@ +======================================================================== + DYNAMIC LINK LIBRARY : OCContextMenu Project Overview +======================================================================== + +AppWizard has created this OCContextMenu DLL for you. + +This file contains a summary of what you will find in each of the files that +make up your OCContextMenu application. + + +OCContextMenu.vcxproj + This is the main project file for VC++ projects generated using an Application Wizard. + It contains information about the version of Visual C++ that generated the file, and + information about the platforms, configurations, and project features selected with the + Application Wizard. + +OCContextMenu.vcxproj.filters + This is the filters file for VC++ projects generated using an Application Wizard. + It contains information about the association between the files in your project + and the filters. This association is used in the IDE to show grouping of files with + similar extensions under a specific node (for e.g. ".cpp" files are associated with the + "Source Files" filter). + +OCContextMenu.cpp + This is the main DLL source file. + +///////////////////////////////////////////////////////////////////////////// +Other standard files: + +StdAfx.h, StdAfx.cpp + These files are used to build a precompiled header (PCH) file + named OCContextMenu.pch and a precompiled types file named StdAfx.obj. + +///////////////////////////////////////////////////////////////////////////// +Other notes: + +AppWizard uses "TODO:" comments to indicate parts of the source code you +should add to or customize. + +///////////////////////////////////////////////////////////////////////////// diff --git a/shell_integration/windows/OCContextMenu/dllmain.cpp b/shell_integration/windows/OCContextMenu/dllmain.cpp new file mode 100644 index 000000000..088dea767 --- /dev/null +++ b/shell_integration/windows/OCContextMenu/dllmain.cpp @@ -0,0 +1,108 @@ +/** +* 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 "stdafx.h" + +#include <windows.h> +#include <Guiddef.h> +#include "OCContextMenuRegHandler.h" +#include "OCContextMenuFactory.h" + +// {841A0AAD-AA11-4B50-84D9-7F8E727D77D7} +static const GUID CLSID_FileContextMenuExt = { 0x841a0aad, 0xaa11, 0x4b50, { 0x84, 0xd9, 0x7f, 0x8e, 0x72, 0x7d, 0x77, 0xd7 } }; + +HINSTANCE g_hInst = NULL; +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; + + if (IsEqualCLSID(CLSID_FileContextMenuExt, 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; +}
\ No newline at end of file diff --git a/shell_integration/windows/OCContextMenu/stdafx.cpp b/shell_integration/windows/OCContextMenu/stdafx.cpp new file mode 100644 index 000000000..2a649474d --- /dev/null +++ b/shell_integration/windows/OCContextMenu/stdafx.cpp @@ -0,0 +1,8 @@ +// stdafx.cpp : source file that includes just the standard includes +// OCContextMenu.pch will be the pre-compiled header +// stdafx.obj will contain the pre-compiled type information + +#include "stdafx.h" + +// TODO: reference any additional headers you need in STDAFX.H +// and not in this file diff --git a/shell_integration/windows/OCContextMenu/stdafx.h b/shell_integration/windows/OCContextMenu/stdafx.h new file mode 100644 index 000000000..87d219020 --- /dev/null +++ b/shell_integration/windows/OCContextMenu/stdafx.h @@ -0,0 +1,16 @@ +// stdafx.h : include file for standard system include files, +// or project specific include files that are used frequently, but +// are changed infrequently +// + +#pragma once + +#include "targetver.h" + +#define WIN32_LEAN_AND_MEAN // Exclude rarely-used stuff from Windows headers +// Windows Header Files: +#include <windows.h> +#include <strsafe.h> + + +// TODO: reference additional headers your program requires here diff --git a/shell_integration/windows/OCContextMenu/targetver.h b/shell_integration/windows/OCContextMenu/targetver.h new file mode 100644 index 000000000..87c0086de --- /dev/null +++ b/shell_integration/windows/OCContextMenu/targetver.h @@ -0,0 +1,8 @@ +#pragma once + +// Including SDKDDKVer.h defines the highest available Windows platform. + +// If you wish to build your application for a previous Windows platform, include WinSDKVer.h and +// set the _WIN32_WINNT macro to the platform you wish to support before including SDKDDKVer.h. + +#include <SDKDDKVer.h> diff --git a/shell_integration/windows/OCShellExtensions.sln b/shell_integration/windows/OCShellExtensions.sln index 1bfbbf3ed..4b1395433 100644 --- a/shell_integration/windows/OCShellExtensions.sln +++ b/shell_integration/windows/OCShellExtensions.sln @@ -1,7 +1,7 @@ Microsoft Visual Studio Solution File, Format Version 12.00 # Visual Studio 2013 -VisualStudioVersion = 12.0.30501.0 +VisualStudioVersion = 12.0.31101.0 MinimumVisualStudioVersion = 10.0.40219.1 Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "OCOverlays", "OCOverlays\OCOverlays.vcxproj", "{42EFEC79-5ACA-4F76-955F-15CE4340F6BC}" ProjectSection(ProjectDependencies) = postProject @@ -10,6 +10,11 @@ Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "OCOverlays", "OCOverlays\OC EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "OCUtil", "OCUtil\OCUtil.vcxproj", "{E4F63E19-808D-4234-8DF0-69C5F47C9CD3}" EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "OCContextMenu", "OCContextMenu\OCContextMenu.vcxproj", "{FF34851F-1346-4809-A68A-B1188D7DFF32}" + ProjectSection(ProjectDependencies) = postProject + {E4F63E19-808D-4234-8DF0-69C5F47C9CD3} = {E4F63E19-808D-4234-8DF0-69C5F47C9CD3} + EndProjectSection +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Win32 = Debug|Win32 @@ -34,6 +39,14 @@ Global {E4F63E19-808D-4234-8DF0-69C5F47C9CD3}.Release|Win32.Build.0 = Release|Win32 {E4F63E19-808D-4234-8DF0-69C5F47C9CD3}.Release|x64.ActiveCfg = Release|x64 {E4F63E19-808D-4234-8DF0-69C5F47C9CD3}.Release|x64.Build.0 = Release|x64 + {FF34851F-1346-4809-A68A-B1188D7DFF32}.Debug|Win32.ActiveCfg = Debug|Win32 + {FF34851F-1346-4809-A68A-B1188D7DFF32}.Debug|Win32.Build.0 = Debug|Win32 + {FF34851F-1346-4809-A68A-B1188D7DFF32}.Debug|x64.ActiveCfg = Debug|x64 + {FF34851F-1346-4809-A68A-B1188D7DFF32}.Debug|x64.Build.0 = Debug|x64 + {FF34851F-1346-4809-A68A-B1188D7DFF32}.Release|Win32.ActiveCfg = Release|Win32 + {FF34851F-1346-4809-A68A-B1188D7DFF32}.Release|Win32.Build.0 = Release|Win32 + {FF34851F-1346-4809-A68A-B1188D7DFF32}.Release|x64.ActiveCfg = Release|x64 + {FF34851F-1346-4809-A68A-B1188D7DFF32}.Release|x64.Build.0 = Release|x64 EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE diff --git a/shell_integration/windows/OCUtil/CommunicationSocket.cpp b/shell_integration/windows/OCUtil/CommunicationSocket.cpp index dec2970f6..5403e4869 100644 --- a/shell_integration/windows/OCUtil/CommunicationSocket.cpp +++ b/shell_integration/windows/OCUtil/CommunicationSocket.cpp @@ -60,10 +60,11 @@ bool CommunicationSocket::Connect(const std::wstring &pipename) if (_pipe == INVALID_HANDLE_VALUE) { return false; } + return true; } -bool CommunicationSocket::SendMsg(const wchar_t* message) +bool CommunicationSocket::SendMsg(const wchar_t* message) const { auto utf8_msg = StringUtil::toUtf8(message); @@ -73,7 +74,7 @@ bool CommunicationSocket::SendMsg(const wchar_t* message) if (result) { return true; } else { - Close(); + const_cast<CommunicationSocket*>(this)->Close(); return false; } @@ -91,7 +92,6 @@ bool CommunicationSocket::ReadLine(wstring* response) return false; } - while (true) { int lbPos = 0; auto it = std::find(_buffer.begin() + lbPos, _buffer.end(), '\n'); @@ -104,8 +104,8 @@ bool CommunicationSocket::ReadLine(wstring* response) std::array<char, 128> resp_utf8; DWORD numBytesRead = 0; DWORD totalBytesAvailable = 0; - auto result = PeekNamedPipe(_pipe, NULL, 0, 0, &totalBytesAvailable, 0); - if (!result) { + + if (!PeekNamedPipe(_pipe, NULL, 0, 0, &totalBytesAvailable, 0)) { Close(); return false; } @@ -113,8 +113,7 @@ bool CommunicationSocket::ReadLine(wstring* response) return false; } - result = ReadFile(_pipe, resp_utf8.data(), DWORD(resp_utf8.size()), &numBytesRead, NULL); - if (!result) { + if (!ReadFile(_pipe, resp_utf8.data(), DWORD(resp_utf8.size()), &numBytesRead, NULL)) { Close(); return false; } diff --git a/shell_integration/windows/OCUtil/CommunicationSocket.h b/shell_integration/windows/OCUtil/CommunicationSocket.h index d29d86333..312f47006 100644 --- a/shell_integration/windows/OCUtil/CommunicationSocket.h +++ b/shell_integration/windows/OCUtil/CommunicationSocket.h @@ -32,7 +32,7 @@ public: bool Connect(const std::wstring& pipename); bool Close(); - bool SendMsg(const wchar_t*); + bool SendMsg(const wchar_t*) const; bool ReadLine(std::wstring*); HANDLE Event() { return _pipe; } |