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.

709 lines
18 KiB

  1. #include <windows.h>
  2. #include <windowsx.h>
  3. #include <win32.h>
  4. #include "lockbm.h"
  5. //////////////////////////////////////////////////////////////////////////////
  6. //////////////////////////////////////////////////////////////////////////////
  7. #ifndef BI_BITFIELDS
  8. #define BI_BITFIELDS 3
  9. #endif
  10. #ifndef BI_BITMAP
  11. #define BI_BITMAP 0x4D544942 // 'BITM'
  12. #endif
  13. //////////////////////////////////////////////////////////////////////////////
  14. //////////////////////////////////////////////////////////////////////////////
  15. //
  16. // GDI!GDIInit2() GDI.403
  17. //
  18. // this GDI function does the following:
  19. //
  20. // GetSetBitmapHandle(hbm, 0) - will return global handle of bitmap
  21. //
  22. // GetSetBitmapHandle(hbm, h) - will set global handle to <h>
  23. //
  24. // GetSetBitmapHandle(hbm, -1) - will set global handle to NULL
  25. //
  26. static HANDLE (FAR PASCAL *GetSetBitmapHandle)(HBITMAP hbm, HANDLE h);
  27. //////////////////////////////////////////////////////////////////////////////
  28. //////////////////////////////////////////////////////////////////////////////
  29. #define muldiv(a,b,c) (UINT)(((DWORD)(UINT)(a) * (DWORD)(UINT)(b)) / (UINT)(c))
  30. //////////////////////////////////////////////////////////////////////////////
  31. //
  32. // CanLockBitmaps()
  33. //
  34. // determime if we can lock bitmaps on the current display device
  35. //
  36. //////////////////////////////////////////////////////////////////////////////
  37. BOOL FAR CanLockBitmaps(void)
  38. {
  39. #ifndef _WIN32
  40. //its not safe to do this on NT. god only knows what gdi.403 is on future
  41. //nt platforms - the only thing we can be sure of is that it is NOT
  42. // GetSetBitmapHandle()
  43. UINT w;
  44. UINT rc;
  45. HDC hdc;
  46. BOOL f;
  47. static BOOL fCanLockBitmaps = -1;
  48. if (fCanLockBitmaps == -1)
  49. {
  50. w = (UINT)GetVersion();
  51. w = ((UINT)LOBYTE(w) << 8) | HIBYTE(w);
  52. hdc = GetDC(NULL);
  53. rc = GetDeviceCaps(hdc, RASTERCAPS);
  54. ReleaseDC(NULL, hdc);
  55. (FARPROC)GetSetBitmapHandle =
  56. GetProcAddress(GetModuleHandle(TEXT("GDI")),(LPCSTR)MAKEINTATOM(403));
  57. #ifdef _WIN32
  58. // MAKEINTATOM returns a LPTSTR.
  59. // GetProcAddress wants LPCSTR - NOT Unicode. Hence we cast
  60. #endif
  61. //
  62. // assume we dont need this on windows 4.0?
  63. //
  64. // what about the DIBENG? it does DEVBITS and in win 4.0?
  65. //
  66. // if the display handles device bitmaps, dont do this either
  67. //
  68. f = GetProfileIntA("DrawDib", "Bitmaps", TRUE);
  69. #ifdef DEBUG
  70. fCanLockBitmaps = f && GetSetBitmapHandle != NULL;
  71. #else
  72. fCanLockBitmaps = f && /* (w < 0x0400) && */
  73. !(rc & RC_DEVBITS) &&
  74. GetSetBitmapHandle != NULL;
  75. #endif
  76. }
  77. return fCanLockBitmaps;
  78. #else
  79. return FALSE;
  80. #endif
  81. }
  82. //////////////////////////////////////////////////////////////////////////////
  83. //
  84. // LockBitmap
  85. //
  86. // return a pointer to the bitmap bits
  87. //
  88. //////////////////////////////////////////////////////////////////////////////
  89. LPVOID FAR LockBitmap(HBITMAP hbm)
  90. {
  91. return GetBitmap(hbm, NULL, 0);
  92. }
  93. //////////////////////////////////////////////////////////////////////////////
  94. //
  95. // GetBitmapDIB
  96. //
  97. //////////////////////////////////////////////////////////////////////////////
  98. LPVOID FAR GetBitmapDIB(LPBITMAPINFOHEADER lpbi, LPVOID lpBits, LPVOID p, int cb)
  99. {
  100. IBITMAP FAR *pbm;
  101. if (lpBits == NULL)
  102. lpBits = (LPBYTE)lpbi + (int)lpbi->biSize + lpbi->biClrUsed * sizeof(RGBQUAD);
  103. if (p == NULL || cb < sizeof(BITMAP))
  104. return lpBits;
  105. pbm = p;
  106. if (lpbi->biCompression == 0)
  107. {
  108. switch ((int)lpbi->biBitCount + (int)lpbi->biPlanes*256)
  109. {
  110. case 0x0101: pbm->bmType = BM_1BIT; break;
  111. case 0x0104: pbm->bmType = BM_4BIT; break;
  112. case 0x0108: pbm->bmType = BM_8BIT; break;
  113. case 0x0110: pbm->bmType = BM_16555; break;
  114. case 0x0118: pbm->bmType = BM_24BGR; break;
  115. case 0x0120: pbm->bmType = BM_32BGR; break;
  116. case 0x0401: pbm->bmType = BM_VGA; break;
  117. default: return NULL;
  118. }
  119. }
  120. else if (lpbi->biCompression == BI_BITFIELDS)
  121. {
  122. switch ((int)lpbi->biBitCount + (int)lpbi->biPlanes*256)
  123. {
  124. //!!! hack: realy should check the bit fields!
  125. case 0x0110: pbm->bmType = BM_16565; break;
  126. case 0x0118: pbm->bmType = BM_24RGB; break;
  127. case 0x0120: pbm->bmType = BM_32RGB; break;
  128. default: return NULL;
  129. }
  130. }
  131. else
  132. return NULL;
  133. pbm->bmWidth = (int)lpbi->biWidth;
  134. pbm->bmHeight = ((int)lpbi->biHeight > 0) ? (int)lpbi->biHeight : -(int)lpbi->biHeight;
  135. pbm->bmWidthBytes = (((int)lpbi->biBitCount * (int)lpbi->biWidth + 31)&~31)/8;
  136. pbm->bmPlanes = (BYTE)lpbi->biPlanes;
  137. pbm->bmBitsPixel = (BYTE)lpbi->biBitCount;
  138. pbm->bmBits = lpBits;
  139. if (cb > sizeof(BITMAP))
  140. {
  141. pbm->bmSegmentIndex = 0;
  142. pbm->bmScanSegment = pbm->bmHeight;
  143. pbm->bmFillBytes = 0;
  144. pbm->bmBitmapInfo = (LONG)(LONG_PTR)lpbi;
  145. if ((long)lpbi->biHeight < 0)
  146. {
  147. pbm->bmNextScan = -pbm->bmWidthBytes;
  148. pbm->bmOffset = (long)pbm->bmWidthBytes * (pbm->bmHeight-1);
  149. }
  150. else
  151. {
  152. pbm->bmNextScan = pbm->bmWidthBytes;
  153. pbm->bmOffset = 0;
  154. }
  155. }
  156. return lpBits;
  157. }
  158. #if 0
  159. //////////////////////////////////////////////////////////////////////////////
  160. //////////////////////////////////////////////////////////////////////////////
  161. void FAR BitmapXY(IBITMAP FAR *pbm, int x, int y)
  162. {
  163. UINT t;
  164. if (pbm->bmFillBytes)
  165. {
  166. while (y-- > 0)
  167. {
  168. t = (UINT)(pbm->bmOffset & 0xFFFF0000);
  169. pbm->bmOffset += pbm->bmNextScan;
  170. if ((UINT)(pbm->bmOffset & 0xFFFF0000) != t)
  171. pbm->bmOffset += pbm->bmFillBytes;
  172. }
  173. }
  174. else
  175. {
  176. pbm->bmOffset += y * (long)pbm->bmNextScan;
  177. }
  178. pbm->bmOffset += x * pbm->bmBitsPixel / 8;
  179. }
  180. #endif
  181. //////////////////////////////////////////////////////////////////////////////
  182. //
  183. // GetDIBBitmap
  184. //
  185. //////////////////////////////////////////////////////////////////////////////
  186. /*
  187. * creates a DIB header for a bitmap, and returns a pointer to the bitmap
  188. * bits. This pointer is not used - it's checked against NULL, as if this
  189. * routine returned BOOL.
  190. *
  191. * On NT, you can't get the bitmap bits (wrong process) so we return 1 meaning
  192. * TRUE. You need to call SetBitmapBits to access the bits themselves.
  193. */
  194. LPVOID FAR GetDIBBitmap(HBITMAP hbm, LPBITMAPINFOHEADER lpbi)
  195. {
  196. UINT wType;
  197. BITMAP bm;
  198. UINT ScansPerSeg;
  199. UINT FillBytes;
  200. if (hbm)
  201. GetObject(hbm, sizeof(bm), &bm);
  202. wType = GetBitmapType();
  203. if (wType == 0)
  204. return NULL;
  205. lpbi->biSize = sizeof(BITMAPINFOHEADER);
  206. lpbi->biWidth = bm.bmWidth;
  207. lpbi->biHeight = bm.bmHeight;
  208. lpbi->biPlanes = bm.bmPlanes;
  209. lpbi->biBitCount = bm.bmBitsPixel;
  210. lpbi->biCompression = 0;
  211. lpbi->biSizeImage = (DWORD)(bm.bmWidthBytes * bm.bmPlanes) * (DWORD)bm.bmHeight;
  212. lpbi->biXPelsPerMeter = 0;
  213. lpbi->biYPelsPerMeter = 0;
  214. lpbi->biClrUsed = 0;
  215. lpbi->biClrImportant = 0;
  216. switch(wType & BM_TYPE)
  217. {
  218. case BM_VGA:
  219. break;
  220. case BM_1BIT:
  221. case BM_4BIT:
  222. case BM_8BIT:
  223. break;
  224. case BM_16555:
  225. break;
  226. case BM_24BGR:
  227. case BM_32BGR:
  228. break;
  229. case BM_16565:
  230. lpbi->biCompression = BI_BITFIELDS;
  231. lpbi->biSize += 3 * sizeof(DWORD);
  232. ((LPDWORD)(lpbi+1))[0] = 0x00F800;
  233. ((LPDWORD)(lpbi+1))[1] = 0x0007E0;
  234. ((LPDWORD)(lpbi+1))[2] = 0x00001F;
  235. break;
  236. case BM_24RGB:
  237. case BM_32RGB:
  238. lpbi->biCompression = BI_BITFIELDS;
  239. lpbi->biSize += 3 * sizeof(DWORD);
  240. ((LPDWORD)(lpbi+1))[0] = 0x0000FF;
  241. ((LPDWORD)(lpbi+1))[1] = 0x00FF00;
  242. ((LPDWORD)(lpbi+1))[2] = 0xFF0000;
  243. break;
  244. default:
  245. return NULL;
  246. }
  247. //
  248. // make sure WidthBytes is right, dont forget bitmaps are WORD aligned
  249. // and DIBs are DWORD aligned.
  250. //
  251. if (bm.bmWidthBytes != ((bm.bmWidth * bm.bmBitsPixel + 31) & ~31)/8)
  252. {
  253. if (lpbi->biCompression != 0)
  254. return NULL;
  255. lpbi->biCompression = BI_BITMAP;
  256. lpbi->biXPelsPerMeter = bm.bmWidthBytes;
  257. }
  258. if ((wType & BM_HUGE) && (lpbi->biSizeImage > 64*1024l))
  259. {
  260. if (lpbi->biCompression == BI_BITFIELDS)
  261. return NULL;
  262. lpbi->biCompression = BI_BITMAP;
  263. ScansPerSeg = muldiv(64,1024,bm.bmWidthBytes * bm.bmPlanes);
  264. FillBytes = (UINT)(64ul*1024 - bm.bmWidthBytes * bm.bmPlanes * ScansPerSeg);
  265. lpbi->biSizeImage += FillBytes * (bm.bmHeight / ScansPerSeg);
  266. lpbi->biXPelsPerMeter = bm.bmWidthBytes;
  267. lpbi->biYPelsPerMeter = FillBytes;
  268. }
  269. if (!(wType & BM_BOTTOMTOTOP))
  270. lpbi->biHeight = -bm.bmHeight;
  271. #ifdef _WIN32
  272. return (LPVOID) TRUE;
  273. #else
  274. return LockBitmap(hbm);
  275. #endif
  276. }
  277. //////////////////////////////////////////////////////////////////////////////
  278. //
  279. // GetBitmap
  280. //
  281. //////////////////////////////////////////////////////////////////////////////
  282. LPVOID FAR GetBitmap(HBITMAP hbm, LPVOID p, int cb)
  283. {
  284. HANDLE h;
  285. DWORD dwSize;
  286. IBITMAP FAR *pbm;
  287. HDC hdc = NULL;
  288. HBITMAP hbmT;
  289. if (!CanLockBitmaps())
  290. return NULL;
  291. if (hbm == NULL)
  292. return NULL;
  293. h = GetSetBitmapHandle(hbm, 0);
  294. if (h == NULL)
  295. return NULL;
  296. pbm = (LPVOID)GlobalLock(h);
  297. if (IsBadReadPtr(pbm, sizeof(IBITMAP)))
  298. return NULL;
  299. //
  300. // see if it is realy a bitmap.
  301. //
  302. if (pbm->bmType != 0)
  303. return NULL;
  304. //
  305. // make sure the bmBits pointer is valid.
  306. //
  307. if (pbm->bmBits == NULL)
  308. {
  309. hdc = CreateCompatibleDC(NULL);
  310. hbmT = SelectObject(hdc, hbm);
  311. }
  312. dwSize = (DWORD)pbm->bmHeight * (DWORD)pbm->bmWidthBytes;
  313. if (IsBadHugeWritePtr((LPVOID)pbm->bmBits, dwSize))
  314. {
  315. if (hdc)
  316. {
  317. SelectObject(hdc, hbmT);
  318. DeleteDC(hdc);
  319. }
  320. return NULL;
  321. }
  322. if (p)
  323. {
  324. UINT u;
  325. hmemcpy(p, pbm, min(cb, sizeof(IBITMAP)));
  326. pbm = p;
  327. u = GetBitmapType();
  328. pbm->bmType = u & BM_TYPE;
  329. if (cb > sizeof(BITMAP))
  330. {
  331. pbm->bmBitmapInfo = 0;
  332. pbm->bmNextScan = pbm->bmWidthBytes * pbm->bmPlanes;
  333. if (u & BM_BOTTOMTOTOP)
  334. {
  335. pbm->bmOffset = 0;
  336. }
  337. else
  338. {
  339. pbm->bmOffset = (long)pbm->bmNextScan * (pbm->bmHeight-1);
  340. pbm->bmNextScan = -pbm->bmNextScan;
  341. pbm->bmFillBytes = -pbm->bmFillBytes;
  342. }
  343. //
  344. // see if this particular bitmap is HUGE
  345. //
  346. if (!(u & BM_HUGE) || (DWORD)pbm->bmHeight * pbm->bmWidthBytes < 64l*1024)
  347. {
  348. pbm->bmFillBytes = 0;
  349. pbm->bmScanSegment = pbm->bmHeight;
  350. }
  351. else
  352. {
  353. if (pbm->bmOffset)
  354. pbm->bmOffset -= (long)((pbm->bmHeight-1) / pbm->bmScanSegment) * pbm->bmFillBytes;
  355. }
  356. }
  357. }
  358. if (hdc)
  359. {
  360. SelectObject(hdc, hbmT);
  361. DeleteDC(hdc);
  362. }
  363. return (LPVOID)pbm->bmBits;
  364. }
  365. /////////////////////////////////////////////////////////////////////////////
  366. //
  367. // SetPixel
  368. //
  369. // some cards cant't seam to do SetPixel right it is amazing they work at all
  370. //
  371. /////////////////////////////////////////////////////////////////////////////
  372. static void SetPixelX(HDC hdc, int x, int y, COLORREF rgb)
  373. {
  374. RECT rc;
  375. rc.left = x;
  376. rc.top = y;
  377. rc.right = x+1;
  378. rc.bottom = y+1;
  379. SetBkColor(hdc, rgb);
  380. ExtTextOut(hdc, 0, 0, ETO_OPAQUE, &rc, NULL, 0, NULL);
  381. }
  382. #define SetPixel SetPixelX
  383. ///////////////////////////////////////////////////////////////////////////////
  384. //
  385. // GetSurfaceType
  386. //
  387. ///////////////////////////////////////////////////////////////////////////////
  388. #define BCODE _based(_segname("_CODE"))
  389. static BYTE BCODE bits8[] = {0x00,0xF9,0xFA,0xFC,0xFF};
  390. static WORD BCODE bits555[] = {0x0000,0x7C00,0x03E0,0x001F,0x7FFF};
  391. static WORD BCODE bits5551[]= {0x8000,0xFC00,0x83E0,0x801F,0xFFFF};
  392. static WORD BCODE bits565[] = {0x0000,0xF800,0x07E0,0x001F,0xFFFF};
  393. static BYTE BCODE bitsBGR[] = {0x00,0x00,0x00, 0x00,0x00,0xFF, 0x00,0xFF,0x00, 0xFF,0x00,0x00, 0xFF,0xFF,0xFF};
  394. static BYTE BCODE bitsRGB[] = {0x00,0x00,0x00, 0xFF,0x00,0x00, 0x00,0xFF,0x00, 0x00,0x00,0xFF, 0xFF,0xFF,0xFF};
  395. static DWORD BCODE bitsRGBX[]= {0x000000, 0x0000FF, 0x00FF00, 0xFF0000, 0xFFFFFF};
  396. static DWORD BCODE bitsBGRX[]= {0x000000, 0xFF0000, 0x00FF00, 0x0000FF, 0xFFFFFF};
  397. void FAR TestSurfaceType(HDC hdc, int x, int y)
  398. {
  399. PatBlt(hdc, x, y, 5, 1, BLACKNESS);
  400. SetPixel(hdc, x+0, y, RGB(000,000,000));
  401. SetPixel(hdc, x+1, y, RGB(255,000,000));
  402. SetPixel(hdc, x+2, y, RGB(000,255,000));
  403. SetPixel(hdc, x+3, y, RGB(000,000,255));
  404. SetPixel(hdc, x+4, y, RGB(255,255,255));
  405. GetPixel(hdc, x, y);
  406. }
  407. UINT FAR GetSurfaceType(LPVOID lpBits)
  408. {
  409. #define TESTFMT(a,n) \
  410. if (_fmemcmp(lpBits, (LPVOID)a, sizeof(a)) == 0) return n;
  411. TESTFMT(bits8, BM_8BIT);
  412. TESTFMT(bits555, BM_16555);
  413. TESTFMT(bits5551, BM_16555);
  414. TESTFMT(bits565, BM_16565);
  415. TESTFMT(bitsRGB, BM_24RGB);
  416. TESTFMT(bitsBGR, BM_24BGR);
  417. TESTFMT(bitsRGBX, BM_32RGB);
  418. TESTFMT(bitsBGRX, BM_32BGR);
  419. return 0;
  420. }
  421. ///////////////////////////////////////////////////////////////////////////////
  422. //
  423. // GetBitmapType
  424. //
  425. // return the bitmap type that the display driver uses
  426. //
  427. ///////////////////////////////////////////////////////////////////////////////
  428. UINT FAR GetBitmapType()
  429. {
  430. BITMAP bm;
  431. HBITMAP hbm;
  432. HBITMAP hbmT;
  433. HDC hdc;
  434. UINT u;
  435. BYTE bits[20*4*2];
  436. static UINT wBitmapType = 0xFFFF;
  437. if (wBitmapType != 0xFFFF)
  438. return wBitmapType;
  439. //
  440. // create a test bitmap (<64k)
  441. //
  442. hdc = GetDC(NULL);
  443. if (hdc == NULL) {
  444. return 0;
  445. }
  446. hbm = CreateCompatibleBitmap(hdc,20,2);
  447. ReleaseDC(NULL, hdc);
  448. if (hbm == NULL) {
  449. return 0;
  450. }
  451. hdc = CreateCompatibleDC(NULL);
  452. if (hdc == NULL) {
  453. DeleteObject(hbm);
  454. return 0;
  455. }
  456. hbmT = SelectObject(hdc, hbm);
  457. if (GetObject(hbm, sizeof(bm), &bm) == 0) {
  458. SelectObject(hdc, hbmT);
  459. DeleteObject(hbm);
  460. DeleteDC(hdc);
  461. return 0;
  462. }
  463. PatBlt(hdc, 0, 0, bm.bmWidth, bm.bmHeight, BLACKNESS);
  464. TestSurfaceType(hdc, 0, 0);
  465. GetBitmapBits(hbm, sizeof(bits), bits);
  466. u = GetSurfaceType(bits);
  467. if (u == 0) {
  468. u = GetSurfaceType(bits + bm.bmWidthBytes);
  469. if (u)
  470. u |= BM_BOTTOMTOTOP;
  471. }
  472. #ifndef _WIN32
  473. if (u) {
  474. BYTE _huge *pb;
  475. UINT dy,w;
  476. //
  477. // see if bitmap(s) are huge format
  478. //
  479. dy = (UINT)(0x10000l/bm.bmWidthBytes) + 1;
  480. hbm = CreateCompatibleBitmap(hdc,bm.bmWidth,dy);
  481. DeleteObject(SelectObject(hdc, hbm));
  482. PatBlt(hdc, 0, 0, bm.bmWidth, dy, BLACKNESS);
  483. pb = (BYTE _huge *)LockBitmap(hbm);
  484. if (pb == NULL || OFFSETOF(pb) != 0)
  485. ; // cant lock bitmaps
  486. else {
  487. u |= BM_CANLOCK;
  488. w = (dy-1) * bm.bmWidthBytes;
  489. pb[64l*1024] = 0;
  490. pb[w] = 0;
  491. if (u & BM_BOTTOMTOTOP)
  492. SetPixel(hdc, 0, 0, RGB(255,255,255));
  493. else
  494. SetPixel(hdc, 0, dy-1, RGB(255,255,255));
  495. if (pb[64l*1024] != 0 && pb[w] == 0)
  496. u |= BM_HUGE;
  497. else if (pb[64l*1024] == 0 && pb[w] != 0)
  498. ;
  499. else
  500. u = 0;
  501. }
  502. }
  503. #endif
  504. SelectObject(hdc, hbmT);
  505. DeleteObject(hbm);
  506. DeleteDC(hdc);
  507. wBitmapType = u;
  508. return u;
  509. }
  510. //////////////////////////////////////////////////////////////////////////////
  511. //
  512. // returns the PDevice of the given physical or memory DC
  513. //
  514. // return the bitmap type that the display driver uses
  515. //
  516. ///////////////////////////////////////////////////////////////////////////////
  517. LPVOID FAR GetPDevice(HDC hdc)
  518. {
  519. HANDLE h;
  520. HBITMAP hbm;
  521. HBITMAP hbmT;
  522. HDC hdcT=NULL;
  523. IBITMAP FAR *pbm;
  524. LPVOID lpPDevice = NULL;
  525. // GDI.403
  526. static HANDLE (FAR PASCAL *GdiGetBitmapHandle)(HBITMAP hbm, HANDLE h);
  527. if (GdiGetBitmapHandle == NULL)
  528. (FARPROC)GdiGetBitmapHandle = GetProcAddress(GetModuleHandle(TEXT("GDI")),(LPCSTR)MAKEINTATOM(403));
  529. if (GdiGetBitmapHandle == NULL)
  530. return NULL;
  531. hbm = CreateBitmap(1,1,1,1,NULL);
  532. //
  533. // first try the passed DC if it is a bitmap/DC
  534. //
  535. hbmT = SelectBitmap(hdc, hbm);
  536. if (hbmT != NULL)
  537. {
  538. //
  539. // it is a memory DC.
  540. //
  541. h = GdiGetBitmapHandle(hbmT, 0);
  542. }
  543. else
  544. {
  545. //
  546. // it is a physical DC.
  547. //
  548. hdcT = CreateCompatibleDC(hdc);
  549. hbmT = SelectBitmap(hdcT, hbm);
  550. h = GdiGetBitmapHandle(hbm, 0);
  551. }
  552. if (h == NULL)
  553. goto exit;
  554. pbm = (IBITMAP FAR *)GlobalLock(h);
  555. if (IsBadReadPtr(pbm, sizeof(IBITMAP)))
  556. goto exit;
  557. if (pbm)
  558. pbm = (IBITMAP FAR *)pbm->bmlpPDevice;
  559. else
  560. pbm = NULL;
  561. if (IsBadReadPtr(pbm, 2))
  562. goto exit;
  563. lpPDevice = (LPVOID)pbm;
  564. exit:
  565. if (hdcT)
  566. {
  567. SelectObject(hdcT, hbmT);
  568. DeleteObject(hdcT);
  569. }
  570. else
  571. {
  572. SelectObject(hdc, hbmT);
  573. }
  574. DeleteObject(hbm);
  575. return lpPDevice;
  576. }