/*++ 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; }