Reactos
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
10WINE_DEFAULT_DEBUG_CHANNEL(sendmail);
11
12BEGIN_OBJECT_MAP(ObjectMap)
13 OBJECT_ENTRY(CLSID_DeskLinkDropHandler, CDeskLinkDropHandler)
14END_OBJECT_MAP()
15
16CComModule gModule;
17LONG g_ModuleRefCnt = 0;
18HINSTANCE g_hModule;
19
20static BOOL
21CreateEmptyFile(LPCWSTR pszFile)
22{
23 HANDLE hFile;
24 hFile = CreateFileW(pszFile, GENERIC_WRITE, FILE_SHARE_READ, NULL,
25 CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
26 if (hFile != INVALID_HANDLE_VALUE)
27 {
28 CloseHandle(hFile);
29 return TRUE;
30 }
31 return FALSE;
32}
33
34static HRESULT
35CreateSendToDeskLink(LPCWSTR pszSendTo)
36{
37 WCHAR szTarget[MAX_PATH], szSendToFile[MAX_PATH];
38
39 LoadStringW(g_hModule, IDS_DESKLINK, szTarget, _countof(szTarget));
40 StringCbCatW(szTarget, sizeof(szTarget), L".DeskLink");
41
42 StringCbCopyW(szSendToFile, sizeof(szSendToFile), pszSendTo);
43 PathAppendW(szSendToFile, szTarget);
44
45 if (!CreateEmptyFile(szSendToFile))
46 {
47 ERR("CreateEmptyFile('%ls')\n", szSendToFile);
48 return E_FAIL;
49 }
50 return S_OK;
51}
52
53static HRESULT
54GetDefaultUserSendTo(LPWSTR pszPath)
55{
56 return SHGetFolderPathW(NULL, CSIDL_SENDTO, INVALID_HANDLE_VALUE,
57 SHGFP_TYPE_DEFAULT, pszPath);
58}
59
60STDAPI DllCanUnloadNow(void)
61{
62 if (g_ModuleRefCnt)
63 return S_FALSE;
64 return gModule.DllCanUnloadNow();
65}
66
67STDAPI DllGetClassObject(REFCLSID rclsid, REFIID riid, LPVOID *ppv)
68{
69 TRACE("CLSID:%s,IID:%s\n", wine_dbgstr_guid(&rclsid), wine_dbgstr_guid(&riid));
70
71 HRESULT hr = gModule.DllGetClassObject(rclsid, riid, ppv);
72
73 TRACE("-- pointer to class factory: %p\n", *ppv);
74
75 return hr;
76}
77
78STDAPI DllRegisterServer(void)
79{
80 HRESULT hr = gModule.DllRegisterServer(FALSE);
81 if (FAILED_UNEXPECTEDLY(hr))
82 return hr;
83
84 WCHAR szSendTo[MAX_PATH];
85 hr = GetDefaultUserSendTo(szSendTo);
86 if (SUCCEEDED(hr))
87 CreateSendToDeskLink(szSendTo);
88
89 return S_OK;
90}
91
92STDAPI DllUnregisterServer(void)
93{
94 HRESULT hr = gModule.DllUnregisterServer(FALSE);
95 if (FAILED_UNEXPECTEDLY(hr))
96 return hr;
97
98 return S_OK;
99}
100
101HRESULT
102CreateShellLink(
103 LPCWSTR pszLinkPath,
104 LPCWSTR pszTargetPath OPTIONAL,
105 LPCITEMIDLIST pidlTarget OPTIONAL,
106 LPCWSTR pszArg OPTIONAL,
107 LPCWSTR pszDir OPTIONAL,
108 LPCWSTR pszIconPath OPTIONAL,
109 INT iIconNr OPTIONAL,
110 LPCWSTR pszComment OPTIONAL)
111{
112 CComPtr<IShellLinkW> psl;
113 HRESULT hr = CoCreateInstance(CLSID_ShellLink, NULL,
114 CLSCTX_INPROC_SERVER,
115 IID_PPV_ARG(IShellLinkW, &psl));
116 if (FAILED_UNEXPECTEDLY(hr))
117 return hr;
118
119 if (pszTargetPath)
120 {
121 hr = psl->SetPath(pszTargetPath);
122 if (FAILED_UNEXPECTEDLY(hr))
123 return hr;
124 }
125 else if (pidlTarget)
126 {
127 hr = psl->SetIDList(pidlTarget);
128 if (FAILED_UNEXPECTEDLY(hr))
129 return hr;
130 }
131 else
132 {
133 ERR("invalid argument\n");
134 return E_INVALIDARG;
135 }
136
137 if (pszArg)
138 hr = psl->SetArguments(pszArg);
139
140 if (pszDir)
141 hr = psl->SetWorkingDirectory(pszDir);
142
143 if (pszIconPath)
144 hr = psl->SetIconLocation(pszIconPath, iIconNr);
145
146 if (pszComment)
147 hr = psl->SetDescription(pszComment);
148
149 CComPtr<IPersistFile> ppf;
150 hr = psl->QueryInterface(IID_PPV_ARG(IPersistFile, &ppf));
151 if (FAILED_UNEXPECTEDLY(hr))
152 return hr;
153
154 hr = ppf->Save(pszLinkPath, TRUE);
155 if (FAILED_UNEXPECTEDLY(hr))
156 return hr;
157
158 return hr;
159}
160
161STDAPI_(BOOL) DllMain(HINSTANCE hInstance, DWORD dwReason, LPVOID fImpLoad)
162{
163 TRACE("%p 0x%x %p\n", hInstance, dwReason, fImpLoad);
164 if (dwReason == DLL_PROCESS_ATTACH)
165 {
166 g_hModule = hInstance;
167 gModule.Init(ObjectMap, hInstance, NULL);
168 DisableThreadLibraryCalls(hInstance);
169 }
170 else if (dwReason == DLL_PROCESS_DETACH)
171 {
172 gModule.Term();
173 }
174 return TRUE;
175}