Leaked source code of windows server 2003
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.

308 lines
9.0 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. DWORD dwType;
  73. lRv = RegQueryValueEx(
  74. hkeyFolders
  75. , m_pszShellFolder
  76. , NULL
  77. , &dwType
  78. , (LPBYTE)pszFolderPath
  79. , pulSize);
  80. if (lRv != ERROR_SUCCESS || dwType != REG_SZ)
  81. pszFolderPath[0] = TEXT('\0');
  82. pszFolderPath[*pulSize-1] = TEXT('\0');
  83. RegCloseKey(hkeyFolders);
  84. }
  85. return lRv;
  86. }
  87. //*****************************************************************************
  88. // GetUsersFolderPath - returns the location of the current user's shell folder
  89. //
  90. // pszFolderPath [out] - pointer to location for shell folder
  91. // pulSize [in out] - pointer to size of pszFolderPath
  92. //
  93. // Returns TRUE if it found the folder name else FALSE
  94. //
  95. BOOL CManageShellLinks::GetUsersFolderPath(LPTSTR pszFolderPath, unsigned long *pulSize)
  96. {
  97. long lRv = ERROR_ACCESS_DENIED;
  98. unsigned long ulSize = 0;
  99. *pszFolderPath = 0;
  100. if (m_pszShellFolder)
  101. {
  102. ulSize = *pulSize;
  103. BOOL fError;
  104. // At this point, if UtilMan was started in the system context (WinKey+U),
  105. // HKCU points to "Default User". We need it to point to the logged on
  106. // user's hive so we can get the correct path for the logged on user.
  107. // Note: GetUserAccessToken() will fail if we are not started by SYSTEM
  108. // and in that case just get the logged on user's folder path.
  109. HANDLE hMyToken = GetUserAccessToken(TRUE, &fError);
  110. if (hMyToken)
  111. {
  112. if (ImpersonateLoggedOnUser(hMyToken))
  113. {
  114. lRv = GetFolderPath(pszFolderPath, &ulSize);
  115. RevertToSelf();
  116. }
  117. CloseHandle(hMyToken);
  118. }
  119. else
  120. {
  121. lRv = GetFolderPath(pszFolderPath, &ulSize);
  122. }
  123. }
  124. *pulSize = ulSize;
  125. return (lRv == ERROR_SUCCESS)?TRUE:FALSE;
  126. }
  127. //*****************************************************************************
  128. // CreateLinkPath - returns the complete path and name of the link. Caller
  129. // free's the memory.
  130. //
  131. // pszLink [in] - the base name of the link itself
  132. //
  133. LPTSTR CManageShellLinks::CreateLinkPath(LPCTSTR pszLink)
  134. {
  135. // allocate enough space for folder path + '\' + filename + NULL
  136. unsigned long ccbStartPath = MAX_PATH;
  137. LPTSTR pszLinkPath = new TCHAR [ccbStartPath + 1 + lstrlen(pszLink) + sizeof(LINK_EXT) + 1];
  138. if (!pszLinkPath)
  139. return NULL;
  140. // get the user's shell folder name
  141. if (!GetUsersFolderPath(pszLinkPath, &ccbStartPath) || !ccbStartPath)
  142. {
  143. delete [] pszLinkPath;
  144. return NULL;
  145. }
  146. // append the link name and extension
  147. lstrcat(pszLinkPath, TEXT("\\"));
  148. lstrcat(pszLinkPath, pszLink);
  149. lstrcat(pszLinkPath, LINK_EXT);
  150. return pszLinkPath;
  151. }
  152. //*****************************************************************************
  153. // LinkExists - returns TRUE if pszLink exists in the shell folder else FALSE
  154. //
  155. // pszLink [in] - the base name of the link itself
  156. //
  157. BOOL CManageShellLinks::LinkExists(LPCTSTR pszLink)
  158. {
  159. LPTSTR pszLinkPath = CreateLinkPath(pszLink);
  160. if (!pszLinkPath)
  161. return FALSE;
  162. DWORD dwAttr = GetFileAttributes(pszLinkPath);
  163. delete [] pszLinkPath;
  164. return (dwAttr == -1)?FALSE:TRUE;
  165. }
  166. //*****************************************************************************
  167. // RemoveLink - removes a link from the user's shell folder
  168. //
  169. // pszLink [in] - the base name of the link itself
  170. //
  171. // Returns S_OK on success or a standard HRESULT
  172. //
  173. HRESULT CManageShellLinks::RemoveLink(LPCTSTR pszLink)
  174. {
  175. if (!m_pIShLink)
  176. return E_FAIL;
  177. LPTSTR pszLinkPath = CreateLinkPath(pszLink);
  178. if (!pszLinkPath)
  179. return E_FAIL;
  180. int iRemoveFailed = _wremove(pszLinkPath);
  181. delete [] pszLinkPath;
  182. return (iRemoveFailed)?S_FALSE:S_OK;
  183. }
  184. //*****************************************************************************
  185. // CreateLink - creates a link in the user's shell folder
  186. //
  187. // pszLinkFile [in] - the fully qualified name of the file the link refers to
  188. // pszLink [in] - the base name of the link itself
  189. // pszStartIn [in] - working directory (may be NULL)
  190. // pszDesc [in] - the tooltip for the link (may be NULL)
  191. // pszArgs [in] - command line arguments (may be NULL)
  192. //
  193. // Returns S_OK on success or a standard HRESULT
  194. //
  195. HRESULT CManageShellLinks::CreateLink(
  196. LPCTSTR pszLink,
  197. LPCTSTR pszLinkFile,
  198. LPCTSTR pszStartIn,
  199. LPCTSTR pszDesc,
  200. LPCTSTR pszArgs
  201. )
  202. {
  203. if (!m_pIShLink)
  204. {
  205. DBPRINTF(TEXT("CManageShellLinks::CreateLink: !m_pIShLink\r\n"));
  206. return E_FAIL;
  207. }
  208. LPTSTR pszLinkPath = CreateLinkPath(pszLink);
  209. if (!pszLinkPath)
  210. {
  211. DBPRINTF(TEXT("CManageShellLinks::CreateLink: !pszLinkPath\r\n"));
  212. return E_FAIL;
  213. }
  214. IPersistFile *pIPersistFile;
  215. // Get the IPersistFile interface to save the shortcut
  216. HRESULT hr = m_pIShLink->QueryInterface(IID_IPersistFile, (void **)&pIPersistFile);
  217. if (SUCCEEDED(hr))
  218. {
  219. // Set the path to and description of the link
  220. // The shortcut
  221. if (FAILED(m_pIShLink->SetPath(pszLinkFile)))
  222. DBPRINTF(TEXT("SetPath failed!\r\n"));
  223. // ToolTip description
  224. if (pszDesc && FAILED(m_pIShLink->SetDescription(pszDesc)))
  225. DBPRINTF(TEXT("SetDescription failed!\r\n"));
  226. // Working directory
  227. if (pszStartIn && FAILED(m_pIShLink->SetWorkingDirectory(pszStartIn)))
  228. DBPRINTF(TEXT("SetWorkingDirectory failed!\r\n"));
  229. // Command line args
  230. if (pszArgs && FAILED(m_pIShLink->SetArguments(pszArgs)))
  231. DBPRINTF(TEXT("SetArguments failed!\r\n"));
  232. // Save it
  233. if (FAILED(pIPersistFile->Save(pszLinkPath, TRUE)))
  234. DBPRINTF(TEXT("Save failed!\r\n"));
  235. pIPersistFile->Release();
  236. }
  237. delete [] pszLinkPath;
  238. return hr;
  239. }
  240. #ifdef __cplusplus
  241. extern "C" {
  242. #endif
  243. //*****************************************************************************
  244. // LinkExists - helper function called from C returns TRUE if pszLink exists
  245. // in the shell folder else FALSE
  246. //
  247. // pszLink [in] - the base name of the link itself
  248. //
  249. BOOL LinkExists(LPCTSTR pszLink)
  250. {
  251. CManageShellLinks CMngShellLinks(STARTUP_FOLDER);
  252. return CMngShellLinks.LinkExists(pszLink);
  253. }
  254. #ifdef __cplusplus
  255. }
  256. #endif