You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
513 lines
11 KiB
513 lines
11 KiB
/*++
|
|
|
|
Copyright (c) Microsoft Corporation. All rights reserved.
|
|
|
|
Module Name:
|
|
|
|
Shortcut.cpp
|
|
|
|
Abstract:
|
|
|
|
Implementation of the IShellLink wrapper class.
|
|
|
|
Notes:
|
|
|
|
ANSI & Unicode via TCHAR - runs on Win9x/NT/2K/XP etc.
|
|
|
|
History:
|
|
|
|
01/29/2001 rparsons Created
|
|
01/10/2002 rparsons Revised
|
|
01/27/2002 rparsons Converted to TCHAR
|
|
|
|
--*/
|
|
#include "shortcut.h"
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Creates a shortcut given a CSIDL.
|
|
|
|
Arguments:
|
|
|
|
pszFileNamePath - Name and path of the file that the shortcut points to.
|
|
pszDisplayName - Shortcut display text.
|
|
pszArguments - Arguments to be passed to the program.
|
|
pszStartIn - The start-in directory for the program.
|
|
nCmdShow - Dictates how the program will be displayed.
|
|
nFolder - CSIDL that dictates where to place the shortcut.
|
|
|
|
Return Value:
|
|
|
|
S_OK on success, a failure code otherwise.
|
|
|
|
--*/
|
|
HRESULT
|
|
CShortcut::CreateShortcut(
|
|
IN LPCTSTR pszFileNamePath,
|
|
IN LPTSTR pszDisplayName,
|
|
IN LPCTSTR pszArguments OPTIONAL,
|
|
IN LPCTSTR pszStartIn OPTIONAL,
|
|
IN int nCmdShow,
|
|
IN int nFolder
|
|
)
|
|
{
|
|
HRESULT hr;
|
|
TCHAR szDestFolder[MAX_PATH];
|
|
TCHAR szLocation[MAX_PATH];
|
|
|
|
if (!pszFileNamePath || !pszDisplayName) {
|
|
return E_INVALIDARG;
|
|
}
|
|
|
|
hr = SHGetFolderPath(NULL, nFolder, NULL, SHGFP_TYPE_CURRENT, szDestFolder);
|
|
|
|
if (FAILED(hr)) {
|
|
return hr;
|
|
}
|
|
|
|
hr = StringCchPrintf(szLocation,
|
|
ARRAYSIZE(szLocation),
|
|
"%s\\%s.lnk",
|
|
szDestFolder,
|
|
pszDisplayName);
|
|
|
|
if (FAILED(hr)) {
|
|
return hr;
|
|
}
|
|
|
|
//
|
|
// Call the function to do the work of creating the shortcut.
|
|
//
|
|
hr = BuildShortcut(pszFileNamePath,
|
|
pszArguments,
|
|
szLocation,
|
|
pszStartIn,
|
|
nCmdShow);
|
|
|
|
return hr;
|
|
}
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Creates a shortcut given a path.
|
|
|
|
Arguments:
|
|
|
|
lpLnkDirectory - Path that will contain the shortcut
|
|
lpFileNamePath - Name and path of the file that the shortcut points to
|
|
lpDisplayName - Shortcut display text
|
|
lpArguments - Arguments to be passed to the program
|
|
lpStartIn - The start-in directory for the program
|
|
nCmdShow - Dictates how the program will be displayed
|
|
|
|
|
|
Return Value:
|
|
|
|
Calls BuildShortcut which returns an HRESULT.
|
|
|
|
--*/
|
|
HRESULT
|
|
CShortcut::CreateShortcut(
|
|
IN LPCTSTR pszLnkDirectory,
|
|
IN LPCTSTR pszFileNamePath,
|
|
IN LPTSTR pszDisplayName,
|
|
IN LPCTSTR pszArguments OPTIONAL,
|
|
IN LPCTSTR pszStartIn OPTIONAL,
|
|
IN int nCmdShow
|
|
)
|
|
{
|
|
HRESULT hr;
|
|
TCHAR szLocation[MAX_PATH];
|
|
|
|
if (!pszLnkDirectory || !pszFileNamePath || !pszDisplayName) {
|
|
return E_INVALIDARG;
|
|
}
|
|
|
|
hr = StringCchPrintf(szLocation,
|
|
ARRAYSIZE(szLocation),
|
|
"%s\\%s.lnk",
|
|
pszLnkDirectory,
|
|
pszDisplayName);
|
|
|
|
if (FAILED(hr)) {
|
|
return hr;
|
|
}
|
|
|
|
//
|
|
// Call the function to do the work of creating the shortcut.
|
|
//
|
|
return BuildShortcut(pszFileNamePath,
|
|
pszArguments,
|
|
szLocation,
|
|
pszStartIn,
|
|
nCmdShow);
|
|
|
|
}
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Does the work of actually creating the shortcut.
|
|
|
|
Arguments:
|
|
|
|
pszPath - Path that the shortcut points to.
|
|
pszArguments - Arguments to be passed to the program.
|
|
pszLocation - Location of the shortcut and it's name.
|
|
pszWorkingDir - The start-in directory for the program.
|
|
nCmdShow - Dictates how the program will be displayed.
|
|
|
|
Return Value:
|
|
|
|
S_OK on success, an HRESULT code on failure.
|
|
|
|
--*/
|
|
HRESULT
|
|
CShortcut::BuildShortcut(
|
|
IN LPCTSTR pszPath,
|
|
IN LPCTSTR pszArguments OPTIONAL,
|
|
IN LPCTSTR pszLocation,
|
|
IN LPCTSTR pszWorkingDir OPTIONAL,
|
|
IN int nCmdShow
|
|
)
|
|
{
|
|
IShellLink* pisl = NULL;
|
|
IPersistFile* pipf = NULL;
|
|
HRESULT hr = E_FAIL;
|
|
WCHAR wszLocation[MAX_PATH];
|
|
|
|
if (!pszPath || !pszLocation) {
|
|
return E_INVALIDARG;
|
|
}
|
|
|
|
//
|
|
// Load the COM libraries.
|
|
//
|
|
hr = CoInitializeEx(NULL, COINIT_APARTMENTTHREADED);
|
|
|
|
if (FAILED(hr)) {
|
|
return hr;
|
|
}
|
|
|
|
//
|
|
// Get an IShellLink interface pointer.
|
|
//
|
|
hr = CoCreateInstance(CLSID_ShellLink,
|
|
NULL,
|
|
CLSCTX_INPROC_SERVER,
|
|
IID_IShellLink,
|
|
(LPVOID*)&pisl);
|
|
|
|
if (FAILED(hr)) {
|
|
goto exit;
|
|
}
|
|
|
|
//
|
|
// Get an IPersistFile interface pointer.
|
|
//
|
|
hr = pisl->QueryInterface(IID_IPersistFile, (LPVOID*)&pipf);
|
|
|
|
if (FAILED(hr)) {
|
|
goto exit;
|
|
}
|
|
|
|
//
|
|
// Set the path to the shortcut.
|
|
//
|
|
hr = pisl->SetPath(pszPath);
|
|
|
|
if (FAILED(hr)) {
|
|
goto exit;
|
|
}
|
|
|
|
//
|
|
// Set the arguments for the shortcut.
|
|
//
|
|
if (pszArguments) {
|
|
hr = pisl->SetArguments(pszArguments);
|
|
|
|
if (FAILED(hr)) {
|
|
goto exit;
|
|
}
|
|
}
|
|
|
|
//
|
|
// Set the working directory.
|
|
//
|
|
if (pszWorkingDir) {
|
|
hr = pisl->SetWorkingDirectory(pszWorkingDir);
|
|
|
|
if (FAILED(hr)) {
|
|
goto exit;
|
|
}
|
|
}
|
|
|
|
//
|
|
// Set the show flag.
|
|
//
|
|
hr = pisl->SetShowCmd(nCmdShow);
|
|
|
|
if (FAILED(hr)) {
|
|
goto exit;
|
|
}
|
|
|
|
//
|
|
// Convert from ANSI to UNICODE prior to the save.
|
|
//
|
|
#ifndef UNICODE
|
|
if (!MultiByteToWideChar(CP_ACP,
|
|
0,
|
|
pszLocation,
|
|
-1,
|
|
wszLocation,
|
|
MAX_PATH)) {
|
|
hr = E_FAIL;
|
|
goto exit;
|
|
}
|
|
#else
|
|
wcsncpy(wszLocation, pszLocation, MAX_PATH);
|
|
#endif // UNICODE
|
|
|
|
//
|
|
// Write the shortcut to disk.
|
|
//
|
|
hr = pipf->Save(wszLocation, TRUE);
|
|
|
|
if (FAILED(hr)) {
|
|
goto exit;
|
|
}
|
|
|
|
exit:
|
|
|
|
if (pisl) {
|
|
pisl->Release();
|
|
}
|
|
|
|
if (pipf) {
|
|
pipf->Release();
|
|
}
|
|
|
|
CoUninitialize();
|
|
|
|
return hr;
|
|
}
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Creates a group on the start menu.
|
|
|
|
Arguments:
|
|
|
|
pszGroupName - Name of the group.
|
|
fAllUsers - A flag to indicate if the group should
|
|
appear in the All Users folder. If false,
|
|
the group is created in the private user's folder.
|
|
|
|
Return Value:
|
|
|
|
S_OK on success, an HRESULT code on failure.
|
|
|
|
--*/
|
|
HRESULT
|
|
CShortcut::CreateGroup(
|
|
IN LPCTSTR pszGroupName,
|
|
IN BOOL fAllUsers
|
|
)
|
|
{
|
|
LPITEMIDLIST pidl;
|
|
TCHAR szProgramPath[MAX_PATH];
|
|
TCHAR szGroupPath[MAX_PATH];
|
|
BOOL bReturn = FALSE;
|
|
HRESULT hr;
|
|
|
|
if (!pszGroupName) {
|
|
return E_INVALIDARG;
|
|
}
|
|
|
|
//
|
|
// Get the PIDL for the Programs folder in the shell namespace
|
|
//
|
|
hr = SHGetSpecialFolderLocation(NULL,
|
|
fAllUsers ? CSIDL_COMMON_PROGRAMS : CSIDL_PROGRAMS,
|
|
&pidl);
|
|
|
|
if (FAILED(hr)) {
|
|
return hr;
|
|
}
|
|
|
|
//
|
|
// Get the path associated with the PIDL.
|
|
//
|
|
bReturn = SHGetPathFromIDList(pidl, szProgramPath);
|
|
|
|
if (!bReturn) {
|
|
goto exit;
|
|
}
|
|
|
|
//
|
|
// Build the path for the new group.
|
|
//
|
|
hr = StringCchPrintf(szGroupPath,
|
|
ARRAYSIZE(szGroupPath),
|
|
"%s\\%s",
|
|
szProgramPath,
|
|
pszGroupName);
|
|
|
|
if (FAILED(hr)) {
|
|
goto exit;
|
|
}
|
|
|
|
//
|
|
// Create the directory (group) where shortcuts will reside.
|
|
//
|
|
if (!CreateDirectory(szGroupPath, NULL)) {
|
|
goto exit;
|
|
}
|
|
|
|
//
|
|
// Tell the shell that we changed something.
|
|
//
|
|
SHChangeNotify(SHCNE_MKDIR,
|
|
SHCNF_PATH,
|
|
(LPVOID)szGroupPath,
|
|
0);
|
|
|
|
hr = S_OK;
|
|
|
|
exit:
|
|
|
|
if (pidl) {
|
|
CoTaskMemFree((LPVOID)pidl);
|
|
}
|
|
|
|
return hr;
|
|
}
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Sets arguments for a given shortcut.
|
|
|
|
Arguments:
|
|
|
|
pszFileName - Name of the file to set the arguments for.
|
|
pszArguments - Arguments to apply to file.
|
|
|
|
Return Value:
|
|
|
|
S_OK on success, an HRESULT code on failure.
|
|
|
|
--*/
|
|
HRESULT
|
|
CShortcut::SetArguments(
|
|
IN LPTSTR pszFileName,
|
|
IN LPTSTR pszArguments
|
|
)
|
|
{
|
|
IShellLink* pisl = NULL;
|
|
IPersistFile* pipf = NULL;
|
|
HRESULT hr = E_FAIL;
|
|
WCHAR wszFileName[MAX_PATH];
|
|
|
|
if (!pszFileName || !pszArguments) {
|
|
return E_INVALIDARG;
|
|
}
|
|
|
|
//
|
|
// Load the COM libraries.
|
|
//
|
|
hr = CoInitializeEx(NULL, COINIT_APARTMENTTHREADED);
|
|
|
|
if (FAILED(hr)) {
|
|
return hr;
|
|
}
|
|
|
|
//
|
|
// Get an IShellLink interface pointer.
|
|
//
|
|
hr = CoCreateInstance(CLSID_ShellLink,
|
|
NULL,
|
|
CLSCTX_INPROC_SERVER,
|
|
IID_IShellLink,
|
|
(LPVOID*)&pisl);
|
|
|
|
if (FAILED(hr)) {
|
|
goto exit;
|
|
}
|
|
|
|
//
|
|
// Get an IPersistFile interface pointer.
|
|
//
|
|
hr = pisl->QueryInterface(IID_IPersistFile, (LPVOID*)&pipf);
|
|
|
|
if (FAILED(hr)) {
|
|
goto exit;
|
|
}
|
|
|
|
//
|
|
// Convert from ANSI to UNICODE.
|
|
//
|
|
#ifndef UNICODE
|
|
if (!MultiByteToWideChar(CP_ACP,
|
|
0,
|
|
pszFileName,
|
|
-1,
|
|
wszFileName,
|
|
MAX_PATH)) {
|
|
hr = E_FAIL;
|
|
goto exit;
|
|
}
|
|
#else
|
|
wcsncpy(wszFileName, pszFileName, MAX_PATH);
|
|
#endif
|
|
|
|
//
|
|
// Load the shortcut so we can change it.
|
|
//
|
|
hr = pipf->Load(wszFileName, STGM_READWRITE);
|
|
|
|
if (FAILED(hr)) {
|
|
goto exit;
|
|
}
|
|
|
|
//
|
|
// Set the arguments.
|
|
//
|
|
hr = pisl->SetArguments(pszArguments);
|
|
|
|
if (FAILED(hr)) {
|
|
goto exit;
|
|
}
|
|
|
|
//
|
|
// Save the shortcut back to disk.
|
|
//
|
|
hr = pipf->Save(wszFileName, TRUE);
|
|
|
|
if (FAILED(hr)) {
|
|
goto exit;
|
|
}
|
|
|
|
exit:
|
|
|
|
if (pisl) {
|
|
pisl->Release();
|
|
}
|
|
|
|
if (pipf) {
|
|
pipf->Release();
|
|
}
|
|
|
|
CoUninitialize();
|
|
|
|
|
|
return hr;
|
|
}
|