|
|
// StartupLinks.cpp: implementation of the CManageShellLinks class
// to manage Shell Folder links.
//
// Note: Multiple calls using the same class instance don't assume any
// information about previous calls. The only stuff in common
// is the IShellLink object and the specific shell folder.
//////////////////////////////////////////////////////////////////////
#include "stdio.h"
#include "ManageShellLinks.h"
#include "_umclnt.h"
#define SHELL_FOLDERS TEXT("Software\\Microsoft\\Windows\\CurrentVersion\\Explorer\\Shell Folders")
#define LINK_EXT TEXT(".lnk")
//////////////////////////////////////////////////////////////////////
// Construction/Destruction
//////////////////////////////////////////////////////////////////////
CManageShellLinks::CManageShellLinks( LPCTSTR pszDestFolder // [in] Which shell folder to operate on
) : m_pIShLink(0) , m_pszShellFolder(0) { // Get a pointer to the IShellLink interface
HRESULT hr = CoCreateInstance(CLSID_ShellLink, NULL, CLSCTX_INPROC_SERVER, IID_IShellLink, (void **)&m_pIShLink);
if (FAILED(hr) || !m_pIShLink) DBPRINTF(TEXT("CManageShellLinks::CManageShellLinks: CoCreateInstance failed 0x%x\r\n"), hr);
m_pszShellFolder = new TCHAR[lstrlen(pszDestFolder)+1]; if (m_pszShellFolder) lstrcpy(m_pszShellFolder, pszDestFolder); }
CManageShellLinks::~CManageShellLinks() { if (m_pIShLink) { m_pIShLink->Release(); m_pIShLink = 0; } if (m_pszShellFolder) { delete [] m_pszShellFolder; m_pszShellFolder = 0; } }
//*****************************************************************************
// GetFolderPath - returns shell folder path
//
// pszFolderPath [out] - pointer to location for shell folder
// pulSize [in out] - pointer to size of pszFolderPath
//
// Returns TRUE if it found the folder name else FALSE
//
long CManageShellLinks::GetFolderPath(LPTSTR pszFolderPath, unsigned long *pulSize) { *pszFolderPath = 0;
if (!m_pszShellFolder) return ERROR_NOT_ENOUGH_MEMORY;
HKEY hkeyFolders; HKEY hkeyUser;
// Open current user's hive and retrieve shell folder path
long lRv = RegOpenCurrentUser(KEY_QUERY_VALUE, &hkeyUser);
if (lRv == ERROR_SUCCESS) { lRv = RegOpenKeyEx( hkeyUser , SHELL_FOLDERS , 0,KEY_QUERY_VALUE , &hkeyFolders); RegCloseKey(hkeyUser); }
if (lRv == ERROR_SUCCESS) { DWORD dwType; lRv = RegQueryValueEx( hkeyFolders , m_pszShellFolder , NULL , &dwType , (LPBYTE)pszFolderPath , pulSize); if (lRv != ERROR_SUCCESS || dwType != REG_SZ) pszFolderPath[0] = TEXT('\0');
pszFolderPath[*pulSize-1] = TEXT('\0'); RegCloseKey(hkeyFolders); }
return lRv; }
//*****************************************************************************
// GetUsersFolderPath - returns the location of the current user's shell folder
//
// pszFolderPath [out] - pointer to location for shell folder
// pulSize [in out] - pointer to size of pszFolderPath
//
// Returns TRUE if it found the folder name else FALSE
//
BOOL CManageShellLinks::GetUsersFolderPath(LPTSTR pszFolderPath, unsigned long *pulSize) { long lRv = ERROR_ACCESS_DENIED; unsigned long ulSize = 0; *pszFolderPath = 0;
if (m_pszShellFolder) { ulSize = *pulSize; BOOL fError;
// At this point, if UtilMan was started in the system context (WinKey+U),
// HKCU points to "Default User". We need it to point to the logged on
// user's hive so we can get the correct path for the logged on user.
// Note: GetUserAccessToken() will fail if we are not started by SYSTEM
// and in that case just get the logged on user's folder path.
HANDLE hMyToken = GetUserAccessToken(TRUE, &fError); if (hMyToken) { if (ImpersonateLoggedOnUser(hMyToken)) { lRv = GetFolderPath(pszFolderPath, &ulSize); RevertToSelf(); } CloseHandle(hMyToken); } else { lRv = GetFolderPath(pszFolderPath, &ulSize); } }
*pulSize = ulSize; return (lRv == ERROR_SUCCESS)?TRUE:FALSE; }
//*****************************************************************************
// CreateLinkPath - returns the complete path and name of the link. Caller
// free's the memory.
//
// pszLink [in] - the base name of the link itself
//
LPTSTR CManageShellLinks::CreateLinkPath(LPCTSTR pszLink) { // allocate enough space for folder path + '\' + filename + NULL
unsigned long ccbStartPath = MAX_PATH; LPTSTR pszLinkPath = new TCHAR [ccbStartPath + 1 + lstrlen(pszLink) + sizeof(LINK_EXT) + 1]; if (!pszLinkPath) return NULL;
// get the user's shell folder name
if (!GetUsersFolderPath(pszLinkPath, &ccbStartPath) || !ccbStartPath) { delete [] pszLinkPath; return NULL; }
// append the link name and extension
lstrcat(pszLinkPath, TEXT("\\")); lstrcat(pszLinkPath, pszLink); lstrcat(pszLinkPath, LINK_EXT);
return pszLinkPath; }
//*****************************************************************************
// LinkExists - returns TRUE if pszLink exists in the shell folder else FALSE
//
// pszLink [in] - the base name of the link itself
//
BOOL CManageShellLinks::LinkExists(LPCTSTR pszLink) { LPTSTR pszLinkPath = CreateLinkPath(pszLink); if (!pszLinkPath) return FALSE;
DWORD dwAttr = GetFileAttributes(pszLinkPath); delete [] pszLinkPath; return (dwAttr == -1)?FALSE:TRUE; }
//*****************************************************************************
// RemoveLink - removes a link from the user's shell folder
//
// pszLink [in] - the base name of the link itself
//
// Returns S_OK on success or a standard HRESULT
//
HRESULT CManageShellLinks::RemoveLink(LPCTSTR pszLink) { if (!m_pIShLink) return E_FAIL;
LPTSTR pszLinkPath = CreateLinkPath(pszLink); if (!pszLinkPath) return E_FAIL;
int iRemoveFailed = _wremove(pszLinkPath); delete [] pszLinkPath; return (iRemoveFailed)?S_FALSE:S_OK; }
//*****************************************************************************
// CreateLink - creates a link in the user's shell folder
//
// pszLinkFile [in] - the fully qualified name of the file the link refers to
// pszLink [in] - the base name of the link itself
// pszStartIn [in] - working directory (may be NULL)
// pszDesc [in] - the tooltip for the link (may be NULL)
// pszArgs [in] - command line arguments (may be NULL)
//
// Returns S_OK on success or a standard HRESULT
//
HRESULT CManageShellLinks::CreateLink( LPCTSTR pszLink, LPCTSTR pszLinkFile, LPCTSTR pszStartIn, LPCTSTR pszDesc, LPCTSTR pszArgs ) { if (!m_pIShLink) { DBPRINTF(TEXT("CManageShellLinks::CreateLink: !m_pIShLink\r\n")); return E_FAIL; }
LPTSTR pszLinkPath = CreateLinkPath(pszLink); if (!pszLinkPath) { DBPRINTF(TEXT("CManageShellLinks::CreateLink: !pszLinkPath\r\n")); return E_FAIL; }
IPersistFile *pIPersistFile;
// Get the IPersistFile interface to save the shortcut
HRESULT hr = m_pIShLink->QueryInterface(IID_IPersistFile, (void **)&pIPersistFile); if (SUCCEEDED(hr)) { // Set the path to and description of the link
// The shortcut
if (FAILED(m_pIShLink->SetPath(pszLinkFile))) DBPRINTF(TEXT("SetPath failed!\r\n"));
// ToolTip description
if (pszDesc && FAILED(m_pIShLink->SetDescription(pszDesc))) DBPRINTF(TEXT("SetDescription failed!\r\n"));
// Working directory
if (pszStartIn && FAILED(m_pIShLink->SetWorkingDirectory(pszStartIn))) DBPRINTF(TEXT("SetWorkingDirectory failed!\r\n"));
// Command line args
if (pszArgs && FAILED(m_pIShLink->SetArguments(pszArgs))) DBPRINTF(TEXT("SetArguments failed!\r\n"));
// Save it
if (FAILED(pIPersistFile->Save(pszLinkPath, TRUE))) DBPRINTF(TEXT("Save failed!\r\n"));
pIPersistFile->Release(); }
delete [] pszLinkPath;
return hr; }
#ifdef __cplusplus
extern "C" { #endif
//*****************************************************************************
// LinkExists - helper function called from C returns TRUE if pszLink exists
// in the shell folder else FALSE
//
// pszLink [in] - the base name of the link itself
//
BOOL LinkExists(LPCTSTR pszLink) { CManageShellLinks CMngShellLinks(STARTUP_FOLDER);
return CMngShellLinks.LinkExists(pszLink); }
#ifdef __cplusplus
} #endif
|