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
CDeskLinkDropHandler()12 CDeskLinkDropHandler::CDeskLinkDropHandler()
13 {
14 InterlockedIncrement(&g_ModuleRefCnt);
15 }
16
~CDeskLinkDropHandler()17 CDeskLinkDropHandler::~CDeskLinkDropHandler()
18 {
19 InterlockedDecrement(&g_ModuleRefCnt);
20 }
21
22 // IDropTarget
23 STDMETHODIMP
DragEnter(IDataObject * pDataObject,DWORD dwKeyState,POINTL pt,DWORD * pdwEffect)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
DragOver(DWORD dwKeyState,POINTL pt,DWORD * pdwEffect)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
DragLeave()44 STDMETHODIMP CDeskLinkDropHandler::DragLeave()
45 {
46 TRACE("(%p)\n", this);
47 return S_OK;
48 }
49
50 STDMETHODIMP
Drop(IDataObject * pDataObject,DWORD dwKeyState,POINTL pt,DWORD * pdwEffect)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
GetCurFile(LPOLESTR * ppszFileName)162 STDMETHODIMP CDeskLinkDropHandler::GetCurFile(LPOLESTR *ppszFileName)
163 {
164 FIXME("(%p)\n", this);
165 return E_NOTIMPL;
166 }
167
IsDirty()168 STDMETHODIMP CDeskLinkDropHandler::IsDirty()
169 {
170 FIXME("(%p)\n", this);
171 return E_NOTIMPL;
172 }
173
Load(LPCOLESTR pszFileName,DWORD dwMode)174 STDMETHODIMP CDeskLinkDropHandler::Load(LPCOLESTR pszFileName, DWORD dwMode)
175 {
176 return S_OK;
177 }
178
Save(LPCOLESTR pszFileName,BOOL fRemember)179 STDMETHODIMP CDeskLinkDropHandler::Save(LPCOLESTR pszFileName, BOOL fRemember)
180 {
181 FIXME("(%p)\n", this);
182 return E_NOTIMPL;
183 }
184
SaveCompleted(LPCOLESTR pszFileName)185 STDMETHODIMP CDeskLinkDropHandler::SaveCompleted(LPCOLESTR pszFileName)
186 {
187 FIXME("(%p)\n", this);
188 return E_NOTIMPL;
189 }
190
191 // IPersist
GetClassID(CLSID * lpClassId)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