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.

533 lines
16 KiB

  1. /****************************** Module Header ******************************\
  2. *
  3. * Module Name: rtlres.c
  4. *
  5. * Copyright (c) 1985 - 1999, Microsoft Corporation
  6. *
  7. * Resource Loading Routines
  8. *
  9. * History:
  10. * 05-Apr-1991 ScottLu Fixed up, resource code is now shared between client
  11. * and server, added a few new resource loading routines.
  12. * 24-Sep-1990 MikeKe From win30
  13. \***************************************************************************/
  14. #include "precomp.h"
  15. #pragma hdrstop
  16. HICON IconFromBestImage(
  17. ICONFILEHEADER *pifh,
  18. LPNEWHEADER lpnhSrc,
  19. int cxDesired,
  20. int cyDesired,
  21. UINT LR_flags);
  22. /***************************************************************************\
  23. * LoadStringOrError
  24. *
  25. * NOTE: Passing a NULL value for lpch returns the string length. (WRONG!)
  26. *
  27. * Warning: The return count does not include the terminating NULL WCHAR;
  28. *
  29. * History:
  30. * 05-Apr-1991 ScottLu Fixed - code is now shared between client and server
  31. * 24-Sep-1990 MikeKe From Win30
  32. \***************************************************************************/
  33. int LoadStringOrError(
  34. HANDLE hModule,
  35. UINT wID,
  36. LPWSTR lpBuffer, // Unicode buffer
  37. int cchBufferMax, // cch in Unicode buffer
  38. WORD wLangId)
  39. {
  40. HANDLE hResInfo;
  41. HANDLE hStringSeg;
  42. LPTSTR lpsz;
  43. int cch;
  44. /*
  45. * Make sure the parms are valid.
  46. */
  47. if (lpBuffer == NULL) {
  48. RIPMSG0(RIP_WARNING, "LoadStringOrError: lpBuffer == NULL");
  49. return 0;
  50. }
  51. cch = 0;
  52. /*
  53. * String Tables are broken up into 16 string segments. Find the segment
  54. * containing the string we are interested in.
  55. */
  56. if (hResInfo = FINDRESOURCEEXW(hModule, (LPTSTR)ULongToPtr( ((LONG)(((USHORT)wID >> 4) + 1)) ), RT_STRING, wLangId)) {
  57. /*
  58. * Load that segment.
  59. */
  60. hStringSeg = LOADRESOURCE(hModule, hResInfo);
  61. /*
  62. * Lock the resource.
  63. */
  64. if (lpsz = (LPTSTR)LOCKRESOURCE(hStringSeg, hModule)) {
  65. /*
  66. * Move past the other strings in this segment.
  67. * (16 strings in a segment -> & 0x0F)
  68. */
  69. wID &= 0x0F;
  70. while (TRUE) {
  71. cch = *((UTCHAR *)lpsz++); // PASCAL like string count
  72. // first UTCHAR is count if TCHARs
  73. if (wID-- == 0) break;
  74. lpsz += cch; // Step to start if next string
  75. }
  76. /*
  77. * chhBufferMax == 0 means return a pointer to the read-only resource buffer.
  78. */
  79. if (cchBufferMax == 0) {
  80. *(LPTSTR *)lpBuffer = lpsz;
  81. } else {
  82. /*
  83. * Account for the NULL
  84. */
  85. cchBufferMax--;
  86. /*
  87. * Don't copy more than the max allowed.
  88. */
  89. if (cch > cchBufferMax)
  90. cch = cchBufferMax;
  91. /*
  92. * Copy the string into the buffer.
  93. */
  94. RtlCopyMemory(lpBuffer, lpsz, cch*sizeof(WCHAR));
  95. }
  96. /*
  97. * Unlock resource, but don't free it - better performance this
  98. * way.
  99. */
  100. UNLOCKRESOURCE(hStringSeg, hModule);
  101. }
  102. }
  103. /*
  104. * Append a NULL.
  105. */
  106. if (cchBufferMax != 0) {
  107. lpBuffer[cch] = 0;
  108. }
  109. return cch;
  110. }
  111. /***************************************************************************\
  112. * RtlLoadObjectFromDIBFile
  113. *
  114. * Loads a resource object from file.
  115. *
  116. * 05-Sep-1995 ChrisWil Created.
  117. \***************************************************************************/
  118. #define BITMAPFILEHEADER_SIZE 14
  119. #define MINHEADERS_SIZE (BITMAPFILEHEADER_SIZE + sizeof(BITMAPCOREHEADER))
  120. HANDLE RtlLoadObjectFromDIBFile(
  121. LPCWSTR lpszName,
  122. LPWSTR type,
  123. DWORD cxDesired,
  124. DWORD cyDesired,
  125. UINT LR_flags)
  126. {
  127. FILEINFO fi = { NULL, NULL, NULL };
  128. HANDLE hFile;
  129. HANDLE hFileMap = NULL;
  130. HANDLE hObj = NULL;
  131. TCHAR szFile[MAX_PATH];
  132. TCHAR szFile2[MAX_PATH];
  133. LPWSTR pszFileDummy;
  134. if (LR_flags & LR_ENVSUBST) {
  135. /*
  136. * Do any %% string substitutions. We need this feature to handle
  137. * loading custom cursors and icons from the registry which uses
  138. * %SystemRoot% in the paths. It also makes the shell's job
  139. * easier.
  140. */
  141. ExpandEnvironmentStrings(lpszName, szFile2, MAX_PATH);
  142. } else {
  143. lstrcpyn(szFile2, lpszName, MAX_PATH);
  144. }
  145. if (SearchPath(NULL, // use default search locations
  146. szFile2, // file name to search for
  147. NULL, // already have file name extension
  148. MAX_PATH, // how big is that buffer, anyway?
  149. szFile, // stick fully qualified path name here
  150. &pszFileDummy) == 0) {
  151. RIPERR0(ERROR_FILE_NOT_FOUND, RIP_VERBOSE, "");
  152. return NULL;
  153. }
  154. /*
  155. * Open File for reading.
  156. */
  157. hFile = CreateFileW(szFile,
  158. GENERIC_READ,
  159. FILE_SHARE_READ,
  160. NULL,
  161. OPEN_EXISTING,
  162. 0,
  163. NULL);
  164. if (hFile == INVALID_HANDLE_VALUE)
  165. goto Done;
  166. /*
  167. * Create file-mapping for the file in question.
  168. */
  169. hFileMap = CreateFileMapping(hFile, NULL, PAGE_READONLY, 0, 0, NULL);
  170. if (hFileMap == NULL)
  171. goto CloseDone;
  172. /*
  173. * Map the file into view.
  174. */
  175. fi.pFileMap = MapViewOfFile(hFileMap, FILE_MAP_READ, 0, 0, 0);
  176. if (fi.pFileMap == NULL)
  177. goto CloseDone;
  178. fi.pFileEnd = fi.pFileMap + GetFileSize(hFile, NULL);
  179. fi.pFilePtr = fi.pFileMap;
  180. fi.pszName = szFile;
  181. try {
  182. switch(PTR_TO_ID(type)) {
  183. case PTR_TO_ID(RT_BITMAP): {
  184. LPBITMAPFILEHEADER pBFH;
  185. UPBITMAPINFOHEADER upBIH;
  186. LPBYTE lpBits;
  187. DWORD cx;
  188. DWORD cy;
  189. WORD planes;
  190. WORD bpp;
  191. DWORD cbSizeImage = 0;
  192. DWORD cbSizeFile;
  193. DWORD cbSizeBits;
  194. /*
  195. * Set the BitmapFileHeader and BitmapInfoHeader pointers.
  196. */
  197. pBFH = (LPBITMAPFILEHEADER)fi.pFileMap;
  198. upBIH = (UPBITMAPINFOHEADER)(fi.pFileMap + BITMAPFILEHEADER_SIZE);
  199. /*
  200. * Are we dealing with a bitmap file.
  201. */
  202. if (pBFH->bfType != BFT_BITMAP)
  203. break;
  204. /*
  205. * We need to check the filesize against the potential size of
  206. * the image. Bad-Bitmaps would otherwise be able to slam us
  207. * if they lied about the size (and/or) the file is truncated.
  208. */
  209. if (upBIH->biSize == sizeof(BITMAPCOREHEADER)) {
  210. cx = ((UPBITMAPCOREHEADER)upBIH)->bcWidth;
  211. cy = ((UPBITMAPCOREHEADER)upBIH)->bcHeight;
  212. bpp = ((UPBITMAPCOREHEADER)upBIH)->bcBitCount;
  213. planes = ((UPBITMAPCOREHEADER)upBIH)->bcPlanes;
  214. } else {
  215. cx = upBIH->biWidth;
  216. cy = upBIH->biHeight;
  217. bpp = upBIH->biBitCount;
  218. planes = upBIH->biPlanes;
  219. if (upBIH->biSizeImage >= sizeof(BITMAPINFOHEADER)) {
  220. cbSizeImage = upBIH->biSizeImage;
  221. }
  222. }
  223. cbSizeFile = (DWORD)(fi.pFileEnd - fi.pFileMap);
  224. cbSizeBits = BitmapSize(cx, cy, planes, bpp);
  225. if ((!cbSizeImage && ((cbSizeFile - MINHEADERS_SIZE) < cbSizeBits)) ||
  226. (cbSizeImage && ((cbSizeFile - MINHEADERS_SIZE) < cbSizeImage))) {
  227. break;
  228. }
  229. /*
  230. * Get the bits-offset in the file.
  231. */
  232. if ((pBFH->bfOffBits >= (sizeof(BITMAPFILEHEADER) + sizeof(BITMAPCOREHEADER))) &&
  233. (pBFH->bfOffBits <= (cbSizeFile - cbSizeImage))) {
  234. lpBits = ((LPBYTE)upBIH) + pBFH->bfOffBits - sizeof(BITMAPFILEHEADER);
  235. } else {
  236. lpBits = NULL;
  237. }
  238. /*
  239. * Convert the dib-on-file to a bitmap-handle. This can
  240. * convert both CORE and INFO formats.
  241. */
  242. hObj = ConvertDIBBitmap(upBIH,
  243. cxDesired,
  244. cyDesired,
  245. LR_flags,
  246. NULL,
  247. &lpBits); // use these bits!
  248. }
  249. break;
  250. case PTR_TO_ID(RT_CURSOR):
  251. case PTR_TO_ID(RT_ICON):
  252. {
  253. RTAG *prtag;
  254. ICONFILEHEADER *pifh;
  255. /*
  256. * Is this a RIFF file?
  257. */
  258. prtag = (RTAG *)fi.pFileMap;
  259. if (prtag->ckID != FOURCC_RIFF) {
  260. NEWHEADER nh;
  261. pifh = (ICONFILEHEADER *)fi.pFileMap;
  262. /*
  263. * BUG?: looks like we can load icons as cursors and cursors
  264. * as icons. Does this work? Is this desired? (SAS)
  265. */
  266. if ((pifh->iReserved != 0) ||
  267. ((pifh->iResourceType != IMAGE_ICON) &&
  268. (pifh->iResourceType != IMAGE_CURSOR)) ||
  269. (pifh->cresIcons < 1))
  270. break;
  271. nh.ResType = ((type == RT_ICON) ? IMAGE_ICON : IMAGE_CURSOR);
  272. nh.ResCount = pifh->cresIcons;
  273. nh.Reserved = 0;
  274. /*
  275. * Get the size of the it and meanwhile seek the file pointer
  276. * to point at the DIB we want. Files that have more than one
  277. * icon/cursor are treated like a group. In other words,
  278. * each image is treated like an individual element in the res
  279. * dir. So we need to pick the best fit one...
  280. */
  281. hObj = IconFromBestImage(pifh,
  282. &nh,
  283. cxDesired,
  284. cyDesired,
  285. LR_flags);
  286. } else {
  287. BOOL fAni;
  288. hObj = LoadCursorIconFromFileMap(&fi,
  289. &type,
  290. cxDesired,
  291. cyDesired,
  292. LR_flags,
  293. &fAni);
  294. }
  295. }
  296. break;
  297. default:
  298. UserAssert(FALSE);
  299. break;
  300. } // switch
  301. } except (W32ExceptionHandler(FALSE, RIP_WARNING)) {
  302. hObj = NULL;
  303. }
  304. CloseDone:
  305. if (fi.pFileMap != NULL)
  306. UnmapViewOfFile(fi.pFileMap);
  307. if (hFileMap)
  308. CloseHandle(hFileMap);
  309. if (hFile && (hFile != INVALID_HANDLE_VALUE))
  310. CloseHandle(hFile);
  311. Done:
  312. #if DBG
  313. if (hObj == NULL) {
  314. RIPMSG1(RIP_WARNING,
  315. "RtlLoadObjectFromDIBFile: Couldn't read resource from %ws",
  316. lpszName);
  317. }
  318. #endif
  319. return hObj;
  320. }
  321. /***************************************************************************\
  322. * IconFromBestImage
  323. *
  324. * Creates HICON from best fitting image in the given file.
  325. *
  326. \***************************************************************************/
  327. HICON IconFromBestImage(
  328. ICONFILEHEADER *pifh,
  329. LPNEWHEADER lpnhSrc,
  330. int cxDesired,
  331. int cyDesired,
  332. UINT LR_flags)
  333. {
  334. UINT iImage;
  335. UINT iImageBest;
  336. LPNEWHEADER lpnhDst;
  337. LPRESDIR lprd;
  338. LPBYTE lpRes;
  339. DWORD cbDIB;
  340. HICON hIcon = NULL;
  341. IMAGEFILEHEADER *pimh;
  342. if (lpnhSrc->ResCount > 1) {
  343. /*
  344. * First, alloc dummy group resource.
  345. */
  346. lpnhDst = (LPNEWHEADER)UserLocalAlloc(0,
  347. sizeof(NEWHEADER) + (lpnhSrc->ResCount * sizeof(RESDIR)));
  348. if (lpnhDst == NULL)
  349. goto Done;
  350. *lpnhDst = *lpnhSrc;
  351. lprd = (LPRESDIR)(lpnhDst + 1);
  352. /*
  353. * Build up an image directory from the file's image header info.
  354. */
  355. for (pimh = pifh->imh, iImage=0;
  356. iImage < lpnhDst->ResCount;
  357. iImage++, lprd++, pimh++) {
  358. /*
  359. * Fill in RESDIR
  360. */
  361. lprd->Icon.Width = pimh->cx;
  362. lprd->Icon.Height = pimh->cy;
  363. lprd->Icon.reserved = 0;
  364. lprd->BytesInRes = pimh->cbDIB;
  365. lprd->idIcon = (WORD)iImage; // Make fake ID: the index of the image.
  366. if (lpnhDst->ResType == IMAGE_ICON) {
  367. /*
  368. * 10/18/2000 - dwaynen
  369. *
  370. * For icons, this is really an ICONDIRENTRY (which has
  371. * wPlanes and wBitCount fields that overlap xHotSpot and
  372. * yHotSpot!
  373. */
  374. lprd->Icon.ColorCount = pimh->nColors;
  375. lprd->Planes = pimh->xHotSpot;
  376. lprd->BitCount = pimh->yHotSpot;
  377. } else {
  378. /*
  379. * 10/18/2000 - dwaynen
  380. *
  381. * Hopefully, cursors will only have one image. Otherwise,
  382. * our selection logic is gonna be screwed up because we don't
  383. * store the color bit depth! I suppose we could dig out the
  384. * actual bitmap header and find the info there. Consider doing
  385. * this if we ever want to support multi-resource cursors.
  386. */
  387. lprd->Icon.ColorCount = 0;
  388. lprd->Planes = 0;
  389. lprd->BitCount = 0;
  390. }
  391. }
  392. /*
  393. * Find the best image in the group
  394. */
  395. iImageBest = LookupIconIdFromDirectoryEx((PBYTE)lpnhDst,
  396. (lpnhDst->ResType == IMAGE_ICON),
  397. cxDesired,
  398. cyDesired,
  399. LR_flags);
  400. /*
  401. * Get rid of fake group resource
  402. */
  403. UserLocalFree(lpnhDst);
  404. } else {
  405. iImageBest = 0;
  406. }
  407. /*
  408. * Point to selected image.
  409. */
  410. pimh = &pifh->imh[iImageBest];
  411. cbDIB = pimh->cbDIB;
  412. /*
  413. * If we're creating a cursor, we have to whack in HOTSPOT in front
  414. * Regardless of which type we are making, we need to make sure
  415. * the resource is aligned. Thus we always copy.
  416. */
  417. if (lpnhSrc->ResType == IMAGE_CURSOR)
  418. cbDIB += sizeof(POINTS);
  419. lpRes = (LPBYTE)UserLocalAlloc(0, cbDIB);
  420. if (lpRes == NULL)
  421. goto Done;
  422. if (lpnhSrc->ResType == IMAGE_CURSOR)
  423. lpRes += sizeof(POINTS);
  424. RtlCopyMemory(lpRes,
  425. ((LPBYTE)pifh) + pimh->offsetDIB,
  426. pimh->cbDIB);
  427. if (lpnhSrc->ResType == IMAGE_CURSOR) {
  428. lpRes -= sizeof(POINTS);
  429. ((LPPOINTS)lpRes)->x = pimh->xHotSpot;
  430. ((LPPOINTS)lpRes)->y = pimh->yHotSpot;
  431. }
  432. hIcon = CreateIconFromResourceEx(lpRes,
  433. cbDIB,
  434. (lpnhSrc->ResType == IMAGE_ICON),
  435. 0x00030000, // was WIN32VER40
  436. cxDesired,
  437. cyDesired,
  438. LR_flags);
  439. UserLocalFree(lpRes);
  440. Done:
  441. return hIcon;
  442. }