Wed, 31 Dec 2014 06:55:50 +0100
Added tag UPSTREAM_283F7C6 for changeset ca08bd8f51b2
1 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* This Source Code Form is subject to the terms of the Mozilla Public
3 * License, v. 2.0. If a copy of the MPL was not distributed with this file,
4 * You can obtain one at http://mozilla.org/MPL/2.0/. */
6 #undef WINVER
7 #undef _WIN32_WINNT
8 #define WINVER 0x602
9 #define _WIN32_WINNT 0x602
11 #include <windows.h>
12 #include <shobjidl.h>
13 #include <objbase.h>
14 #include <shlguid.h>
15 #include <shlobj.h>
16 #define INITGUID
17 #include <propvarutil.h>
18 #include <propkey.h>
19 #include <stdio.h>
21 // Indicates that an application supports dual desktop and immersive modes. In Windows 8, this property is only applicable for web browsers.
22 //DEFINE_PROPERTYKEY(PKEY_AppUserModel_IsDualMode, 0x9F4C2855, 0x9F79, 0x4B39, 0xA8, 0xD0, 0xE1, 0xD4, 0x2D, 0xE1, 0xD5, 0xF3, 11);
24 void DumpParameters(LPCWSTR aTargetPath, LPCWSTR aShortcutPath, LPCWSTR aAppModelID, LPCWSTR aDescription)
25 {
26 if (aTargetPath)
27 wprintf(L"target path: '%s'\n", aTargetPath);
28 if (aShortcutPath)
29 wprintf(L"shortcut path: '%s'\n", aShortcutPath);
30 if (aAppModelID)
31 wprintf(L"app id: '%s'\n", aAppModelID);
32 if (aDescription)
33 wprintf(L"description: '%s'\n", aDescription);
34 }
36 HRESULT
37 SetShortcutProps(LPCWSTR aShortcutPath, LPCWSTR aAppModelID, bool aSetID, bool aSetMode)
38 {
39 HRESULT hres;
40 ::CoInitialize(nullptr);
42 IPropertyStore *m_pps = nullptr;
43 if (FAILED(hres = SHGetPropertyStoreFromParsingName(aShortcutPath,
44 nullptr,
45 GPS_READWRITE,
46 IID_PPV_ARGS(&m_pps)))) {
47 printf("SHGetPropertyStoreFromParsingName failed\n");
48 goto Exit;
49 }
51 if (aSetMode) {
52 PROPVARIANT propvar;
53 if (FAILED(hres = InitPropVariantFromBoolean(true, &propvar)) ||
54 FAILED(hres = m_pps->SetValue(PKEY_AppUserModel_IsDualMode, propvar))) {
55 goto Exit;
56 }
57 PropVariantClear(&propvar);
58 }
60 if (aSetID && aAppModelID) {
61 PROPVARIANT propvar;
62 if (FAILED(hres = InitPropVariantFromString(aAppModelID, &propvar)) ||
63 FAILED(hres = m_pps->SetValue(PKEY_AppUserModel_ID, propvar))) {
64 goto Exit;
65 }
66 PropVariantClear(&propvar);
67 }
69 hres = m_pps->Commit();
71 Exit:
73 if (m_pps) {
74 m_pps->Release();
75 }
77 CoUninitialize();
78 return hres;
79 }
81 HRESULT
82 PrintShortcutProps(LPCWSTR aTargetPath)
83 {
84 HRESULT hres;
85 ::CoInitialize(nullptr);
87 IPropertyStore *m_pps = nullptr;
88 if (FAILED(hres = SHGetPropertyStoreFromParsingName(aTargetPath,
89 nullptr,
90 GPS_READWRITE,
91 IID_PPV_ARGS(&m_pps)))) {
92 printf("SHGetPropertyStoreFromParsingName failed\n");
93 goto Exit;
94 }
96 bool found = false;
98 PROPVARIANT propvar;
99 if (SUCCEEDED(hres = m_pps->GetValue(PKEY_AppUserModel_IsDualMode, &propvar)) && propvar.vt == VT_BOOL && propvar.boolVal == -1) {
100 printf("PKEY_AppUserModel_IsDualMode found\n");
101 PropVariantClear(&propvar);
102 found = true;
103 }
105 if (SUCCEEDED(hres = m_pps->GetValue(PKEY_AppUserModel_ID, &propvar)) && propvar.pwszVal) {
106 printf("PKEY_AppUserModel_ID found ");
107 wprintf(L"value: '%s'\n", propvar.pwszVal);
108 PropVariantClear(&propvar);
109 found = true;
110 }
112 if (!found) {
113 printf("no known properties found.\n");
114 }
116 Exit:
118 if (m_pps) {
119 m_pps->Release();
120 }
122 CoUninitialize();
123 return hres;
124 }
126 HRESULT
127 CreateLink(LPCWSTR aTargetPath, LPCWSTR aShortcutPath, LPCWSTR aDescription)
128 {
129 HRESULT hres;
130 IShellLink* psl;
132 wprintf(L"creating shortcut: '%s'\n", aShortcutPath);
134 CoInitialize(nullptr);
136 hres = CoCreateInstance(CLSID_ShellLink, nullptr, CLSCTX_INPROC_SERVER,
137 IID_IShellLink, (LPVOID*)&psl);
138 if (FAILED(hres)) {
139 CoUninitialize();
140 return hres;
141 }
142 psl->SetPath(aTargetPath);
143 if (aDescription) {
144 psl->SetDescription(aDescription);
145 } else {
146 psl->SetDescription(L"");
147 }
149 IPersistFile* ppf = nullptr;
150 hres = psl->QueryInterface(IID_IPersistFile, (LPVOID*)&ppf);
152 if (SUCCEEDED(hres)) {
153 hres = ppf->Save(aShortcutPath, TRUE);
154 ppf->Release();
155 }
156 psl->Release();
157 CoUninitialize();
158 return hres;
159 }
161 void DumpCommands()
162 {
163 printf("control options:\n");
164 printf(" /CREATE create a shortcut for the target file.\n");
165 printf(" /UPDATE update properties on the target file.\n");
166 printf(" /PRINT print the known properties set on the target file.\n");
167 printf("parameters:\n");
168 printf(" /T(path) the full path and filename of the target file.\n");
169 printf(" /S(path) with CREATE, the full path and filename of the shortcut to create.\n");
170 printf(" /D(string) with CREATE, adds a description to the shortcut.\n");
171 printf(" /A(id) the app model id to assign to the shortcut or target file.\n");
172 printf(" /M enable support for dual desktop and immersive modes on the shortcut or target file.\n");
173 }
175 int wmain(int argc, WCHAR* argv[])
176 {
177 WCHAR shortcutPathStr[MAX_PATH];
178 WCHAR targetPathStr[MAX_PATH];
179 WCHAR appModelIDStr[MAX_PATH];
180 WCHAR descriptionStr[MAX_PATH];
182 shortcutPathStr[0] = '\0';
183 targetPathStr[0] = '\0';
184 appModelIDStr[0] = '\0';
185 descriptionStr[0] = '\0';
187 bool createShortcutFound = false;
188 bool updateFound = false;
189 bool shortcutPathFound = false;
190 bool targetPathFound = false;
191 bool appModelIDFound = false;
192 bool modeFound = false;
193 bool descriptionFound = false;
194 bool printFound = false;
196 int idx;
197 for (idx = 1; idx < argc; idx++) {
198 if (!wcscmp(L"/CREATE", argv[idx])) {
199 createShortcutFound = true;
200 continue;
201 }
202 if (!wcscmp(L"/UPDATE", argv[idx])) {
203 updateFound = true;
204 continue;
205 }
206 if (!wcscmp(L"/PRINT", argv[idx])) {
207 printFound = true;
208 continue;
209 }
211 if (!wcsncmp(L"/S", argv[idx], 2) && wcslen(argv[idx]) > 2) {
212 wcscpy_s(shortcutPathStr, MAX_PATH, (argv[idx]+2));
213 shortcutPathFound = true;
214 continue;
215 }
216 if (!wcsncmp(L"/T", argv[idx], 2) && wcslen(argv[idx]) > 2) {
217 wcscpy_s(targetPathStr, MAX_PATH, (argv[idx]+2));
218 targetPathFound = true;
219 continue;
220 }
221 if (!wcsncmp(L"/A", argv[idx], 2) && wcslen(argv[idx]) > 2) {
222 wcscpy_s(appModelIDStr, MAX_PATH, (argv[idx]+2));
223 appModelIDFound = true;
224 continue;
225 }
226 if (!wcsncmp(L"/D", argv[idx], 2) && wcslen(argv[idx]) > 2 && wcslen(argv[idx]) < MAX_PATH) {
227 wcscpy_s(descriptionStr, MAX_PATH, (argv[idx]+2));
228 descriptionFound = true;
229 continue;
230 }
231 if (!wcscmp(L"/M", argv[idx])) {
232 modeFound = true;
233 continue;
234 }
235 }
237 DumpParameters(targetPathStr, shortcutPathStr, appModelIDStr, descriptionStr);
239 if (!createShortcutFound && !updateFound && !printFound) {
240 DumpCommands();
241 return 0;
242 }
244 if (!targetPathFound) {
245 printf("missing target file path.\n");
246 return -1;
247 }
249 HRESULT hres;
251 if (printFound) {
252 if (FAILED(hres = PrintShortcutProps(targetPathStr))) {
253 printf("failed printing target props HRESULT=%X\n", hres);
254 return -1;
255 }
256 return 0;
257 }
259 if (createShortcutFound && !shortcutPathFound) {
260 printf("missing shortcut file path.\n");
261 return -1;
262 }
264 if (updateFound && !appModelIDFound && !modeFound) {
265 printf("no properties selected.\n");
266 return -1;
267 }
269 if (createShortcutFound) {
270 if (FAILED(hres = CreateLink(targetPathStr,
271 shortcutPathStr,
272 (descriptionFound ? descriptionStr : nullptr)))) {
273 printf("failed creating shortcut HRESULT=%X\n", hres);
274 return -1;
275 }
276 }
278 LPCWSTR target;
279 if (createShortcutFound) {
280 target = shortcutPathStr;
281 } else {
282 target = targetPathStr;
283 }
285 if (appModelIDFound || modeFound) {
286 if (FAILED(hres = SetShortcutProps(target,
287 (appModelIDFound ? appModelIDStr : nullptr),
288 appModelIDFound, modeFound))) {
289 printf("failed adding property HRESULT=%X\n", hres);
290 return -1;
291 }
292 }
294 return 0;
295 }