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.

308 lines
9.2 KiB

  1. #include "shellprv.h"
  2. #pragma hdrstop
  3. #include <ntimage.h>
  4. #include <ntrtl.h>
  5. static DWORD s_dwThreadIDSuspendNotify = 0;
  6. STDAPI_(BOOL) SuspendSHNotify()
  7. {
  8. DWORD dwID = GetCurrentThreadId();
  9. DWORD dwOldID = InterlockedCompareExchange(&s_dwThreadIDSuspendNotify, dwID, 0);
  10. return (dwOldID == 0);
  11. }
  12. STDAPI_(BOOL) ResumeSHNotify()
  13. {
  14. DWORD dwID = GetCurrentThreadId();
  15. DWORD dwOldID = InterlockedCompareExchange(&s_dwThreadIDSuspendNotify, 0, dwID);
  16. return (dwOldID == dwID);
  17. }
  18. STDAPI_(BOOL) SHMoveFile(LPCTSTR pszExisting, LPCTSTR pszNew, LONG lEvent)
  19. {
  20. BOOL res;
  21. // CreateDirectory fails if the directory name being created does
  22. // not have room for an 8.3 name to be tagged onto the end of it,
  23. // i.e., lstrlen(new_directory_name)+12 must be less or equal to MAX_PATH.
  24. // However, NT does not impose this restriction on MoveFile -- which the
  25. // shell sometimes uses to manipulate directory names. So, in order to
  26. // maintain consistency, we now check the length of the name before we
  27. // move the directory...
  28. if (IsDirPathTooLongForCreateDir(pszNew) &&
  29. (GetFileAttributes(pszExisting) & FILE_ATTRIBUTE_DIRECTORY))
  30. {
  31. SetLastError(ERROR_FILENAME_EXCED_RANGE);
  32. res = FALSE;
  33. }
  34. else
  35. {
  36. res = MoveFile(pszExisting, pszNew);
  37. if (FALSE == res)
  38. {
  39. // If we couldn't move the file, see if it had the readonly or system attributes.
  40. // If so, clear them, move the file, and set them back on the destination
  41. DWORD dwAttributes = GetFileAttributes(pszExisting);
  42. if (-1 != dwAttributes && (dwAttributes & (FILE_ATTRIBUTE_READONLY | FILE_ATTRIBUTE_SYSTEM)))
  43. {
  44. if (SetFileAttributes(pszExisting, dwAttributes & ~(FILE_ATTRIBUTE_READONLY | FILE_ATTRIBUTE_SYSTEM)))
  45. {
  46. res = MoveFile(pszExisting, pszNew);
  47. if (res)
  48. {
  49. SetFileAttributes(pszNew, dwAttributes);
  50. }
  51. else
  52. {
  53. SetFileAttributes(pszExisting, dwAttributes); // if move failed, return attributes.
  54. }
  55. }
  56. }
  57. }
  58. }
  59. if (res && s_dwThreadIDSuspendNotify != GetCurrentThreadId())
  60. {
  61. SHChangeNotify(lEvent, SHCNF_PATH, pszExisting, pszNew);
  62. }
  63. return res;
  64. }
  65. STDAPI_(BOOL) Win32MoveFile(LPCTSTR pszExisting, LPCTSTR pszNew, BOOL fDir)
  66. {
  67. return SHMoveFile(pszExisting, pszNew, fDir ? SHCNE_RENAMEFOLDER : SHCNE_RENAMEITEM);
  68. }
  69. STDAPI_(BOOL) Win32DeleteFilePidl(LPCTSTR pszFileName, LPCITEMIDLIST pidlFile)
  70. {
  71. BOOL res = DeleteFile(pszFileName);
  72. if (FALSE == res)
  73. {
  74. // If we couldn't delete the file, see if it has the readonly or
  75. // system bits set. If so, clear them and try again
  76. DWORD dwAttributes = GetFileAttributes(pszFileName);
  77. if (-1 != dwAttributes && (dwAttributes & (FILE_ATTRIBUTE_READONLY | FILE_ATTRIBUTE_SYSTEM)))
  78. {
  79. if (SetFileAttributes(pszFileName, dwAttributes & ~(FILE_ATTRIBUTE_READONLY | FILE_ATTRIBUTE_SYSTEM)))
  80. {
  81. res = DeleteFile(pszFileName);
  82. }
  83. }
  84. }
  85. if (res && s_dwThreadIDSuspendNotify != GetCurrentThreadId())
  86. {
  87. if (pidlFile)
  88. {
  89. SHChangeNotify(SHCNE_DELETE, SHCNF_IDLIST, pidlFile, NULL);
  90. }
  91. else
  92. {
  93. SHChangeNotify(SHCNE_DELETE, SHCNF_PATH, pszFileName, NULL);
  94. }
  95. }
  96. return res;
  97. }
  98. STDAPI_(BOOL) Win32DeleteFile(LPCTSTR pszFileName)
  99. {
  100. return Win32DeleteFilePidl(pszFileName, NULL);
  101. }
  102. STDAPI_(BOOL) Win32CreateDirectory(LPCTSTR pszPath, LPSECURITY_ATTRIBUTES lpsa)
  103. {
  104. BOOL res = CreateDirectory(pszPath, lpsa);
  105. if (res && s_dwThreadIDSuspendNotify != GetCurrentThreadId())
  106. {
  107. SHChangeNotify(SHCNE_MKDIR, SHCNF_PATH, pszPath, NULL);
  108. }
  109. return res;
  110. }
  111. //
  112. // Some filesystems (like NTFS, perchance) actually pay attention to
  113. // the readonly bit on folders. So, in order to pretend we're sort of
  114. // FAT and dumb, we clear the attribute before trying to delete the
  115. // directory.
  116. //
  117. STDAPI_(BOOL) Win32RemoveDirectory(LPCTSTR pszDir)
  118. {
  119. BOOL res = RemoveDirectory(pszDir);
  120. if (FALSE == res)
  121. {
  122. DWORD dwAttr = GetFileAttributes(pszDir);
  123. if ((-1 != dwAttr) && (dwAttr & FILE_ATTRIBUTE_READONLY))
  124. {
  125. dwAttr &= ~FILE_ATTRIBUTE_READONLY;
  126. SetFileAttributes(pszDir, dwAttr);
  127. res = RemoveDirectory(pszDir);
  128. }
  129. }
  130. if (res && s_dwThreadIDSuspendNotify != GetCurrentThreadId())
  131. {
  132. SHChangeNotify(SHCNE_RMDIR, SHCNF_PATH, pszDir, NULL);
  133. }
  134. return res;
  135. }
  136. STDAPI_(HANDLE) Win32CreateFile(LPCTSTR pszFileName, DWORD dwAttrib)
  137. {
  138. HANDLE hFile = CreateFile(pszFileName, GENERIC_READ | GENERIC_WRITE,
  139. FILE_SHARE_READ | FILE_SHARE_WRITE,
  140. NULL, CREATE_ALWAYS, dwAttrib & FILE_ATTRIBUTE_VALID_FLAGS,
  141. NULL);
  142. if (INVALID_HANDLE_VALUE != hFile && s_dwThreadIDSuspendNotify != GetCurrentThreadId())
  143. {
  144. SHChangeNotify(SHCNE_CREATE, SHCNF_PATH, pszFileName, NULL);
  145. }
  146. return hFile;
  147. }
  148. STDAPI_(BOOL) CreateWriteCloseFile(HWND hwnd, LPCTSTR pszFile, void *pData, DWORD cbData)
  149. {
  150. BOOL bRet;
  151. HANDLE hfile = Win32CreateFile(pszFile, 0);
  152. if (hfile != INVALID_HANDLE_VALUE)
  153. {
  154. if (cbData)
  155. {
  156. DWORD dwBytesWritten;
  157. WriteFile(hfile, pData, cbData, &dwBytesWritten, 0);
  158. }
  159. CloseHandle(hfile);
  160. bRet = TRUE;
  161. }
  162. else
  163. {
  164. TCHAR szPath[MAX_PATH];
  165. lstrcpyn(szPath, pszFile, ARRAYSIZE(szPath));
  166. PathRemoveExtension(szPath);
  167. SHSysErrorMessageBox(hwnd, NULL, IDS_CANNOTCREATEFILE,
  168. GetLastError(), PathFindFileName(szPath),
  169. MB_OK | MB_ICONEXCLAMATION);
  170. bRet = FALSE;
  171. }
  172. return bRet;
  173. }
  174. #undef SHGetProcessDword
  175. STDAPI_(DWORD) SHGetProcessDword(DWORD idProcess, LONG iIndex)
  176. {
  177. return 0;
  178. }
  179. STDAPI_(BOOL) SHSetShellWindowEx(HWND hwnd, HWND hwndChild)
  180. {
  181. return SetShellWindowEx(hwnd, hwndChild);
  182. }
  183. #define ISEXETSAWARE_MAX_IMAGESIZE (4 * 1024) // allocate at most a 4k block to hold the image header (eg 1 page on x86)
  184. //
  185. // this is a function that takes a full path to an executable and returns whether or not
  186. // the exe has the TS_AWARE bit set in the image header
  187. //
  188. STDAPI_(BOOL) IsExeTSAware(LPCTSTR pszExe)
  189. {
  190. BOOL bRet = FALSE;
  191. HANDLE hFile = CreateFile(pszExe,
  192. GENERIC_READ,
  193. FILE_SHARE_READ | FILE_SHARE_WRITE,
  194. NULL,
  195. OPEN_EXISTING,
  196. FILE_ATTRIBUTE_NORMAL | FILE_FLAG_SEQUENTIAL_SCAN,
  197. NULL);
  198. if (hFile != INVALID_HANDLE_VALUE)
  199. {
  200. DWORD cbImageSize = GetFileSize(hFile, NULL);
  201. LPBYTE pBuffer;
  202. if (cbImageSize > ISEXETSAWARE_MAX_IMAGESIZE)
  203. {
  204. // 64k should be enough to get the image header for everything...
  205. cbImageSize = ISEXETSAWARE_MAX_IMAGESIZE;
  206. }
  207. pBuffer = LocalAlloc(LPTR, cbImageSize);
  208. if (pBuffer)
  209. {
  210. HANDLE hMap = CreateFileMapping(hFile, NULL, PAGE_READONLY | SEC_IMAGE, 0, cbImageSize, NULL);
  211. if (hMap)
  212. {
  213. // map the first 4k of the file in
  214. LPBYTE pFileMapping = (LPBYTE)MapViewOfFile(hMap, FILE_MAP_READ, 0, 0, cbImageSize);
  215. if (pFileMapping)
  216. {
  217. _try
  218. {
  219. memcpy(pBuffer, pFileMapping, cbImageSize);
  220. }
  221. _except(UnhandledExceptionFilter(GetExceptionInformation()))
  222. {
  223. // We hit an exception while copying! doh!
  224. LocalFree(pBuffer);
  225. pBuffer = NULL;
  226. }
  227. UnmapViewOfFile(pFileMapping);
  228. }
  229. else
  230. {
  231. LocalFree(pBuffer);
  232. pBuffer = NULL;
  233. }
  234. CloseHandle(hMap);
  235. }
  236. else
  237. {
  238. LocalFree(pBuffer);
  239. pBuffer = NULL;
  240. }
  241. if (pBuffer)
  242. {
  243. PIMAGE_NT_HEADERS pImageNTHeader;
  244. // NOTE: this should work ok for 64-bit images too, since both the IMAGE_NT_HEADERS and the IMAGE_NT_HEADERS64
  245. // structs have a ->Signature and ->OptionalHeader that is identical up to the DllCharacteristics offset.
  246. pImageNTHeader = RtlImageNtHeader(pBuffer);
  247. if (pImageNTHeader)
  248. {
  249. if (pImageNTHeader->OptionalHeader.DllCharacteristics & IMAGE_DLLCHARACTERISTICS_TERMINAL_SERVER_AWARE)
  250. {
  251. // yes, this is a TSAWARE executable!
  252. bRet = TRUE;
  253. }
  254. }
  255. LocalFree(pBuffer);
  256. }
  257. }
  258. CloseHandle(hFile);
  259. }
  260. return bRet;
  261. }