﻿// TortoiseSVN - a Windows shell extension for easy version control

// Copyright (C) 2009-2014, 2021 - TortoiseSVN

// This program is free software; you can redistribute it and/or
// modify it under the terms of the GNU General Public License
// as published by the Free Software Foundation; either version 2
// of the License, or (at your option) any later version.

// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU General Public License for more details.

// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software Foundation,
// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
//
#include "stdafx.h"
#include "SmartHandle.h"
#include "JumpListHelpers.h"
#include <propvarutil.h>
#include <propsys.h>
#include <propkey.h>

HRESULT SetAppID(LPCWSTR appID)
{
    HRESULT                                                   hRes   = S_FALSE;
    using SetCurrentProcessExplicitAppUserModelIdfn                  = HRESULT STDAPICALLTYPE(PCWSTR appId);
    CAutoLibrary                                              hShell = AtlLoadSystemLibraryUsingFullPath(L"shell32.dll");
    if (hShell)
    {
        SetCurrentProcessExplicitAppUserModelIdfn *pfnSetCurrentProcessExplicitAppUserModelID = reinterpret_cast<SetCurrentProcessExplicitAppUserModelIdfn *>(GetProcAddress(hShell, "SetCurrentProcessExplicitAppUserModelID"));
        if (pfnSetCurrentProcessExplicitAppUserModelID)
        {
            hRes = pfnSetCurrentProcessExplicitAppUserModelID(appID);
        }
    }
    return hRes;
}

HRESULT CreateShellLink(PCWSTR pszArguments, PCWSTR pszTitle, int iconIndex, IShellLink **ppsl)
{
    ATL::CComPtr<IShellLink> psl;
    HRESULT                  hr = psl.CoCreateInstance(CLSID_ShellLink, nullptr, CLSCTX_INPROC_SERVER);
    if (FAILED(hr))
        return hr;

    WCHAR szAppPath[MAX_PATH] = {0};
    if (GetModuleFileName(nullptr, szAppPath, _countof(szAppPath)) == 0)
    {
        hr = HRESULT_FROM_WIN32(GetLastError());
        return hr;
    }
    hr = psl->SetPath(szAppPath);
    if (FAILED(hr))
        return hr;

    hr = psl->SetArguments(pszArguments);
    if (FAILED(hr))
        return hr;

    hr = psl->SetIconLocation(szAppPath, iconIndex);
    if (FAILED(hr))
        return hr;

    ATL::CComPtr<IPropertyStore> pps;
    hr = psl.QueryInterface(&pps);
    if (FAILED(hr))
        return hr;

    PROPVARIANT propVar;
    hr = InitPropVariantFromString(pszTitle, &propVar);
    if (SUCCEEDED(hr))
    {
        hr = pps->SetValue(PKEY_Title, propVar);
        if (SUCCEEDED(hr))
        {
            hr = pps->Commit();
            if (SUCCEEDED(hr))
            {
                hr = psl.QueryInterface(ppsl);
            }
        }
        PropVariantClear(&propVar);
    }
    return hr;
}

HRESULT CreateSeparatorLink(IShellLink **ppsl)
{
    ATL::CComPtr<IPropertyStore> pps;
    HRESULT                      hr = pps.CoCreateInstance(CLSID_ShellLink, nullptr, CLSCTX_INPROC_SERVER);
    if (FAILED(hr))
        return hr;

    PROPVARIANT propVar;
    hr = InitPropVariantFromBoolean(TRUE, &propVar);
    if (FAILED(hr))
        return hr;

    hr = pps->SetValue(PKEY_AppUserModel_IsDestListSeparator, propVar);
    if (SUCCEEDED(hr))
    {
        hr = pps->Commit();
        if (SUCCEEDED(hr))
        {
            hr = pps.QueryInterface(ppsl);
        }
    }
    PropVariantClear(&propVar);
    return hr;
}

bool IsItemInArray(IShellItem *psi, IObjectArray *poaRemoved)
{
    UINT cItems;
    if (FAILED(poaRemoved->GetCount(&cItems)))
        return false;

    bool fRet = false;
    for (UINT i = 0; !fRet && i < cItems; i++)
    {
        ATL::CComPtr<IShellItem> psiCompare;
        if (FAILED(poaRemoved->GetAt(i, IID_PPV_ARGS(&psiCompare))))
            continue;
        int iOrder;
        fRet = SUCCEEDED(psiCompare->Compare(psi, SICHINT_CANONICAL, &iOrder)) && (0 == iOrder);
    }
    return fRet;
}

void DeleteJumpList(LPCWSTR appID)
{
    ATL::CComPtr<ICustomDestinationList> pcdl;
    HRESULT                              hr = pcdl.CoCreateInstance(CLSID_DestinationList, nullptr, CLSCTX_INPROC_SERVER);
    if (SUCCEEDED(hr))
    {
        pcdl->DeleteList(appID);
    }
}