1 /* 2 * PROJECT: sendmail 3 * LICENSE: LGPL-2.1+ (https://spdx.org/licenses/LGPL-2.1+) 4 * PURPOSE: DeskLink implementation 5 * COPYRIGHT: Copyright 2019 Katayama Hirofumi MZ (katayama.hirofumi.mz@gmail.com) 6 */ 7 8 #include "precomp.hpp" 9 10 WINE_DEFAULT_DEBUG_CHANNEL(sendmail); 11 12 CDeskLinkDropHandler::CDeskLinkDropHandler() 13 { 14 InterlockedIncrement(&g_ModuleRefCnt); 15 } 16 17 CDeskLinkDropHandler::~CDeskLinkDropHandler() 18 { 19 InterlockedDecrement(&g_ModuleRefCnt); 20 } 21 22 // IDropTarget 23 STDMETHODIMP 24 CDeskLinkDropHandler::DragEnter(IDataObject *pDataObject, DWORD dwKeyState, 25 POINTL pt, DWORD *pdwEffect) 26 { 27 TRACE("(%p)\n", this); 28 29 *pdwEffect &= DROPEFFECT_LINK; 30 31 return S_OK; 32 } 33 34 STDMETHODIMP 35 CDeskLinkDropHandler::DragOver(DWORD dwKeyState, POINTL pt, DWORD *pdwEffect) 36 { 37 TRACE("(%p)\n", this); 38 39 *pdwEffect &= DROPEFFECT_LINK; 40 41 return S_OK; 42 } 43 44 STDMETHODIMP CDeskLinkDropHandler::DragLeave() 45 { 46 TRACE("(%p)\n", this); 47 return S_OK; 48 } 49 50 STDMETHODIMP 51 CDeskLinkDropHandler::Drop(IDataObject *pDataObject, DWORD dwKeyState, 52 POINTL pt, DWORD *pdwEffect) 53 { 54 TRACE("(%p)\n", this); 55 56 if (!pDataObject) 57 { 58 ERR("pDataObject is NULL\n"); 59 return E_POINTER; 60 } 61 62 FORMATETC fmt; 63 fmt.cfFormat = RegisterClipboardFormatW(CFSTR_SHELLIDLIST); 64 fmt.ptd = NULL; 65 fmt.dwAspect = DVASPECT_CONTENT; 66 fmt.lindex = -1; 67 fmt.tymed = TYMED_HGLOBAL; 68 69 WCHAR szDir[MAX_PATH], szDest[MAX_PATH], szSrc[MAX_PATH]; 70 SHGetSpecialFolderPathW(NULL, szDir, CSIDL_DESKTOPDIRECTORY, FALSE); 71 72 CComPtr<IShellFolder> pDesktop; 73 HRESULT hr = SHGetDesktopFolder(&pDesktop); 74 if (FAILED_UNEXPECTEDLY(hr)) 75 return hr; 76 77 STGMEDIUM medium; 78 hr = pDataObject->GetData(&fmt, &medium); 79 if (FAILED_UNEXPECTEDLY(hr)) 80 return hr; 81 82 LPIDA pida = reinterpret_cast<LPIDA>(GlobalLock(medium.hGlobal)); 83 if (!pida) 84 { 85 ERR("Error locking global\n"); 86 ReleaseStgMedium(&medium); 87 return E_FAIL; 88 } 89 90 LPBYTE pb = reinterpret_cast<LPBYTE>(pida); 91 LPCITEMIDLIST pidlParent = reinterpret_cast<LPCITEMIDLIST>(pb + pida->aoffset[0]); 92 for (UINT i = 1; i <= pida->cidl; ++i) 93 { 94 LPCITEMIDLIST pidlChild = reinterpret_cast<LPCITEMIDLIST>(pb + pida->aoffset[i]); 95 96 CComHeapPtr<ITEMIDLIST> pidl(ILCombine(pidlParent, pidlChild)); 97 if (!pidl) 98 { 99 ERR("Out of memory\n"); 100 break; 101 } 102 103 StringCbCopyW(szDest, sizeof(szDest), szDir); 104 if (SHGetPathFromIDListW(pidl, szSrc)) 105 { 106 CStringW strTitle; 107 strTitle.Format(IDS_SHORTCUT, PathFindFileNameW(szSrc)); 108 109 PathAppendW(szDest, strTitle); 110 PathRemoveExtensionW(szDest); 111 StringCbCatW(szDest, sizeof(szDest), L".lnk"); 112 113 hr = CreateShellLink(szDest, szSrc, NULL, NULL, NULL, NULL, -1, NULL); 114 } 115 else 116 { 117 STRRET strret; 118 hr = pDesktop->GetDisplayNameOf(pidl, SHGDN_INFOLDER, &strret); 119 if (FAILED_UNEXPECTEDLY(hr)) 120 break; 121 122 hr = StrRetToBufW(&strret, pidl, szSrc, _countof(szSrc)); 123 if (FAILED_UNEXPECTEDLY(hr)) 124 break; 125 126 CStringW strTitle; 127 strTitle.Format(IDS_SHORTCUT, szSrc); 128 129 PathAppendW(szDest, strTitle); 130 PathRemoveExtensionW(szDest); 131 StringCbCatW(szDest, sizeof(szDest), L".lnk"); 132 133 hr = CreateShellLink(szDest, NULL, pidl, NULL, NULL, NULL, -1, NULL); 134 } 135 136 if (FAILED_UNEXPECTEDLY(hr)) 137 break; 138 } 139 140 GlobalUnlock(medium.hGlobal); 141 ReleaseStgMedium(&medium); 142 143 return hr; 144 } 145 146 // IPersistFile 147 STDMETHODIMP CDeskLinkDropHandler::GetCurFile(LPOLESTR *ppszFileName) 148 { 149 FIXME("(%p)\n", this); 150 return E_NOTIMPL; 151 } 152 153 STDMETHODIMP CDeskLinkDropHandler::IsDirty() 154 { 155 FIXME("(%p)\n", this); 156 return E_NOTIMPL; 157 } 158 159 STDMETHODIMP CDeskLinkDropHandler::Load(LPCOLESTR pszFileName, DWORD dwMode) 160 { 161 return S_OK; 162 } 163 164 STDMETHODIMP CDeskLinkDropHandler::Save(LPCOLESTR pszFileName, BOOL fRemember) 165 { 166 FIXME("(%p)\n", this); 167 return E_NOTIMPL; 168 } 169 170 STDMETHODIMP CDeskLinkDropHandler::SaveCompleted(LPCOLESTR pszFileName) 171 { 172 FIXME("(%p)\n", this); 173 return E_NOTIMPL; 174 } 175 176 // IPersist 177 STDMETHODIMP CDeskLinkDropHandler::GetClassID(CLSID * lpClassId) 178 { 179 TRACE("(%p)\n", this); 180 181 if (!lpClassId) 182 { 183 ERR("lpClassId is NULL\n"); 184 return E_POINTER; 185 } 186 187 *lpClassId = CLSID_DeskLinkDropHandler; 188 189 return S_OK; 190 } 191