diff --git a/dll/shellext/CMakeLists.txt b/dll/shellext/CMakeLists.txt index 4baed6eb048..8d005319c4c 100644 --- a/dll/shellext/CMakeLists.txt +++ b/dll/shellext/CMakeLists.txt @@ -5,6 +5,7 @@ add_subdirectory(deskadp) add_subdirectory(deskmon) add_subdirectory(devcpux) add_subdirectory(fontext) +add_subdirectory(mydocs) add_subdirectory(netplwiz) add_subdirectory(netshell) add_subdirectory(ntobjshex) diff --git a/dll/shellext/mydocs/CMakeLists.txt b/dll/shellext/mydocs/CMakeLists.txt new file mode 100644 index 00000000000..0c9649c25f4 --- /dev/null +++ b/dll/shellext/mydocs/CMakeLists.txt @@ -0,0 +1,35 @@ +set_cpp(WITH_RUNTIME) +spec2def(mydocs.dll mydocs.spec) + +add_definitions( + -D_WINE + -D_ATL_NO_EXCEPTIONS) + +if(NOT MSVC) + # HACK: this should be enabled globally! + add_compile_flags_language("-std=c++11" "CXX") +endif() + +include_directories( + ${REACTOS_SOURCE_DIR}/sdk/lib/atl + ${REACTOS_SOURCE_DIR}) + +file(GLOB_RECURSE mydocs_rc_deps res/*.*) +add_rc_deps(mydocs.rc ${mydocs_rc_deps}) + +list(APPEND SOURCE + CMyDocsDropHandler.cpp + mydocs.cpp + precomp.hpp) + +add_library(mydocs MODULE + ${SOURCE} + mydocs.rc + ${CMAKE_CURRENT_BINARY_DIR}/mydocs.def) + +set_module_type(mydocs win32dll UNICODE) +target_link_libraries(mydocs uuid wine) +add_delay_importlibs(mydocs ole32 oleaut32) +add_importlibs(mydocs advapi32 shell32 user32 comctl32 shlwapi msvcrt kernel32 ntdll) +add_pch(mydocs precomp.hpp SOURCE) +add_cd_file(TARGET mydocs DESTINATION reactos/system32 FOR all) diff --git a/dll/shellext/mydocs/CMyDocsDropHandler.cpp b/dll/shellext/mydocs/CMyDocsDropHandler.cpp new file mode 100644 index 00000000000..c21be8964b9 --- /dev/null +++ b/dll/shellext/mydocs/CMyDocsDropHandler.cpp @@ -0,0 +1,214 @@ +/* + * PROJECT: mydocs + * LICENSE: LGPL-2.1+ (https://spdx.org/licenses/LGPL-2.1+) + * PURPOSE: MyDocs implementation + * COPYRIGHT: Copyright 2020 Katayama Hirofumi MZ (katayama.hirofumi.mz@gmail.com) + */ + +#include "precomp.hpp" + +WINE_DEFAULT_DEBUG_CHANNEL(mydocs); + +static CLIPFORMAT g_cfHIDA = 0; + +CMyDocsDropHandler::CMyDocsDropHandler() +{ + InterlockedIncrement(&g_ModuleRefCnt); +} + +CMyDocsDropHandler::~CMyDocsDropHandler() +{ + InterlockedDecrement(&g_ModuleRefCnt); +} + +// IDropTarget +STDMETHODIMP +CMyDocsDropHandler::DragEnter(IDataObject *pDataObject, DWORD dwKeyState, + POINTL pt, DWORD *pdwEffect) +{ + TRACE("(%p)\n", this); + + *pdwEffect &= DROPEFFECT_COPY; // Copy only + + return S_OK; +} + +STDMETHODIMP +CMyDocsDropHandler::DragOver(DWORD dwKeyState, POINTL pt, DWORD *pdwEffect) +{ + TRACE("(%p)\n", this); + + *pdwEffect &= DROPEFFECT_COPY; // Copy only + + return S_OK; +} + +STDMETHODIMP CMyDocsDropHandler::DragLeave() +{ + TRACE("(%p)\n", this); + return S_OK; +} + +STDMETHODIMP +CMyDocsDropHandler::Drop(IDataObject *pDataObject, DWORD dwKeyState, + POINTL pt, DWORD *pdwEffect) +{ + TRACE("(%p)\n", this); + + if (!pDataObject) + { + ERR("pDataObject is NULL\n"); + *pdwEffect = 0; + DragLeave(); + return E_POINTER; + } + + CComPtr pDesktop; + HRESULT hr = SHGetDesktopFolder(&pDesktop); + if (FAILED_UNEXPECTEDLY(hr)) + return hr; + + // get the clipboard format + if (g_cfHIDA == 0) + g_cfHIDA = ::RegisterClipboardFormatW(CFSTR_SHELLIDLIST); + + // Retrieve an HIDA (handle of IDA) + STGMEDIUM medium; + FORMATETC fmt = { g_cfHIDA, NULL, DVASPECT_CONTENT, -1, TYMED_HGLOBAL }; + hr = pDataObject->GetData(&fmt, &medium); + if (FAILED_UNEXPECTEDLY(hr)) + { + *pdwEffect = 0; + DragLeave(); + return E_FAIL; + } + + // lock HIDA + LPIDA pida = reinterpret_cast(GlobalLock(medium.hGlobal)); + UINT iItem, cItems = pida->cidl; + + // get the path of "My Documents" + WCHAR szzDir[MAX_PATH + 1]; + SHGetSpecialFolderPathW(NULL, szzDir, CSIDL_PERSONAL, FALSE); + szzDir[lstrlenW(szzDir) + 1] = 0; // ends with double NULs + + // for all source items + CStringW strSrcList; + WCHAR szSrc[MAX_PATH]; + const BYTE *pb = reinterpret_cast(pida); + PCIDLIST_ABSOLUTE pidlParent = reinterpret_cast(pb + pida->aoffset[0]); + for (iItem = 0; iItem < cItems; ++iItem) + { + // query source pidl + PCITEMID_CHILD pidlChild = reinterpret_cast(pb + pida->aoffset[iItem + 1]); + CComHeapPtr pidl(ILCombine(pidlParent, pidlChild)); + + // can get path? + szSrc[0] = 0; + if (!SHGetPathFromIDListW(pidl, szSrc)) + { + // try to retrieve path from desktop + STRRET strret; + hr = pDesktop->GetDisplayNameOf(pidl, SHGDN_INFOLDER, &strret); + if (FAILED_UNEXPECTEDLY(hr)) + break; + hr = StrRetToBufW(&strret, pidl, szSrc, _countof(szSrc)); + if (FAILED_UNEXPECTEDLY(hr)) + break; + if (!PathFileExistsW(szSrc)) + break; + } + + if (iItem > 0) + strSrcList += L'|'; // separator is '|' + strSrcList += szSrc; + } + + // unlock HIDA + GlobalUnlock(medium.hGlobal); + + if (iItem != cItems) + { + // source not found + CStringW strText; + strText.Format(IDS_NOSRCFILEFOUND, szSrc[0] ? szSrc : L"(null)"); + MessageBoxW(NULL, strText, NULL, MB_ICONERROR); + + *pdwEffect = 0; + DragLeave(); + return E_FAIL; + } + + strSrcList += L"||"; // double separators + + // lock the buffer + LPWSTR pszzSrcList = strSrcList.GetBuffer(); + + // convert every separator to a NUL + INT cch = strSrcList.GetLength(); + for (INT i = 0; i < cch; ++i) + { + if (pszzSrcList[i] == L'|') + pszzSrcList[i] = L'\0'; + } + + // copy them + SHFILEOPSTRUCTW fileop = { NULL }; + fileop.wFunc = FO_COPY; + fileop.pFrom = pszzSrcList; + fileop.pTo = szzDir; + fileop.fFlags = FOF_ALLOWUNDO | FOF_FILESONLY | FOF_MULTIDESTFILES | FOF_NOCONFIRMMKDIR; + SHFileOperationW(&fileop); + + // unlock buffer + strSrcList.ReleaseBuffer(); + + DragLeave(); + return hr; +} + +// IPersistFile +STDMETHODIMP CMyDocsDropHandler::GetCurFile(LPOLESTR *ppszFileName) +{ + FIXME("(%p)\n", this); + return E_NOTIMPL; +} + +STDMETHODIMP CMyDocsDropHandler::IsDirty() +{ + FIXME("(%p)\n", this); + return E_NOTIMPL; +} + +STDMETHODIMP CMyDocsDropHandler::Load(LPCOLESTR pszFileName, DWORD dwMode) +{ + return S_OK; +} + +STDMETHODIMP CMyDocsDropHandler::Save(LPCOLESTR pszFileName, BOOL fRemember) +{ + FIXME("(%p)\n", this); + return E_NOTIMPL; +} + +STDMETHODIMP CMyDocsDropHandler::SaveCompleted(LPCOLESTR pszFileName) +{ + FIXME("(%p)\n", this); + return E_NOTIMPL; +} + +// IPersist +STDMETHODIMP CMyDocsDropHandler::GetClassID(CLSID * lpClassId) +{ + TRACE("(%p)\n", this); + + if (!lpClassId) + { + ERR("lpClassId is NULL\n"); + return E_POINTER; + } + + *lpClassId = CLSID_MyDocsDropHandler; + + return S_OK; +} diff --git a/dll/shellext/mydocs/CMyDocsDropHandler.hpp b/dll/shellext/mydocs/CMyDocsDropHandler.hpp new file mode 100644 index 00000000000..f9993a8ae6c --- /dev/null +++ b/dll/shellext/mydocs/CMyDocsDropHandler.hpp @@ -0,0 +1,50 @@ +/* + * PROJECT: mydocs + * LICENSE: LGPL-2.1+ (https://spdx.org/licenses/LGPL-2.1+) + * PURPOSE: MyDocs implementation + * COPYRIGHT: Copyright 2020 Katayama Hirofumi MZ (katayama.hirofumi.mz@gmail.com) + */ + +#pragma once + +#include "resource.h" + +class CMyDocsDropHandler : + public CComCoClass, + public CComObjectRootEx, + public IDropTarget, + public IPersistFile +{ +public: + CMyDocsDropHandler(); + ~CMyDocsDropHandler(); + + // IDropTarget + STDMETHODIMP DragEnter(IDataObject *pDataObject, DWORD dwKeyState, + POINTL pt, DWORD *pdwEffect); + STDMETHODIMP DragOver(DWORD dwKeyState, POINTL pt, DWORD *pdwEffect); + STDMETHODIMP DragLeave(); + STDMETHODIMP Drop(IDataObject *pDataObject, DWORD dwKeyState, POINTL pt, + DWORD *pdwEffect); + + // IPersist + STDMETHODIMP GetClassID(CLSID *lpClassId); + + // IPersistFile + STDMETHODIMP GetCurFile(LPOLESTR *ppszFileName); + STDMETHODIMP IsDirty(); + STDMETHODIMP Load(LPCOLESTR pszFileName, DWORD dwMode); + STDMETHODIMP Save(LPCOLESTR pszFileName, BOOL fRemember); + STDMETHODIMP SaveCompleted(LPCOLESTR pszFileName); + + DECLARE_REGISTRY_RESOURCEID(IDR_MYDOCS) + DECLARE_NOT_AGGREGATABLE(CMyDocsDropHandler) + + DECLARE_PROTECT_FINAL_CONSTRUCT() + + BEGIN_COM_MAP(CMyDocsDropHandler) + COM_INTERFACE_ENTRY_IID(IID_IPersist, IPersist) + COM_INTERFACE_ENTRY_IID(IID_IPersistFile, IPersistFile) + COM_INTERFACE_ENTRY_IID(IID_IDropTarget, IDropTarget) + END_COM_MAP() +}; diff --git a/dll/shellext/mydocs/lang/en-US.rc b/dll/shellext/mydocs/lang/en-US.rc new file mode 100644 index 00000000000..f38a277fa2f --- /dev/null +++ b/dll/shellext/mydocs/lang/en-US.rc @@ -0,0 +1,6 @@ +LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US + +STRINGTABLE +{ + IDS_NOSRCFILEFOUND "Source file or folder '%ls' is not found." +} diff --git a/dll/shellext/mydocs/mydocs.cpp b/dll/shellext/mydocs/mydocs.cpp new file mode 100644 index 00000000000..c5954c1ff88 --- /dev/null +++ b/dll/shellext/mydocs/mydocs.cpp @@ -0,0 +1,68 @@ +/* + * PROJECT: mydocs + * LICENSE: LGPL-2.1+ (https://spdx.org/licenses/LGPL-2.1+) + * PURPOSE: MyDocs implementation + * COPYRIGHT: Copyright 2019 Katayama Hirofumi MZ (katayama.hirofumi.mz@gmail.com) + */ + +#include "precomp.hpp" + +WINE_DEFAULT_DEBUG_CHANNEL(mydocs); + +BEGIN_OBJECT_MAP(ObjectMap) + OBJECT_ENTRY(CLSID_MyDocsDropHandler, CMyDocsDropHandler) +END_OBJECT_MAP() + +CComModule gModule; +LONG g_ModuleRefCnt = 0; + +STDAPI DllCanUnloadNow(void) +{ + if (g_ModuleRefCnt) + return S_FALSE; + return gModule.DllCanUnloadNow(); +} + +STDAPI DllGetClassObject(REFCLSID rclsid, REFIID riid, LPVOID *ppv) +{ + TRACE("CLSID:%s,IID:%s\n", wine_dbgstr_guid(&rclsid), wine_dbgstr_guid(&riid)); + + HRESULT hr = gModule.DllGetClassObject(rclsid, riid, ppv); + + TRACE("-- pointer to class factory: %p\n", *ppv); + + return hr; +} + +STDAPI DllRegisterServer(void) +{ + HRESULT hr = gModule.DllRegisterServer(FALSE); + if (FAILED_UNEXPECTEDLY(hr)) + return hr; + + return S_OK; +} + +STDAPI DllUnregisterServer(void) +{ + HRESULT hr = gModule.DllUnregisterServer(FALSE); + if (FAILED_UNEXPECTEDLY(hr)) + return hr; + + return S_OK; +} + +STDAPI_(BOOL) DllMain(HINSTANCE hInstance, DWORD dwReason, LPVOID fImpLoad) +{ + TRACE("%p 0x%x %p\n", hInstance, dwReason, fImpLoad); + if (dwReason == DLL_PROCESS_ATTACH) + { + gModule.Init(ObjectMap, hInstance, NULL); + DisableThreadLibraryCalls(hInstance); + } + else if (dwReason == DLL_PROCESS_DETACH) + { + gModule.Term(); + } + return TRUE; +} diff --git a/dll/shellext/mydocs/mydocs.rc b/dll/shellext/mydocs/mydocs.rc new file mode 100644 index 00000000000..8adeb54160c --- /dev/null +++ b/dll/shellext/mydocs/mydocs.rc @@ -0,0 +1,23 @@ +/* + * PROJECT: mydocs + * LICENSE: LGPL-2.1+ (https://spdx.org/licenses/LGPL-2.1+) + * PURPOSE: MyDocs implementation + * COPYRIGHT: Copyright 2020 Katayama Hirofumi MZ (katayama.hirofumi.mz@gmail.com) + */ + +#include +#include +#include "resource.h" + +#include "mydocs_version.rc" + +/* UTF-8 */ +#pragma code_page(65001) + +LANGUAGE LANG_NEUTRAL, SUBLANG_NEUTRAL + +IDR_MYDOCS REGISTRY "res/mydocs.rgs" + +#ifdef LANGUAGE_EN_US + #include "lang/en-US.rc" +#endif diff --git a/dll/shellext/mydocs/mydocs.spec b/dll/shellext/mydocs/mydocs.spec new file mode 100644 index 00000000000..b16365d0c9f --- /dev/null +++ b/dll/shellext/mydocs/mydocs.spec @@ -0,0 +1,4 @@ +@ stdcall -private DllCanUnloadNow() +@ stdcall -private DllGetClassObject(ptr ptr ptr) +@ stdcall -private DllRegisterServer() +@ stdcall -private DllUnregisterServer() diff --git a/dll/shellext/mydocs/mydocs_version.h b/dll/shellext/mydocs/mydocs_version.h new file mode 100644 index 00000000000..4ce4d8b4fe6 --- /dev/null +++ b/dll/shellext/mydocs/mydocs_version.h @@ -0,0 +1,15 @@ +/* + * PROJECT: mydocs + * LICENSE: LGPL-2.1+ (https://spdx.org/licenses/LGPL-2.1+) + * PURPOSE: MyDocs implementation + * COPYRIGHT: Copyright 2020 Katayama Hirofumi MZ (katayama.hirofumi.mz@gmail.com) + */ + +#pragma once + +#define WINE_FILEVERSION_MAJOR 6 +#define WINE_FILEVERSION_MINOR 0 +#define WINE_FILEVERSION_BUILD 3790 +#define WINE_FILEVERSION_PLATFORMID 3959 + +#define WINE_FILEVERSION_STR "6.0.3790.3959" diff --git a/dll/shellext/mydocs/mydocs_version.rc b/dll/shellext/mydocs/mydocs_version.rc new file mode 100644 index 00000000000..937b11947e8 --- /dev/null +++ b/dll/shellext/mydocs/mydocs_version.rc @@ -0,0 +1,14 @@ +/* + * PROJECT: mydocs + * LICENSE: LGPL-2.1+ (https://spdx.org/licenses/LGPL-2.1+) + * PURPOSE: MyDocs implementation + * COPYRIGHT: Copyright 2020 Katayama Hirofumi MZ (katayama.hirofumi.mz@gmail.com) + */ + +#include "mydocs_version.h" + +#define WINE_OLESELFREGISTER +#define WINE_FILEVERSION WINE_FILEVERSION_MAJOR,WINE_FILEVERSION_MINOR,WINE_FILEVERSION_BUILD,WINE_FILEVERSION_PLATFORMID +#define WINE_FILENAME_STR "mydocs.dll" + +#include diff --git a/dll/shellext/mydocs/precomp.hpp b/dll/shellext/mydocs/precomp.hpp new file mode 100644 index 00000000000..4ad886e0146 --- /dev/null +++ b/dll/shellext/mydocs/precomp.hpp @@ -0,0 +1,29 @@ +/* + * PROJECT: mydocs + * LICENSE: LGPL-2.1+ (https://spdx.org/licenses/LGPL-2.1+) + * PURPOSE: MyDocs implementation + * COPYRIGHT: Copyright 2020 Katayama Hirofumi MZ (katayama.hirofumi.mz@gmail.com) + */ + +#define COBJMACROS +#define WIN32_NO_STATUS +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "CMyDocsDropHandler.hpp" + +#include "mydocs_version.h" +#include "resource.h" + +extern LONG g_ModuleRefCnt; diff --git a/dll/shellext/mydocs/res/mydocs.rgs b/dll/shellext/mydocs/res/mydocs.rgs new file mode 100644 index 00000000000..40bbe0da0ba --- /dev/null +++ b/dll/shellext/mydocs/res/mydocs.rgs @@ -0,0 +1,35 @@ +HKCR +{ + NoRemove CLSID + { + '{ECF03A32-103D-11d2-854D-006008059367}' = s 'MyDocs Drop Target' + { + val 'NeverShowExt' = s '' + val 'NoOpen' = s 'Drag Files onto this icon to store them in My Documents' + val EditFlags = d '0x01' + DefaultIcon = e '%%SystemRoot%%\system32\shell32.dll,-235' + { + } + InprocServer32 = s '%MODULE%' + { + val ThreadingModel = s 'Apartment' + } + 'shellex' + { + 'DropHandler' = s '{ECF03A32-103D-11d2-854D-006008059367}' + { + } + } + } + } +} +HKLM +{ + NoRemove Software + { + NoRemove Classes + { + '.mydocs' = s 'CLSID\{ECF03A32-103D-11d2-854D-006008059367}' + } + } +} diff --git a/dll/shellext/mydocs/resource.h b/dll/shellext/mydocs/resource.h new file mode 100644 index 00000000000..0cbcb889962 --- /dev/null +++ b/dll/shellext/mydocs/resource.h @@ -0,0 +1,15 @@ +/* + * PROJECT: mydocs + * LICENSE: LGPL-2.1+ (https://spdx.org/licenses/LGPL-2.1+) + * PURPOSE: MyDocs implementation + * COPYRIGHT: Copyright 2020 Katayama Hirofumi MZ (katayama.hirofumi.mz@gmail.com) + */ + +#ifndef RESOURCE_H_ +#define RESOURCE_H_ + +#define IDR_MYDOCS 100 + +#define IDS_NOSRCFILEFOUND 100 + +#endif diff --git a/media/inf/syssetup.inf b/media/inf/syssetup.inf index d70d83c7d13..0de1dc980ca 100644 --- a/media/inf/syssetup.inf +++ b/media/inf/syssetup.inf @@ -86,6 +86,7 @@ AddReg=Classes 11,,msxml3.dll,1 11,,msxml4.dll,1 11,,msxml6.dll,1 +11,,mydocs.dll,1 11,,netshell.dll,1 11,,ntobjshex.dll,1 11,,objsel.dll,1 diff --git a/sdk/include/reactos/shlguid_undoc.h b/sdk/include/reactos/shlguid_undoc.h index 7360ab57460..42021b6cdb1 100644 --- a/sdk/include/reactos/shlguid_undoc.h +++ b/sdk/include/reactos/shlguid_undoc.h @@ -112,6 +112,7 @@ DEFINE_GUID(CLSID_ShellNetDefExt, 0x86422020, 0x42A0, 0x1069, 0xA2, 0xE DEFINE_GUID(CLSID_ExeDropHandler, 0x86C86720, 0x42A0, 0x1069, 0xA2, 0xE8, 0x08, 0x00, 0x2B, 0x30, 0x30, 0x9D); DEFINE_GUID(CLSID_DeskLinkDropHandler, 0x9E56BE61, 0xC50F, 0x11CF, 0x9A, 0x2C, 0x00, 0xA0, 0xC9, 0x0A, 0x90, 0xCE); +DEFINE_GUID(CLSID_MyDocsDropHandler, 0xECF03A32, 0x103D, 0x11d2, 0x85, 0x4D, 0x00, 0x60, 0x08, 0x05, 0x93, 0x67); DEFINE_GUID(CLSID_MergedFolder, 0x26FDC864, 0xBE88, 0x46E7, 0x92, 0x35, 0x03, 0x2D, 0x8E, 0xA5, 0x16, 0x2E); DEFINE_GUID(IID_IAugmentedShellFolder, 0x91EA3F8C, 0xC99B, 0x11D0, 0x98, 0x15, 0x00, 0xC0, 0x4F, 0xD9, 0x19, 0x72);