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.

219 lines
6.8 KiB

  1. //+---------------------------------------------------------------------------
  2. //
  3. // Microsoft Windows
  4. // Copyright (C) Microsoft Corporation, 1997.
  5. //
  6. // File: S h o r t C u t . C P P
  7. //
  8. // Contents: Creates shortcuts.
  9. //
  10. // Notes:
  11. //
  12. // Author: scottbri 19 June 1998
  13. //
  14. //----------------------------------------------------------------------------
  15. #include "pch.h"
  16. #pragma hdrstop
  17. #include "foldinc.h" // Standard shell\folder includes
  18. extern const WCHAR c_szBackslash[];
  19. const WCHAR c_szLinkExt[] = L".lnk";
  20. const WCHAR c_szVersionFormat[] = L" %d";
  21. //
  22. // Function: HrGenerateLinkName
  23. //
  24. // Purpose: Combine the link path, name, and extension and verify the file
  25. // doesn't already exist.
  26. //
  27. // Parameters: pstrNew [OUT] - The name and path of the .lnk shortcut
  28. // pszPath [IN] - The directory path for the link
  29. // pszConnName [IN] - The connection name itself
  30. //
  31. // Returns: HRESULT, S_OK on success, an error if the file will not be created
  32. //
  33. HRESULT HrGenerateLinkName(tstring * pstrNew, PCWSTR pszPath, PCWSTR pszConnName)
  34. {
  35. HRESULT hr = S_OK;
  36. tstring str;
  37. DWORD dwCnt = 0;
  38. do
  39. {
  40. // prepend the string with \\?\ so CreateFile will use a name buffer
  41. // larger than MAX_PATH
  42. str = L"\\\\?\\";
  43. str += pszPath;
  44. str += c_szBackslash;
  45. str += pszConnName;
  46. if (++dwCnt>1)
  47. {
  48. WCHAR szBuf[10];
  49. wsprintfW(szBuf, c_szVersionFormat, dwCnt);
  50. str += szBuf;
  51. }
  52. str += c_szLinkExt;
  53. HANDLE hFile = CreateFile(str.c_str(), GENERIC_READ, FILE_SHARE_READ,
  54. NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
  55. if (INVALID_HANDLE_VALUE == hFile)
  56. {
  57. hr = HRESULT_FROM_WIN32(GetLastError());
  58. if (HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND) == hr)
  59. {
  60. hr = S_OK; // Filename is unique
  61. }
  62. }
  63. else
  64. {
  65. CloseHandle(hFile);
  66. hr = HRESULT_FROM_WIN32(ERROR_DUP_NAME);
  67. }
  68. } while (HRESULT_FROM_WIN32(ERROR_DUP_NAME) == hr);
  69. if (SUCCEEDED(hr))
  70. {
  71. *pstrNew = str.c_str();
  72. }
  73. return hr;
  74. }
  75. LPITEMIDLIST ILCombinePriv(LPCITEMIDLIST pidl1, LPCITEMIDLIST pidl2);
  76. //
  77. // Function: HrCreateStartMenuShortCut
  78. //
  79. // Purpose: Create a shortcut to a connection in the start menu
  80. //
  81. // Parameters: hwndParent [IN] - Handle to a parent window
  82. // fAllUser [IN] - Create the connection for all users
  83. // pwszName [IN] - The connection name
  84. // pConn [IN] - Connection for which the shortcut is created
  85. //
  86. // Returns: BOOL, TRUE
  87. //
  88. HRESULT HrCreateStartMenuShortCut(HWND hwndParent,
  89. BOOL fAllUsers,
  90. PCWSTR pszName,
  91. INetConnection * pConn)
  92. {
  93. HRESULT hr = S_OK;
  94. PCONFOLDPIDL pidl;
  95. PCONFOLDPIDLFOLDER pidlFolder;
  96. LPSHELLFOLDER psfConnections = NULL;
  97. if ((NULL == pConn) || (NULL == pszName))
  98. {
  99. hr = E_INVALIDARG;
  100. goto Error;
  101. }
  102. // Create a pidl for the connection
  103. //
  104. hr = HrCreateConFoldPidl(WIZARD_NOT_WIZARD, pConn, pidl);
  105. if (SUCCEEDED(hr))
  106. {
  107. // Get the pidl for the Connections Folder
  108. //
  109. hr = HrGetConnectionsFolderPidl(pidlFolder);
  110. if (SUCCEEDED(hr))
  111. {
  112. // Get the Connections Folder object
  113. //
  114. hr = HrGetConnectionsIShellFolder(pidlFolder, &psfConnections);
  115. if (SUCCEEDED(hr))
  116. {
  117. tstring str;
  118. WCHAR szPath[MAX_PATH + 1] = {0};
  119. // Find the location to stash the shortcut
  120. //
  121. if (!SHGetSpecialFolderPath(hwndParent, szPath,
  122. (fAllUsers ? CSIDL_COMMON_DESKTOPDIRECTORY :
  123. CSIDL_DESKTOPDIRECTORY), FALSE))
  124. {
  125. hr = HrFromLastWin32Error();
  126. }
  127. else if (SUCCEEDED(hr) && wcslen(szPath))
  128. {
  129. LPITEMIDLIST pidlFull;
  130. // Combine the folder and connections pidl into a
  131. // fully qualified pidl.
  132. //
  133. pidlFull = ILCombinePriv(pidlFolder.GetItemIdList(), pidl.GetItemIdList());
  134. if (pidlFull)
  135. {
  136. IShellLink *psl = NULL;
  137. hr = CoCreateInstance(
  138. CLSID_ShellLink,
  139. NULL,
  140. CLSCTX_INPROC_SERVER | CLSCTX_NO_CODE_DOWNLOAD,
  141. IID_IShellLink,
  142. (LPVOID*)&psl);
  143. if (SUCCEEDED(hr))
  144. {
  145. IPersistFile *ppf = NULL;
  146. // Set the combined IDL
  147. //
  148. hr = psl->SetIDList(pidlFull);
  149. if (SUCCEEDED(hr))
  150. {
  151. hr = psl->QueryInterface(IID_IPersistFile,
  152. (LPVOID *)&ppf);
  153. if (SUCCEEDED(hr))
  154. {
  155. tstring strPath;
  156. // Generate the lnk filename
  157. //
  158. hr = HrGenerateLinkName(&strPath,
  159. szPath,
  160. pszName);
  161. if (SUCCEEDED(hr))
  162. {
  163. // Create the link file.
  164. //
  165. hr = ppf->Save(strPath.c_str(), TRUE);
  166. }
  167. ReleaseObj(ppf);
  168. }
  169. }
  170. ReleaseObj(psl);
  171. }
  172. if (pidlFull)
  173. FreeIDL(pidlFull);
  174. }
  175. else
  176. {
  177. hr = E_OUTOFMEMORY;
  178. }
  179. }
  180. else
  181. {
  182. TraceError("HrCreateStartMenuShortCut - Unable to find Start Menu save location", hr);
  183. }
  184. ReleaseObj(psfConnections);
  185. }
  186. }
  187. }
  188. Error:
  189. TraceError("HrCreateStartMenuShortCut", hr);
  190. return hr;
  191. }