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 WCHAR szDir[MAX_PATH], szDest[MAX_PATH], szSrc[MAX_PATH]; 63 SHGetSpecialFolderPathW(NULL, szDir, CSIDL_DESKTOPDIRECTORY, FALSE); 64 65 CComPtr<IShellFolder> pDesktop; 66 HRESULT hr = SHGetDesktopFolder(&pDesktop); 67 if (FAILED_UNEXPECTEDLY(hr)) 68 return hr; 69 70 CDataObjectHIDA pida(pDataObject); 71 if (FAILED_UNEXPECTEDLY(pida.hr())) 72 return pida.hr(); 73 74 LPCITEMIDLIST pidlParent = HIDA_GetPIDLFolder(pida); 75 for (UINT i = 0; i < pida->cidl; ++i) 76 { 77 LPCITEMIDLIST pidlChild = HIDA_GetPIDLItem(pida, i); 78 79 CComHeapPtr<ITEMIDLIST> pidl(ILCombine(pidlParent, pidlChild)); 80 if (!pidl) 81 { 82 ERR("Out of memory\n"); 83 break; 84 } 85 86 StringCbCopyW(szDest, sizeof(szDest), szDir); 87 if (SHGetPathFromIDListW(pidl, szSrc)) 88 { 89 LPCWSTR pszSourceExt; 90 BOOL bIsLink; 91 92 pszSourceExt = PathFindExtensionW(szSrc); 93 bIsLink = ((_wcsicmp(pszSourceExt, L".lnk") == 0) || 94 (_wcsicmp(pszSourceExt, L".url") == 0)); 95 96 if (bIsLink) 97 { 98 PathAppendW(szDest, PathFindFileNameW(szSrc)); 99 } 100 else 101 { 102 CStringW strTitle; 103 strTitle.Format(IDS_SHORTCUT, PathFindFileNameW(szSrc)); 104 105 PathAppendW(szDest, strTitle); 106 PathRemoveExtensionW(szDest); 107 StringCbCatW(szDest, sizeof(szDest), L".lnk"); 108 } 109 110 if (PathFileExistsW(szDest)) 111 { 112 CStringW strName(PathFindFileNameW(szDest)); 113 PathYetAnotherMakeUniqueName(szDest, szDir, NULL, strName); 114 } 115 116 if (bIsLink) 117 { 118 hr = (CopyFileW(szSrc, szDest, TRUE) ? S_OK : E_FAIL); 119 } 120 else if (PathIsDirectoryW(szSrc) || (_wcsicmp(pszSourceExt, L".zip") == 0)) 121 { 122 hr = CreateShellLink(szDest, szSrc, NULL, NULL, NULL, NULL, -1, NULL); 123 } 124 else 125 { 126 /* Set default working directory for the shortcut */ 127 CStringW strWorkingDir(szSrc); 128 PathRemoveFileSpecW(strWorkingDir.GetBuffer()); 129 130 hr = CreateShellLink(szDest, szSrc, NULL, NULL, strWorkingDir, NULL, -1, NULL); 131 } 132 } 133 else 134 { 135 STRRET strret; 136 hr = pDesktop->GetDisplayNameOf(pidl, SHGDN_INFOLDER, &strret); 137 if (FAILED_UNEXPECTEDLY(hr)) 138 break; 139 140 hr = StrRetToBufW(&strret, pidl, szSrc, _countof(szSrc)); 141 if (FAILED_UNEXPECTEDLY(hr)) 142 break; 143 144 CStringW strTitle; 145 strTitle.Format(IDS_SHORTCUT, szSrc); 146 147 PathAppendW(szDest, strTitle); 148 PathRemoveExtensionW(szDest); 149 StringCbCatW(szDest, sizeof(szDest), L".lnk"); 150 151 hr = CreateShellLink(szDest, NULL, pidl, NULL, NULL, NULL, -1, NULL); 152 } 153 154 if (FAILED_UNEXPECTEDLY(hr)) 155 break; 156 } 157 158 return hr; 159 } 160 161 // IPersistFile 162 STDMETHODIMP CDeskLinkDropHandler::GetCurFile(LPOLESTR *ppszFileName) 163 { 164 FIXME("(%p)\n", this); 165 return E_NOTIMPL; 166 } 167 168 STDMETHODIMP CDeskLinkDropHandler::IsDirty() 169 { 170 FIXME("(%p)\n", this); 171 return E_NOTIMPL; 172 } 173 174 STDMETHODIMP CDeskLinkDropHandler::Load(LPCOLESTR pszFileName, DWORD dwMode) 175 { 176 return S_OK; 177 } 178 179 STDMETHODIMP CDeskLinkDropHandler::Save(LPCOLESTR pszFileName, BOOL fRemember) 180 { 181 FIXME("(%p)\n", this); 182 return E_NOTIMPL; 183 } 184 185 STDMETHODIMP CDeskLinkDropHandler::SaveCompleted(LPCOLESTR pszFileName) 186 { 187 FIXME("(%p)\n", this); 188 return E_NOTIMPL; 189 } 190 191 // IPersist 192 STDMETHODIMP CDeskLinkDropHandler::GetClassID(CLSID * lpClassId) 193 { 194 TRACE("(%p)\n", this); 195 196 if (!lpClassId) 197 { 198 ERR("lpClassId is NULL\n"); 199 return E_POINTER; 200 } 201 202 *lpClassId = CLSID_DeskLinkDropHandler; 203 204 return S_OK; 205 } 206