зеркало из https://github.com/mozilla/gecko-dev.git
297 строки
8.1 KiB
C++
297 строки
8.1 KiB
C++
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
|
/* This Source Code Form is subject to the terms of the Mozilla Public
|
|
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
|
|
* You can obtain one at http://mozilla.org/MPL/2.0/. */
|
|
|
|
#undef WINVER
|
|
#undef _WIN32_WINNT
|
|
#define WINVER 0x602
|
|
#define _WIN32_WINNT 0x602
|
|
|
|
#include <windows.h>
|
|
#include <shobjidl.h>
|
|
#include <objbase.h>
|
|
#include <shlguid.h>
|
|
#include <shlobj.h>
|
|
#define INITGUID
|
|
#include <propvarutil.h>
|
|
#include <propkey.h>
|
|
#include <stdio.h>
|
|
|
|
// Indicates that an application supports dual desktop and immersive modes. In Windows 8, this property is only applicable for web browsers.
|
|
//DEFINE_PROPERTYKEY(PKEY_AppUserModel_IsDualMode, 0x9F4C2855, 0x9F79, 0x4B39, 0xA8, 0xD0, 0xE1, 0xD4, 0x2D, 0xE1, 0xD5, 0xF3, 11);
|
|
|
|
void DumpParameters(LPCWSTR aTargetPath, LPCWSTR aShortcutPath, LPCWSTR aAppModelID, LPCWSTR aDescription)
|
|
{
|
|
if (aTargetPath)
|
|
wprintf(L"target path: '%s'\n", aTargetPath);
|
|
if (aShortcutPath)
|
|
wprintf(L"shortcut path: '%s'\n", aShortcutPath);
|
|
if (aAppModelID)
|
|
wprintf(L"app id: '%s'\n", aAppModelID);
|
|
if (aDescription)
|
|
wprintf(L"description: '%s'\n", aDescription);
|
|
}
|
|
|
|
HRESULT
|
|
SetShortcutProps(LPCWSTR aShortcutPath, LPCWSTR aAppModelID, bool aSetID, bool aSetMode)
|
|
{
|
|
HRESULT hres;
|
|
::CoInitialize(nullptr);
|
|
|
|
IPropertyStore *m_pps = nullptr;
|
|
if (FAILED(hres = SHGetPropertyStoreFromParsingName(aShortcutPath,
|
|
nullptr,
|
|
GPS_READWRITE,
|
|
IID_PPV_ARGS(&m_pps)))) {
|
|
printf("SHGetPropertyStoreFromParsingName failed\n");
|
|
goto Exit;
|
|
}
|
|
|
|
if (aSetMode) {
|
|
PROPVARIANT propvar;
|
|
if (FAILED(hres = InitPropVariantFromBoolean(true, &propvar)) ||
|
|
FAILED(hres = m_pps->SetValue(PKEY_AppUserModel_IsDualMode, propvar))) {
|
|
goto Exit;
|
|
}
|
|
PropVariantClear(&propvar);
|
|
}
|
|
|
|
if (aSetID && aAppModelID) {
|
|
PROPVARIANT propvar;
|
|
if (FAILED(hres = InitPropVariantFromString(aAppModelID, &propvar)) ||
|
|
FAILED(hres = m_pps->SetValue(PKEY_AppUserModel_ID, propvar))) {
|
|
goto Exit;
|
|
}
|
|
PropVariantClear(&propvar);
|
|
}
|
|
|
|
hres = m_pps->Commit();
|
|
|
|
Exit:
|
|
|
|
if (m_pps) {
|
|
m_pps->Release();
|
|
}
|
|
|
|
CoUninitialize();
|
|
return hres;
|
|
}
|
|
|
|
HRESULT
|
|
PrintShortcutProps(LPCWSTR aTargetPath)
|
|
{
|
|
HRESULT hres;
|
|
::CoInitialize(nullptr);
|
|
|
|
IPropertyStore *m_pps = nullptr;
|
|
if (FAILED(hres = SHGetPropertyStoreFromParsingName(aTargetPath,
|
|
nullptr,
|
|
GPS_READWRITE,
|
|
IID_PPV_ARGS(&m_pps)))) {
|
|
printf("SHGetPropertyStoreFromParsingName failed\n");
|
|
goto Exit;
|
|
}
|
|
|
|
bool found = false;
|
|
|
|
PROPVARIANT propvar;
|
|
if (SUCCEEDED(hres = m_pps->GetValue(PKEY_AppUserModel_IsDualMode, &propvar)) && propvar.vt == VT_BOOL && propvar.boolVal == -1) {
|
|
printf("PKEY_AppUserModel_IsDualMode found\n");
|
|
PropVariantClear(&propvar);
|
|
found = true;
|
|
}
|
|
|
|
if (SUCCEEDED(hres = m_pps->GetValue(PKEY_AppUserModel_ID, &propvar)) && propvar.pwszVal) {
|
|
printf("PKEY_AppUserModel_ID found ");
|
|
wprintf(L"value: '%s'\n", propvar.pwszVal);
|
|
PropVariantClear(&propvar);
|
|
found = true;
|
|
}
|
|
|
|
if (!found) {
|
|
printf("no known properties found.\n");
|
|
}
|
|
|
|
Exit:
|
|
|
|
if (m_pps) {
|
|
m_pps->Release();
|
|
}
|
|
|
|
CoUninitialize();
|
|
return hres;
|
|
}
|
|
|
|
HRESULT
|
|
CreateLink(LPCWSTR aTargetPath, LPCWSTR aShortcutPath, LPCWSTR aDescription)
|
|
{
|
|
HRESULT hres;
|
|
IShellLink* psl;
|
|
|
|
wprintf(L"creating shortcut: '%s'\n", aShortcutPath);
|
|
|
|
CoInitialize(nullptr);
|
|
|
|
hres = CoCreateInstance(CLSID_ShellLink, nullptr, CLSCTX_INPROC_SERVER,
|
|
IID_IShellLink, (LPVOID*)&psl);
|
|
if (FAILED(hres)) {
|
|
CoUninitialize();
|
|
return hres;
|
|
}
|
|
psl->SetPath(aTargetPath);
|
|
if (aDescription) {
|
|
psl->SetDescription(aDescription);
|
|
} else {
|
|
psl->SetDescription(L"");
|
|
}
|
|
|
|
IPersistFile* ppf = nullptr;
|
|
hres = psl->QueryInterface(IID_IPersistFile, (LPVOID*)&ppf);
|
|
|
|
if (SUCCEEDED(hres)) {
|
|
hres = ppf->Save(aShortcutPath, TRUE);
|
|
ppf->Release();
|
|
}
|
|
psl->Release();
|
|
CoUninitialize();
|
|
return hres;
|
|
}
|
|
|
|
void DumpCommands()
|
|
{
|
|
printf("control options:\n");
|
|
printf(" /CREATE create a shortcut for the target file.\n");
|
|
printf(" /UPDATE update properties on the target file.\n");
|
|
printf(" /PRINT print the known properties set on the target file.\n");
|
|
printf("parameters:\n");
|
|
printf(" /T(path) the full path and filename of the target file.\n");
|
|
printf(" /S(path) with CREATE, the full path and filename of the shortcut to create.\n");
|
|
printf(" /D(string) with CREATE, adds a description to the shortcut.\n");
|
|
printf(" /A(id) the app model id to assign to the shortcut or target file.\n");
|
|
printf(" /M enable support for dual desktop and immersive modes on the shortcut or target file.\n");
|
|
}
|
|
|
|
int wmain(int argc, WCHAR* argv[])
|
|
{
|
|
WCHAR shortcutPathStr[MAX_PATH];
|
|
WCHAR targetPathStr[MAX_PATH];
|
|
WCHAR appModelIDStr[MAX_PATH];
|
|
WCHAR descriptionStr[MAX_PATH];
|
|
|
|
shortcutPathStr[0] = '\0';
|
|
targetPathStr[0] = '\0';
|
|
appModelIDStr[0] = '\0';
|
|
descriptionStr[0] = '\0';
|
|
|
|
bool createShortcutFound = false;
|
|
bool updateFound = false;
|
|
bool shortcutPathFound = false;
|
|
bool targetPathFound = false;
|
|
bool appModelIDFound = false;
|
|
bool modeFound = false;
|
|
bool descriptionFound = false;
|
|
bool printFound = false;
|
|
|
|
int idx;
|
|
for (idx = 1; idx < argc; idx++) {
|
|
if (!wcscmp(L"/CREATE", argv[idx])) {
|
|
createShortcutFound = true;
|
|
continue;
|
|
}
|
|
if (!wcscmp(L"/UPDATE", argv[idx])) {
|
|
updateFound = true;
|
|
continue;
|
|
}
|
|
if (!wcscmp(L"/PRINT", argv[idx])) {
|
|
printFound = true;
|
|
continue;
|
|
}
|
|
|
|
if (!wcsncmp(L"/S", argv[idx], 2) && wcslen(argv[idx]) > 2) {
|
|
wcscpy_s(shortcutPathStr, MAX_PATH, (argv[idx]+2));
|
|
shortcutPathFound = true;
|
|
continue;
|
|
}
|
|
if (!wcsncmp(L"/T", argv[idx], 2) && wcslen(argv[idx]) > 2) {
|
|
wcscpy_s(targetPathStr, MAX_PATH, (argv[idx]+2));
|
|
targetPathFound = true;
|
|
continue;
|
|
}
|
|
if (!wcsncmp(L"/A", argv[idx], 2) && wcslen(argv[idx]) > 2) {
|
|
wcscpy_s(appModelIDStr, MAX_PATH, (argv[idx]+2));
|
|
appModelIDFound = true;
|
|
continue;
|
|
}
|
|
if (!wcsncmp(L"/D", argv[idx], 2) && wcslen(argv[idx]) > 2 && wcslen(argv[idx]) < MAX_PATH) {
|
|
wcscpy_s(descriptionStr, MAX_PATH, (argv[idx]+2));
|
|
descriptionFound = true;
|
|
continue;
|
|
}
|
|
if (!wcscmp(L"/M", argv[idx])) {
|
|
modeFound = true;
|
|
continue;
|
|
}
|
|
}
|
|
|
|
DumpParameters(targetPathStr, shortcutPathStr, appModelIDStr, descriptionStr);
|
|
|
|
if (!createShortcutFound && !updateFound && !printFound) {
|
|
DumpCommands();
|
|
return 0;
|
|
}
|
|
|
|
if (!targetPathFound) {
|
|
printf("missing target file path.\n");
|
|
return -1;
|
|
}
|
|
|
|
HRESULT hres;
|
|
|
|
if (printFound) {
|
|
if (FAILED(hres = PrintShortcutProps(targetPathStr))) {
|
|
printf("failed printing target props HRESULT=%X\n", hres);
|
|
return -1;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
if (createShortcutFound && !shortcutPathFound) {
|
|
printf("missing shortcut file path.\n");
|
|
return -1;
|
|
}
|
|
|
|
if (updateFound && !appModelIDFound && !modeFound) {
|
|
printf("no properties selected.\n");
|
|
return -1;
|
|
}
|
|
|
|
if (createShortcutFound) {
|
|
if (FAILED(hres = CreateLink(targetPathStr,
|
|
shortcutPathStr,
|
|
(descriptionFound ? descriptionStr : nullptr)))) {
|
|
printf("failed creating shortcut HRESULT=%X\n", hres);
|
|
return -1;
|
|
}
|
|
}
|
|
|
|
LPCWSTR target;
|
|
if (createShortcutFound) {
|
|
target = shortcutPathStr;
|
|
} else {
|
|
target = targetPathStr;
|
|
}
|
|
|
|
if (appModelIDFound || modeFound) {
|
|
if (FAILED(hres = SetShortcutProps(target,
|
|
(appModelIDFound ? appModelIDStr : nullptr),
|
|
appModelIDFound, modeFound))) {
|
|
printf("failed adding property HRESULT=%X\n", hres);
|
|
return -1;
|
|
}
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|