Source code of Windows XP (NT5)
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.

301 lines
8.5 KiB

  1. // StartupLinks.cpp: implementation of the CManageShellLinks class
  2. // to manage Shell Folder links.
  3. //
  4. // Note: Multiple calls using the same class instance don't assume any
  5. // information about previous calls. The only stuff in common
  6. // is the IShellLink object and the specific shell folder.
  7. //////////////////////////////////////////////////////////////////////
  8. #include "stdio.h"
  9. #include "ManageShellLinks.h"
  10. #include "_umclnt.h"
  11. #define SHELL_FOLDERS TEXT("Software\\Microsoft\\Windows\\CurrentVersion\\Explorer\\Shell Folders")
  12. #define LINK_EXT TEXT(".lnk")
  13. //////////////////////////////////////////////////////////////////////
  14. // Construction/Destruction
  15. //////////////////////////////////////////////////////////////////////
  16. CManageShellLinks::CManageShellLinks(
  17. LPCTSTR pszDestFolder // [in] Which shell folder to operate on
  18. )
  19. : m_pIShLink(0)
  20. , m_pszShellFolder(0)
  21. {
  22. // Get a pointer to the IShellLink interface
  23. HRESULT hr = CoCreateInstance(CLSID_ShellLink, NULL, CLSCTX_INPROC_SERVER,
  24. IID_IShellLink, (void **)&m_pIShLink);
  25. if (FAILED(hr) || !m_pIShLink)
  26. DBPRINTF(TEXT("CManageShellLinks::CManageShellLinks: CoCreateInstance failed 0x%x\r\n"), hr);
  27. m_pszShellFolder = new TCHAR[lstrlen(pszDestFolder)+1];
  28. if (m_pszShellFolder)
  29. lstrcpy(m_pszShellFolder, pszDestFolder);
  30. }
  31. CManageShellLinks::~CManageShellLinks()
  32. {
  33. if (m_pIShLink)
  34. {
  35. m_pIShLink->Release();
  36. m_pIShLink = 0;
  37. }
  38. if (m_pszShellFolder)
  39. {
  40. delete [] m_pszShellFolder;
  41. m_pszShellFolder = 0;
  42. }
  43. }
  44. //*****************************************************************************
  45. // GetFolderPath - returns shell folder path
  46. //
  47. // pszFolderPath [out] - pointer to location for shell folder
  48. // pulSize [in out] - pointer to size of pszFolderPath
  49. //
  50. // Returns TRUE if it found the folder name else FALSE
  51. //
  52. long CManageShellLinks::GetFolderPath(LPTSTR pszFolderPath, unsigned long *pulSize)
  53. {
  54. *pszFolderPath = 0;
  55. if (!m_pszShellFolder)
  56. return ERROR_NOT_ENOUGH_MEMORY;
  57. HKEY hkeyFolders;
  58. HKEY hkeyUser;
  59. // Open current user's hive and retrieve shell folder path
  60. long lRv = RegOpenCurrentUser(KEY_QUERY_VALUE, &hkeyUser);
  61. if (lRv == ERROR_SUCCESS)
  62. {
  63. lRv = RegOpenKeyEx(
  64. hkeyUser
  65. , SHELL_FOLDERS
  66. , 0,KEY_QUERY_VALUE
  67. , &hkeyFolders);
  68. RegCloseKey(hkeyUser);
  69. }
  70. if (lRv == ERROR_SUCCESS)
  71. {
  72. lRv = RegQueryValueEx(
  73. hkeyFolders
  74. , m_pszShellFolder
  75. , NULL, NULL
  76. , (LPBYTE)pszFolderPath
  77. , pulSize);
  78. RegCloseKey(hkeyFolders);
  79. }
  80. return lRv;
  81. }
  82. //*****************************************************************************
  83. // GetUsersFolderPath - returns the location of the current user's shell folder
  84. //
  85. // pszFolderPath [out] - pointer to location for shell folder
  86. // pulSize [in out] - pointer to size of pszFolderPath
  87. //
  88. // Returns TRUE if it found the folder name else FALSE
  89. //
  90. BOOL CManageShellLinks::GetUsersFolderPath(LPTSTR pszFolderPath, unsigned long *pulSize)
  91. {
  92. long lRv = ERROR_ACCESS_DENIED;
  93. unsigned long ulSize = 0;
  94. *pszFolderPath = 0;
  95. BOOL fError;
  96. if (m_pszShellFolder)
  97. {
  98. ulSize = *pulSize;
  99. // At this point, if UtilMan was started in the system context (WinKey+U),
  100. // HKCU points to "Default User". We need it to point to the logged on
  101. // user's hive so we can get the correct path for the logged on user.
  102. // Note: GetUserAccessToken() will fail if we are not started by SYSTEM
  103. // and in that case just get the logged on user's folder path.
  104. HANDLE hMyToken = GetUserAccessToken(TRUE, &fError);
  105. if (hMyToken)
  106. {
  107. if (ImpersonateLoggedOnUser(hMyToken))
  108. {
  109. lRv = GetFolderPath(pszFolderPath, &ulSize);
  110. RevertToSelf();
  111. }
  112. CloseHandle(hMyToken);
  113. }
  114. else
  115. {
  116. lRv = GetFolderPath(pszFolderPath, &ulSize);
  117. }
  118. }
  119. *pulSize = ulSize;
  120. return (lRv == ERROR_SUCCESS)?TRUE:FALSE;
  121. }
  122. //*****************************************************************************
  123. // CreateLinkPath - returns the complete path and name of the link. Caller
  124. // free's the memory.
  125. //
  126. // pszLink [in] - the base name of the link itself
  127. //
  128. LPTSTR CManageShellLinks::CreateLinkPath(LPCTSTR pszLink)
  129. {
  130. // allocate enough space for folder path + '\' + filename + NULL
  131. unsigned long ccbStartPath = MAX_PATH;
  132. LPTSTR pszLinkPath = new TCHAR [ccbStartPath + 1 + lstrlen(pszLink) + sizeof(LINK_EXT) + 1];
  133. if (!pszLinkPath)
  134. return NULL;
  135. // get the user's shell folder name
  136. if (!GetUsersFolderPath(pszLinkPath, &ccbStartPath) || !ccbStartPath)
  137. {
  138. delete [] pszLinkPath;
  139. return NULL;
  140. }
  141. // append the link name and extension
  142. lstrcat(pszLinkPath, TEXT("\\"));
  143. lstrcat(pszLinkPath, pszLink);
  144. lstrcat(pszLinkPath, LINK_EXT);
  145. return pszLinkPath;
  146. }
  147. //*****************************************************************************
  148. // LinkExists - returns TRUE if pszLink exists in the shell folder else FALSE
  149. //
  150. // pszLink [in] - the base name of the link itself
  151. //
  152. BOOL CManageShellLinks::LinkExists(LPCTSTR pszLink)
  153. {
  154. LPTSTR pszLinkPath = CreateLinkPath(pszLink);
  155. if (!pszLinkPath)
  156. return FALSE;
  157. DWORD dwAttr = GetFileAttributes(pszLinkPath);
  158. return (dwAttr == -1)?FALSE:TRUE;
  159. }
  160. //*****************************************************************************
  161. // RemoveLink - removes a link from the user's shell folder
  162. //
  163. // pszLink [in] - the base name of the link itself
  164. //
  165. // Returns S_OK on success or a standard HRESULT
  166. //
  167. HRESULT CManageShellLinks::RemoveLink(LPCTSTR pszLink)
  168. {
  169. if (!m_pIShLink)
  170. return E_FAIL;
  171. LPTSTR pszLinkPath = CreateLinkPath(pszLink);
  172. if (!pszLinkPath)
  173. return E_FAIL;
  174. int iRemoveFailed = _wremove(pszLinkPath);
  175. return (iRemoveFailed)?S_FALSE:S_OK;
  176. }
  177. //*****************************************************************************
  178. // CreateLink - creates a link in the user's shell folder
  179. //
  180. // pszLinkFile [in] - the fully qualified name of the file the link refers to
  181. // pszLink [in] - the base name of the link itself
  182. // pszStartIn [in] - working directory (may be NULL)
  183. // pszDesc [in] - the tooltip for the link (may be NULL)
  184. // pszArgs [in] - command line arguments (may be NULL)
  185. //
  186. // Returns S_OK on success or a standard HRESULT
  187. //
  188. HRESULT CManageShellLinks::CreateLink(
  189. LPCTSTR pszLink,
  190. LPCTSTR pszLinkFile,
  191. LPCTSTR pszStartIn,
  192. LPCTSTR pszDesc,
  193. LPCTSTR pszArgs
  194. )
  195. {
  196. if (!m_pIShLink)
  197. {
  198. DBPRINTF(TEXT("CManageShellLinks::CreateLink: !m_pIShLink\r\n"));
  199. return E_FAIL;
  200. }
  201. LPTSTR pszLinkPath = CreateLinkPath(pszLink);
  202. if (!pszLinkPath)
  203. {
  204. DBPRINTF(TEXT("CManageShellLinks::CreateLink: !pszLinkPath\r\n"));
  205. return E_FAIL;
  206. }
  207. IPersistFile *pIPersistFile;
  208. // Get the IPersistFile interface to save the shortcut
  209. HRESULT hr = m_pIShLink->QueryInterface(IID_IPersistFile, (void **)&pIPersistFile);
  210. if (SUCCEEDED(hr))
  211. {
  212. // Set the path to and description of the link
  213. // The shortcut
  214. if (FAILED(m_pIShLink->SetPath(pszLinkFile)))
  215. DBPRINTF(TEXT("SetPath failed!\r\n"));
  216. // ToolTip description
  217. if (pszDesc && FAILED(m_pIShLink->SetDescription(pszDesc)))
  218. DBPRINTF(TEXT("SetDescription failed!\r\n"));
  219. // Working directory
  220. if (pszStartIn && FAILED(m_pIShLink->SetWorkingDirectory(pszStartIn)))
  221. DBPRINTF(TEXT("SetWorkingDirectory failed!\r\n"));
  222. // Command line args
  223. if (pszArgs && FAILED(m_pIShLink->SetArguments(pszArgs)))
  224. DBPRINTF(TEXT("SetArguments failed!\r\n"));
  225. // Save it
  226. if (FAILED(pIPersistFile->Save(pszLinkPath, TRUE)))
  227. DBPRINTF(TEXT("Save failed!\r\n"));
  228. pIPersistFile->Release();
  229. }
  230. delete [] pszLinkPath;
  231. return hr;
  232. }
  233. #ifdef __cplusplus
  234. extern "C" {
  235. #endif
  236. //*****************************************************************************
  237. // LinkExists - helper function called from C returns TRUE if pszLink exists
  238. // in the shell folder else FALSE
  239. //
  240. // pszLink [in] - the base name of the link itself
  241. //
  242. BOOL LinkExists(LPCTSTR pszLink)
  243. {
  244. CManageShellLinks CMngShellLinks(STARTUP_FOLDER);
  245. return CMngShellLinks.LinkExists(pszLink);
  246. }
  247. #ifdef __cplusplus
  248. }
  249. #endif