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.

377 lines
12 KiB

  1. //
  2. // MyDocs.cpp
  3. //
  4. // Code to call or simulate CreateSharedDocuments in mydocs.dll
  5. //
  6. #include "stdafx.h"
  7. #include "TheApp.h"
  8. #include "MyDocs.h"
  9. #include "Util.h"
  10. #include "NetUtil.h"
  11. #include "Sharing.h"
  12. #include "unicwrap.h"
  13. extern "C" void APIENTRY CreateSharedDocuments(HWND hwndStub, HINSTANCE hAppInstance, LPSTR pszCmdLine, int nCmdShow);
  14. typedef void (APIENTRY* CREATESHAREDDOCS_PROC)(HWND, HINSTANCE, LPSTR, int);
  15. // Local functions
  16. //
  17. HRESULT MySHGetFolderPath(HWND hwndOwner, int nFolder, HANDLE hToken, DWORD dwFlags, LPTSTR pszPath);
  18. #ifndef CSIDL_COMMON_DOCUMENTS
  19. #define CSIDL_COMMON_DOCUMENTS 0x002e
  20. #endif
  21. #ifndef SHGFP_TYPE_CURRENT
  22. #define SHGFP_TYPE_CURRENT 0
  23. #endif
  24. #define CSIDL_FLAG_CREATE 0x8000 // combine with CSIDL_ value to force create on SHGetSpecialFolderLocation()
  25. #ifndef IID_PPV_ARG
  26. #define IID_PPV_ARG(IType, ppType) IID_##IType, reinterpret_cast<void**>(static_cast<IType**>(ppType))
  27. #define IID_X_PPV_ARG(IType, X, ppType) IID_##IType, X, reinterpret_cast<void**>(static_cast<IType**>(ppType))
  28. #endif
  29. #define DEFINE_GUID_EMBEDDED(name, l, w1, w2, b1, b2, b3, b4, b5, b6, b7, b8) \
  30. EXTERN_C const GUID name \
  31. = { l, w1, w2, { b1, b2, b3, b4, b5, b6, b7, b8 } }
  32. DEFINE_GUID_EMBEDDED(CLSID_FolderShortcut_private, 0x0AFACED1,0xE828,0x11D1,0x91,0x87,0xB5,0x32,0xF1,0xE9,0x57,0x5D);
  33. int GetSharedDocsDirectory(LPTSTR pszPath, BOOL bCreate)
  34. {
  35. *pszPath = TEXT('\0');
  36. // Try to find the Shared Documents folder the official way...
  37. HRESULT hr = MyGetSpecialFolderPath(CSIDL_COMMON_DOCUMENTS, pszPath);
  38. // This version of the OS doesn't know about Common Documents
  39. if (FAILED(hr))
  40. {
  41. // Check for "Common Documents" registry entry
  42. CRegistry reg;
  43. if (reg.OpenKey(HKEY_LOCAL_MACHINE, TEXT("Software\\Microsoft\\Windows\\CurrentVersion\\Explorer\\Shell Folders"), KEY_READ))
  44. {
  45. if (reg.QueryStringValue(TEXT("Common Documents"), pszPath, MAX_PATH))
  46. {
  47. DWORD dwAttrib = GetFileAttributes(pszPath);
  48. if (dwAttrib != 0xFFFFFFFF && 0 != (dwAttrib & FILE_ATTRIBUTE_DIRECTORY))
  49. {
  50. goto done;
  51. }
  52. }
  53. }
  54. int nFolder = bCreate ? CSIDL_PERSONAL | CSIDL_FLAG_CREATE : CSIDL_PERSONAL;
  55. MySHGetFolderPath(NULL, nFolder, NULL, 0, pszPath);
  56. int cch = lstrlen(pszPath);
  57. if (cch == 0 || pszPath[cch-1] != '\\')
  58. pszPath[cch++] = '\\';
  59. theApp.LoadString(IDS_SHAREDDOCS, pszPath + cch, MAX_PATH - cch);
  60. if (bCreate)
  61. CreateDirectory(pszPath, NULL);
  62. }
  63. done:
  64. return lstrlen(pszPath);
  65. }
  66. BOOL APIENTRY NetConn_IsSharedDocumentsShared()
  67. {
  68. BOOL bResult = FALSE;
  69. TCHAR szSharedDocs[MAX_PATH];
  70. if (GetSharedDocsDirectory(szSharedDocs))
  71. {
  72. DWORD dwAttrib = GetFileAttributes(szSharedDocs);
  73. if (dwAttrib != 0xFFFFFFFF && (dwAttrib & FILE_ATTRIBUTE_DIRECTORY))
  74. {
  75. if (IsFolderShared(szSharedDocs, TRUE))
  76. {
  77. bResult = TRUE;
  78. }
  79. }
  80. }
  81. return bResult;
  82. }
  83. BOOL MyPathRenameExtension(LPTSTR pszPath, LPCTSTR pszExt)
  84. {
  85. ASSERT(pszExt != NULL && *pszExt == _T('.'));
  86. LPTSTR pszOldExt = FindExtension(pszPath);
  87. if (*pszOldExt != _T('\0') || *(pszOldExt-1) == _T('.'))
  88. {
  89. pszOldExt--;
  90. }
  91. // Check that the new path won't exceed MAX_PATH, including trailing '\0'
  92. int cch = (int)(pszOldExt - pszPath) + lstrlen(pszExt);
  93. if (cch >= MAX_PATH - 1)
  94. return FALSE; // path too long!
  95. StrCpy(pszOldExt, pszExt);
  96. return TRUE;
  97. }
  98. HRESULT MySHGetFolderPath(HWND hwndOwner, int nFolder, HANDLE hToken, DWORD dwFlags, LPTSTR pszPath)
  99. {
  100. ASSERT(hToken == NULL); // not supported
  101. ASSERT(dwFlags == SHGFP_TYPE_CURRENT); // other flags not supported
  102. LPITEMIDLIST pidl;
  103. HRESULT hr;
  104. int nNakedFolder = (nFolder & ~CSIDL_FLAG_CREATE);
  105. // Get the full path of the directory in question
  106. //
  107. if (nNakedFolder == CSIDL_COMMON_DOCUMENTS) // special-case shared docs
  108. {
  109. GetSharedDocsDirectory(pszPath, nFolder & CSIDL_FLAG_CREATE);
  110. hr = S_OK;
  111. }
  112. else if (SUCCEEDED(hr = SHGetSpecialFolderLocation(NULL, nNakedFolder, &pidl)))
  113. {
  114. hr = SHGetPathFromIDList(pidl, pszPath) ? S_OK : E_FAIL;
  115. ILFree(pidl);
  116. }
  117. else // folder doesn't exist, handle some special cases
  118. {
  119. if (nNakedFolder == CSIDL_PERSONAL)
  120. {
  121. GetWindowsDirectory(pszPath, MAX_PATH);
  122. theApp.LoadString(IDS_MYDOCS, pszPath + 3, MAX_PATH - 3);
  123. hr = S_OK;
  124. }
  125. }
  126. // Create the directory if needed
  127. //
  128. if (SUCCEEDED(hr))
  129. {
  130. if (nFolder & CSIDL_FLAG_CREATE)
  131. {
  132. if (!DoesFileExist(pszPath))
  133. {
  134. if (!CreateDirectory(pszPath, NULL))
  135. {
  136. // Unknown error (could be lots of things, all unlikely)
  137. hr = E_FAIL;
  138. }
  139. }
  140. }
  141. }
  142. return hr;
  143. }
  144. HRESULT _MakeSharedDocsLink(CLSID clsid, LPCTSTR pszLinkFolder, LPCTSTR pszSharedDocsPath, LPTSTR pszExtension)
  145. {
  146. TCHAR wszComment[MAX_PATH];
  147. TCHAR wszName[MAX_PATH];
  148. theApp.LoadString(IDS_SHAREDDOCSCOMMENT, wszComment, ARRAYSIZE(wszComment));
  149. theApp.LoadString(IDS_SHAREDDOCS, wszName, ARRAYSIZE(wszName));
  150. if (pszExtension)
  151. MyPathRenameExtension(wszName, pszExtension);
  152. return MakeLnkFile(clsid, pszSharedDocsPath, wszComment, pszLinkFolder, wszName);
  153. }
  154. HRESULT _MakeSharedDocsLink(CLSID clsid, UINT csidl, LPCTSTR pszSharedDocsPath, LPTSTR pszExtension)
  155. {
  156. TCHAR szPath[MAX_PATH];
  157. HRESULT hr = MySHGetFolderPath(NULL, csidl | CSIDL_FLAG_CREATE, NULL, 0, szPath);
  158. if (SUCCEEDED(hr))
  159. {
  160. hr = _MakeSharedDocsLink(clsid, szPath, pszSharedDocsPath, pszExtension);
  161. }
  162. return hr;
  163. }
  164. #define NET_INFO TEXT("System\\CurrentControlSet\\Services\\VxD\\VNETSUP")
  165. void _GetMachineComment(LPTSTR pszBuffer, int cchBuffer)
  166. {
  167. pszBuffer[0] = TEXT('\0'); // null the buffer
  168. // attempt to read the comment for the machine from the registry
  169. HKEY hk;
  170. if (ERROR_SUCCESS == RegOpenKey(HKEY_LOCAL_MACHINE, NET_INFO, &hk))
  171. {
  172. DWORD dwSize = cchBuffer*sizeof(TCHAR);
  173. RegQueryValueEx(hk, TEXT("Comment"), NULL, NULL, (BYTE *)pszBuffer, &dwSize);
  174. RegCloseKey(hk);
  175. }
  176. // either that failed, or the user set the comment to NULL, therefore we
  177. // just read the computer name.
  178. if ( !pszBuffer[0] )
  179. {
  180. DWORD dwSize = cchBuffer;
  181. GetComputerName(pszBuffer, &dwSize);
  182. }
  183. }
  184. BOOL MySHSetIniString(LPCTSTR pszSection, LPCTSTR pszEntry, LPCTSTR pszValue, LPCTSTR pszIniFile)
  185. {
  186. return WritePrivateProfileString(pszSection, pszEntry, pszValue, pszIniFile);
  187. }
  188. BOOL GetShareName(LPTSTR pszName, UINT cchName)
  189. {
  190. TCHAR szBase[SHARE_NAME_LENGTH+1];
  191. int cchBase = theApp.LoadString(IDS_SHAREDDOCS_SHARENAME, szBase, _countof(szBase));
  192. if (cchBase != 0)
  193. {
  194. if (!g_fRunningOnNT)
  195. {
  196. CharUpper(szBase);
  197. }
  198. // Ensure that the share name is unique
  199. StrCpyN(pszName, szBase, cchName);
  200. for (int i = 2; IsShareNameInUse(pszName); i++)
  201. {
  202. loop_begin:
  203. // Format name like "Documents2"
  204. wnsprintf(pszName, cchName, TEXT("%s%d"), szBase, i);
  205. // Ensure the new name isn't too long (rare rare rare rare!)
  206. if (lstrlen(pszName) > SHARE_NAME_LENGTH)
  207. {
  208. ASSERT(cchBase > 0); // must be true, or string wouldn't be too long
  209. // REVIEW: this isn't DBCS compliant, but it's such a rare
  210. // case that I don't really care.
  211. szBase[--cchBase] = _T('\0');
  212. goto loop_begin;
  213. }
  214. }
  215. }
  216. return cchBase != 0;
  217. }
  218. BOOL ShareHelper(LPCTSTR pszPath, LPCTSTR pszShareName, DWORD dwAccess, BYTE bShareType, LPCTSTR pszReadOnlyPassword, LPCTSTR pszFullAccessPassword);
  219. void RenameShare(LPTSTR pszOldName, LPTSTR pszNewName)
  220. {
  221. SHARE_INFO_502* pShare2;
  222. if (GetShareInfo502(pszOldName, &pShare2))
  223. {
  224. pShare2->shi502_netname = pszNewName;
  225. SetShareInfo502(pszOldName, pShare2);
  226. NetApiBufferFree(pShare2);
  227. }
  228. }
  229. void APIENTRY NetConn_CreateSharedDocuments(HWND hwndStub, HINSTANCE hAppInstance, LPSTR pszCmdLine, int nCmdShow)
  230. {
  231. // Try to load the real version of this function
  232. HINSTANCE hInstMyDocs = LoadLibrary(TEXT("mydocs.dll"));
  233. if (hInstMyDocs != NULL)
  234. {
  235. CREATESHAREDDOCS_PROC pfn = (CREATESHAREDDOCS_PROC)GetProcAddress(hInstMyDocs, "CreateSharedDocuments");
  236. if (pfn != NULL)
  237. {
  238. (*pfn)(hwndStub, hAppInstance, pszCmdLine, nCmdShow);
  239. }
  240. FreeLibrary(hInstMyDocs);
  241. if (pfn != NULL)
  242. {
  243. if (!g_fRunningOnNT)
  244. {
  245. // rename share
  246. TCHAR szSharedDocs[MAX_PATH];
  247. GetSharedDocsDirectory(szSharedDocs, TRUE);
  248. TCHAR szShareName[SHARE_NAME_LENGTH+5];
  249. if (ShareNameFromPath(szSharedDocs, szShareName, ARRAYSIZE(szShareName)))
  250. {
  251. TCHAR szNewShareName[SHARE_NAME_LENGTH+5];
  252. if (GetShareName(szNewShareName, ARRAYSIZE(szNewShareName)))
  253. {
  254. RenameShare(szShareName, szNewShareName);
  255. }
  256. }
  257. }
  258. return;
  259. }
  260. }
  261. TCHAR szSharedDocs[MAX_PATH];
  262. GetSharedDocsDirectory(szSharedDocs, TRUE);
  263. // Save the folder path in the registry
  264. //
  265. CRegistry regFolders;
  266. if (regFolders.CreateKey(HKEY_LOCAL_MACHINE, TEXT("Software\\Microsoft\\Windows\\CurrentVersion\\Explorer\\Shell Folders")))
  267. {
  268. regFolders.SetStringValue(TEXT("Common Documents"), szSharedDocs);
  269. regFolders.CloseKey();
  270. }
  271. // stash a desktop.ini in the folder, then when the netcrawler finds this object it will
  272. // attempt to create the shortcut using this name
  273. //
  274. TCHAR szComment[64], szFormat[64], szDesktopIni[MAX_PATH];
  275. MakePath(szDesktopIni, szSharedDocs, TEXT("desktop.ini"));
  276. _GetMachineComment(szComment, _countof(szComment));
  277. theApp.LoadString(IDS_SHARECOMMENT, szFormat, _countof(szFormat));
  278. LPTSTR pszTemp = theApp.FormatStringAlloc(szFormat, szComment);
  279. MySHSetIniString(TEXT("FileSharingInformation"), TEXT("ShortcutName"), pszTemp, szDesktopIni);
  280. free(pszTemp);
  281. SetFileAttributes(szDesktopIni, FILE_ATTRIBUTE_HIDDEN | FILE_ATTRIBUTE_SYSTEM); // ensure it's hidden
  282. // Share the folder
  283. //
  284. if (!IsFolderShared(szSharedDocs, TRUE))
  285. {
  286. TCHAR szShareName[SHARE_NAME_LENGTH+5];
  287. if (GetShareName(szShareName, ARRAYSIZE(szShareName)))
  288. {
  289. ShareFolder(szSharedDocs, szShareName, NETACCESS_FULL, NULL, NULL);
  290. }
  291. }
  292. // Create shortcut to Shared Docs if it's in another user's MyDocs folder
  293. //
  294. TCHAR szMyDocs[MAX_PATH];
  295. if (SUCCEEDED(MySHGetFolderPath(NULL, CSIDL_PERSONAL | CSIDL_FLAG_CREATE, NULL, 0, szMyDocs)))
  296. {
  297. LPTSTR pchTemp = FindFileTitle(szSharedDocs) - 1;
  298. *pchTemp = TEXT('\0');
  299. BOOL bMatch = !StrCmpI(szMyDocs, szSharedDocs);
  300. *pchTemp = TEXT('\\');
  301. if (!bMatch) // don't create link right next to the folder itself
  302. {
  303. _MakeSharedDocsLink(CLSID_ShellLink, szMyDocs, szSharedDocs, TEXT(".lnk"));
  304. }
  305. }
  306. // Create shortcut in SendTo folder
  307. //
  308. _MakeSharedDocsLink(CLSID_ShellLink, CSIDL_SENDTO, szSharedDocs, TEXT(".lnk"));
  309. }