TabSheet.cpp 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468
  1. // TabSheet.cpp : implementation file
  2. //
  3. #include "stdafx.h"
  4. #include "TabSheet.h"
  5. #ifdef _DEBUG
  6. #define new DEBUG_NEW
  7. #undef THIS_FILE
  8. static char THIS_FILE[] = __FILE__;
  9. #endif
  10. // constant string definitions here (or you can put it into resource string table)
  11. #define IDS_UTIL_TAB "TAB"
  12. #define IDS_UTIL_UXTHEME "UxTheme.dll"
  13. #define IDS_UTIL_THEMEACT "IsThemeActive"
  14. #define IDS_UTIL_THEMEOPN "OpenThemeData"
  15. #define IDS_UTIL_THEMEBCKG "DrawThemeBackground"
  16. /***********************************************************************************************************/
  17. /////////////////////////////////////////////////////////////////////////////
  18. // CTabSheet
  19. CTabSheet::CTabSheet()
  20. {
  21. m_nNumOfPages = 0;
  22. m_nCurrentPage = 0;
  23. m_eTabOrientation=e_tabBottom; // default initial orientation is: bottom
  24. }
  25. CTabSheet::~CTabSheet()
  26. {
  27. }
  28. BEGIN_MESSAGE_MAP(CTabSheet, CTabCtrl)
  29. //{{AFX_MSG_MAP(CTabSheet)
  30. ON_WM_LBUTTONDOWN()
  31. //}}AFX_MSG_MAP
  32. ON_WM_PAINT()
  33. END_MESSAGE_MAP()
  34. /////////////////////////////////////////////////////////////////////////////
  35. // CTabSheet message handlers
  36. BOOL CTabSheet::AddPage(LPCTSTR title, CDialog *pDialog,UINT ID)
  37. {
  38. if( MAXPAGE == m_nNumOfPages )
  39. return FALSE;
  40. m_nNumOfPages++;
  41. m_pPages[m_nNumOfPages-1] = pDialog;
  42. m_IDD[m_nNumOfPages-1] = ID;
  43. m_Title[m_nNumOfPages-1] = title;
  44. return TRUE;
  45. }
  46. void CTabSheet::SetRect()
  47. {
  48. CRect tabRect, itemRect;
  49. int nX, nY, nXc, nYc;
  50. GetClientRect(&tabRect);
  51. GetItemRect(0, &itemRect);
  52. nX=itemRect.left;
  53. nY=itemRect.bottom+1;
  54. nXc=tabRect.right-itemRect.left-2;
  55. nYc=tabRect.bottom-nY-2;
  56. m_pPages[0]->SetWindowPos(&wndTop, nX, nY, nXc, nYc, SWP_SHOWWINDOW);
  57. for( int nCount=1; nCount < m_nNumOfPages; nCount++ )
  58. m_pPages[nCount]->SetWindowPos(&wndTop, nX, nY, nXc, nYc, SWP_HIDEWINDOW);
  59. }
  60. void CTabSheet::Show()
  61. {
  62. for( int i=0; i < m_nNumOfPages; i++ )
  63. {
  64. m_pPages[i]->Create( m_IDD[i], this );
  65. InsertItem( i, m_Title[i] );
  66. }
  67. m_pPages[0]->ShowWindow(SW_SHOW);
  68. for( i=1; i < m_nNumOfPages; i++)
  69. m_pPages[i]->ShowWindow(SW_HIDE);
  70. SetRect();
  71. }
  72. void CTabSheet::OnLButtonDown(UINT nFlags, CPoint point)
  73. {
  74. CTabCtrl::OnLButtonDown(nFlags, point);
  75. if(m_nCurrentPage != GetCurFocus())
  76. {
  77. m_pPages[m_nCurrentPage]->ShowWindow(SW_HIDE);
  78. m_nCurrentPage=GetCurFocus();
  79. m_pPages[m_nCurrentPage]->ShowWindow(SW_SHOW);
  80. // m_pPages[m_nCurrentPage]->SetFocus();
  81. }
  82. }
  83. int CTabSheet::SetCurSel(int nItem)
  84. {
  85. if( nItem < 0 || nItem >= m_nNumOfPages)
  86. return -1;
  87. int ret = m_nCurrentPage;
  88. if(m_nCurrentPage != nItem )
  89. {
  90. m_pPages[m_nCurrentPage]->ShowWindow(SW_HIDE);
  91. m_nCurrentPage = nItem;
  92. m_pPages[m_nCurrentPage]->ShowWindow(SW_SHOW);
  93. // m_pPages[m_nCurrentPage]->SetFocus();
  94. CTabCtrl::SetCurSel(nItem);
  95. }
  96. return ret;
  97. }
  98. int CTabSheet::GetCurSel()
  99. {
  100. return CTabCtrl::GetCurSel();
  101. }
  102. void CTabSheet::OnPaint()
  103. {
  104. CPaintDC dc(this); // device context for painting
  105. // TODO: 在此处添加消息处理程序代码
  106. // 不为绘图消息调用 CTabCtrl::OnPaint()
  107. //AfxMessageBox("dd");
  108. CRect rcClip; rcClip.SetRectEmpty();
  109. dc.GetClipBox(rcClip);
  110. // 1st paint the tab body
  111. CRect rcPage,rcItem,rcClient;
  112. GetClientRect(&rcPage);
  113. rcClient=rcPage;
  114. AdjustRect(FALSE,rcPage);
  115. switch(m_eTabOrientation)
  116. { case e_tabTop: rcClient.top =rcPage.top -2; break;
  117. case e_tabBottom: rcClient.bottom=rcPage.bottom+3; break;
  118. case e_tabLeft: rcClient.left =rcPage.left -1; break;
  119. case e_tabRight: rcClient.right =rcPage.right +3; break;
  120. default: ASSERT(FALSE); return;
  121. }
  122. UINT uiVertBottm;
  123. uiVertBottm =(m_eTabOrientation&1)? 8:0; // 8=bottom
  124. uiVertBottm|=(m_eTabOrientation&2)?16:0; // 16=vertical
  125. UINT uiFlags=1|uiVertBottm; // 1=body
  126. DrawThemesXpTabItem(&dc, -1, rcClient,uiFlags); // TABP_PANE=9,0,'TAB'
  127. int nTab=GetItemCount(); // paint the tabs first and then the borders
  128. if(!nTab) return; // no tab pages added
  129. // 2nd paint the inactive tabs
  130. CRect ;
  131. TCHITTESTINFO hti; hti.flags=0;
  132. ::GetCursorPos(&hti.pt); ScreenToClient(&hti.pt);
  133. int ixHot=HitTest(&hti);
  134. int ixSel=GetCurSel();
  135. for(int ixTab=0; ixTab<nTab; ixTab++)
  136. { if(ixTab==ixSel)
  137. continue;
  138. VERIFY(GetItemRect(ixTab, &rcItem));
  139. if(m_eTabOrientation==e_tabLeft) rcItem.right++;
  140. uiFlags=uiVertBottm|(ixTab==ixHot?4:0); // 4= hot
  141. DrawThemesXpTabItem(&dc,ixTab,rcItem,uiFlags);
  142. }
  143. // 3rd paint the active selected tab
  144. VERIFY(GetItemRect(ixSel, &rcItem)); // now selected tab
  145. rcItem.InflateRect(2,2);
  146. if(m_eTabOrientation==e_tabTop) rcItem.bottom--;
  147. uiFlags=uiVertBottm|2; // 2= selected
  148. DrawThemesXpTabItem(&dc, ixSel, rcItem,uiFlags);
  149. }
  150. void CTabSheet::DrawThemesXpTabItem(CDC* pDC, int ixItem, const CRect& rcItem, UINT uiFlag)
  151. { // uiFlag(1/0):1=Type(body/tab);2=Sel(y/n);4=Hot(y/n);8=bBottom(y/n);16=rotate(y/n)
  152. BOOL bBody =(uiFlag& 1)?TRUE:FALSE;
  153. BOOL bSel =(uiFlag& 2)?TRUE:FALSE;
  154. BOOL bHot =(uiFlag& 4)?TRUE:FALSE;
  155. BOOL bBottom=(uiFlag& 8)?TRUE:FALSE; // mirror
  156. BOOL bVertic=(uiFlag&16)?TRUE:FALSE; // rotate
  157. BOOL bLeftTab=!bBottom && bVertic && !bBody;
  158. CSize szBmp=rcItem.Size();
  159. if(bVertic) SwapVars(szBmp.cx,szBmp.cy);
  160. // 1st draw background
  161. CDC dcMem; dcMem .CreateCompatibleDC(pDC);
  162. CBitmap bmpMem; bmpMem.CreateCompatibleBitmap(pDC,szBmp.cx,szBmp.cy);
  163. CBitmap* pBmpOld=dcMem.SelectObject(&bmpMem);
  164. CRect rcMem(CPoint(0,0),szBmp); if(bSel) rcMem.bottom++;
  165. if(bBody)
  166. DrawThemesPart(dcMem.GetSafeHdc(), 9, 0, (LPCSTR)IDS_UTIL_TAB, &rcMem); // TABP_PANE=9, 0, 'TAB'
  167. else DrawThemesPart(dcMem.GetSafeHdc(), 1, bSel?3:(bHot?2:1), (LPCSTR)IDS_UTIL_TAB, &rcMem);
  168. // TABP_TABITEM=1, TIS_SELECTED=3:TIS_HOT=2:TIS_NORMAL=1, 'TAB'
  169. // 2nd init some extra parameters
  170. BITMAPINFO biOut; ZeroMemory(&biOut,sizeof(BITMAPINFO)); // Fill local pixel arrays
  171. BITMAPINFOHEADER& bihOut=biOut.bmiHeader;
  172. bihOut.biSize =sizeof (BITMAPINFOHEADER);
  173. bihOut.biCompression=BI_RGB;
  174. bihOut.biPlanes=1; bihOut.biBitCount=24; // force as RGB: 3 bytes,24 bits -> good for rotating bitmap in any resolution
  175. bihOut.biWidth =szBmp.cx; bihOut.biHeight=szBmp.cy;
  176. int nBmpWdtPS=DWordAlign(szBmp.cx*3);
  177. int nSzBuffPS=((nBmpWdtPS*szBmp.cy)/8+2)*8;
  178. LPBYTE pcImg=NULL;
  179. if(bBottom || bVertic) { pcImg=new BYTE[nSzBuffPS]; ASSERT(pcImg); }
  180. int nStart=0,nLenSub=0;
  181. if(bBody && bBottom && !bVertic) nStart=3,nLenSub=4; // if bottom oriented flip the body contest only (no shadows were flipped)
  182. // 3rd if it is left oriented tab, draw tab context before mirroring or rotating (before GetDIBits)
  183. if(bVertic)
  184. { if(bBody || !bBottom) bihOut.biHeight=-szBmp.cy;
  185. if(!bBottom && !bBody && ixItem>=0) //
  186. { if(bSel) rcMem.bottom--;
  187. DrawTabItem(&dcMem, ixItem, rcMem, uiFlag); ixItem=-1;
  188. } } // rotate or mirror
  189. // 4th get bits (for rotate) and mirror: body=(all except top) tab=(all except top)
  190. if(bVertic || bBottom) // get bits:
  191. { GetDIBits(*pDC, bmpMem.operator HBITMAP(),nStart,szBmp.cy-nLenSub,pcImg,&biOut,DIB_RGB_COLORS);
  192. if(bBottom) // mirror: body=(bottom and right) tab=(bottom and right)
  193. { bihOut.biHeight=-szBmp.cy; // to mirror bitmap is eough to use negative height between Get/SetDIBits
  194. SetDIBits(*pDC, bmpMem.operator HBITMAP(),nStart,szBmp.cy-nLenSub,pcImg,&biOut,DIB_RGB_COLORS);
  195. if(bBody && bVertic) // when it is right oriented body -> flip twice, first flip border shadows, than flip shaded inside body again
  196. { nStart=2; nLenSub=4; bihOut.biHeight=szBmp.cy;
  197. GetDIBits(*pDC, bmpMem.operator HBITMAP(),nStart,szBmp.cy-nLenSub,pcImg,&biOut,DIB_RGB_COLORS);
  198. bihOut.biHeight=-szBmp.cy; // to mirror bitmap is eough to use negative height between Get/SetDIBits
  199. SetDIBits(*pDC, bmpMem.operator HBITMAP(),nStart,szBmp.cy-nLenSub,pcImg,&biOut,DIB_RGB_COLORS);
  200. } } }
  201. // 5th if it is bottom or right oriented tab, draw after mirroring background (do GetDIBits again)
  202. if(!bBody && ixItem>=0) //
  203. { if(bSel) rcMem.bottom--;
  204. DrawTabItem(&dcMem, ixItem, rcMem, uiFlag);
  205. if(bVertic) // if it is right tab, do GetDIBits again
  206. { bihOut.biHeight=-szBmp.cy;
  207. GetDIBits(*pDC, bmpMem.operator HBITMAP(),nStart,szBmp.cy-nLenSub,pcImg,&biOut,DIB_RGB_COLORS);
  208. } }
  209. // 6th: do rotate now, finaly
  210. if(bVertic) // force rotating bitmap as RGB -> good for any resolution
  211. { SwapVars(szBmp.cx,szBmp.cy);
  212. int nBmpWdtPD=DWordAlign(szBmp.cx*3);
  213. int nPadD=nBmpWdtPD-szBmp.cx*3;
  214. int nSzBuffPD=((nBmpWdtPD*szBmp.cy)/8+2)*8;
  215. LPBYTE pcImgRotate=new BYTE[nSzBuffPD]; ASSERT(pcImgRotate);
  216. int nWidth,nHeight=szBmp.cy,nHeight1=nHeight-1;
  217. //====================================
  218. //------------------------------------
  219. // here is the example how to speed up lengthy repeatetive processing by using inline assembler
  220. #define __USE_MASM__ // the same processing is in C and in asm. To use C -> comment the beginning of this line
  221. // Do the actual whole RGB bitmap rotating in C or assembler
  222. #ifndef __USE_MASM__
  223. LPBYTE pcImgS=pcImg;
  224. LPBYTE pcImgD=pcImgRotate;
  225. int ixHeight=0;
  226. BOOL bLast=FALSE;
  227. while(ixHeight<nHeight) // for all destination height lines
  228. { nWidth=szBmp.cx;
  229. if(ixHeight==nHeight1) { bLast=TRUE; nWidth--; }
  230. while(nWidth--)
  231. { *(PDWORD)pcImgD=*(PDWORD)pcImgS; // do all Rgb triplets read/write qicker as DWORD
  232. pcImgS+=nBmpWdtPS; // increment source in padded source lines
  233. pcImgD+=3; // increment destination in rgb triplets
  234. }
  235. if(bLast) // when the last line, the last pixel - colud be a problem if bitmap DWORD alligned
  236. for(int c=3;c;c--) *pcImgD++=*pcImgS++; // (only last three bytes available->could not read/write DWORD)!!
  237. else
  238. { ixHeight++;
  239. pcImgD+=nPadD; // destination bitmap horizontal padding to DWORD
  240. pcImgS=pcImg+(ixHeight*3); // reset the source to the begining of the next vertical line
  241. } }
  242. #else // __USE_MASM__
  243. nBmpWdtPS-=4; // adjust esi increment (due to esi self-incrementing by movsd)
  244. nWidth=szBmp.cx;
  245. __asm
  246. { mov esi, pcImg // source index
  247. mov edi, pcImgRotate // destination index
  248. xor ebx, ebx // vertical counter
  249. loop_height:
  250. mov ecx, nWidth // horizontal counter
  251. cmp ebx, nHeight1 // check is it the last line
  252. jne loop_width
  253. dec ecx // if it is decremnt for the last pixel
  254. loop_width:
  255. movsd // copies 4 bytes and increments source and destination by 4 (we need only 3 bytes copied 'one pixel' RGB triplet)
  256. dec edi // adjust edi to 'as incremented by 3'
  257. add esi,nBmpWdtPS // adjust esi to the next source line
  258. loop loop_width // loop one hotizontal destination line
  259. cmp ebx, nHeight1 // check is it the last line
  260. je do_last // if not last, do incrementing here
  261. inc ebx // increment vertical counter
  262. add edi, nPadD // adjust destination index by possible padding to DWORD
  263. mov esi, ebx // reset the source index: add vertical counter * 3
  264. shl esi, 1 // (is the same as * 2 +1*)
  265. add esi, ebx // +1*
  266. add esi, pcImg // add to the beginning of the source
  267. jmp loop_height // loop whole height
  268. do_last: // the last pixel is done by
  269. movsw // moving first two bytes
  270. movsb // and than by moving the very last byte
  271. }
  272. #endif // __USE_MASM__
  273. dcMem.SelectObject(pBmpOld); bmpMem.DeleteObject(); // recreate rotated bitmap
  274. bmpMem.CreateCompatibleBitmap(pDC,szBmp.cx,szBmp.cy);
  275. dcMem.SelectObject(&bmpMem);
  276. bihOut.biWidth =szBmp.cx; bihOut.biHeight=bBody?-szBmp.cy:szBmp.cy;
  277. SetDIBits(*pDC, bmpMem.operator HBITMAP(),0,szBmp.cy,pcImgRotate,&biOut,DIB_RGB_COLORS); // set rotated bitmap bits
  278. delete pcImgRotate;
  279. }
  280. if(pcImg) delete pcImg;
  281. // 6th blit mirrored/rotated image to the screen
  282. pDC->BitBlt(rcItem.left,rcItem.top,szBmp.cx,szBmp.cy,&dcMem,0,0,SRCCOPY); //
  283. dcMem.SelectObject(pBmpOld);
  284. CRect rc(100,0,1050,50);//85
  285. //pDC->FillSolidRect(rc, g_Color);
  286. }
  287. //----------------------------------------------------------------------------------------------------------
  288. // draw tab item context: possible icon and text
  289. void CTabSheet::DrawTabItem(CDC* pDC, int ixItem, const CRect& rcItemC, UINT uiFlags)
  290. {
  291. TC_ITEM tci; CString sText;
  292. tci.mask =TCIF_TEXT | TCIF_IMAGE;
  293. tci.pszText =sText.GetBuffer(128);
  294. tci.cchTextMax=127;
  295. GetItem(ixItem,&tci);
  296. sText.ReleaseBuffer();
  297. BOOL bSel =(uiFlags&2)?TRUE:FALSE;
  298. BOOL bBottom=(uiFlags&8)?TRUE:FALSE;
  299. CRect rcItem=rcItemC;
  300. if(bSel) rcItem.bottom -= 1;
  301. else rcItem.bottom += 2;
  302. rcItem.left+=(bBottom?3:6); // text & icon
  303. rcItem.top +=(bBottom?3:2) + (bSel ? 1 : (bBottom?0:3));
  304. int nOldMode=pDC->SetBkMode(TRANSPARENT);
  305. HIMAGELIST hilTabs = (HIMAGELIST)TabCtrl_GetImageList(GetSafeHwnd()); // icon
  306. if(hilTabs && tci.iImage>=0)
  307. { ImageList_Draw(hilTabs, tci.iImage, *pDC, rcItem.left+(bSel?2:0), rcItem.top+(bSel?0:-2), ILD_TRANSPARENT);
  308. rcItem.left+=19;
  309. }
  310. else rcItem.OffsetRect(-2,0);
  311. if(sText.GetLength())
  312. { CFont* pOldFont=pDC->SelectObject(GetFont()); // prepare dc
  313. rcItem.right-=3; // text
  314. CRect rect(0,0,rcItem.Width(),20);
  315. ::DrawText(pDC->GetSafeHdc(),sText.GetBuffer(sText.GetLength()+4),-1,rect,DT_CALCRECT|DT_SINGLELINE|DT_MODIFYSTRING|DT_END_ELLIPSIS);
  316. sText.ReleaseBuffer();
  317. rcItem.OffsetRect((bBottom?-1:0),(bSel?1:-1));
  318. pDC->DrawText(sText, rcItem, DT_NOPREFIX|DT_CENTER);
  319. pDC->SelectObject(pOldFont);
  320. }
  321. pDC->SetBkMode(nOldMode);
  322. }
  323. //----------------------------------------------------------------------------------------------------------
  324. //BOOL CXPTabCtrl::IsExtendedTabTheamedXP()
  325. //{
  326. // if(!m_bTabExtended || !::IsWindow(GetSafeHwnd()))
  327. // return FALSE;
  328. // DWORD dwStyle=GetStyle();
  329. // m_eTabOrientation=(dwStyle&TCS_BOTTOM)?e_tabBottom:e_tabTop;
  330. // if(dwStyle&TCS_VERTICAL)
  331. // m_eTabOrientation=(m_eTabOrientation==e_tabTop)?e_tabLeft:e_tabRight;
  332. //#ifdef USE_DEFAULT_XP_TOPTAB
  333. // if(m_eTabOrientation==e_tabTop) return FALSE;
  334. //#endif
  335. // return IsThemeActiveXP()?TRUE:FALSE;
  336. //}
  337. //==========================================================================================================
  338. //// these two messages are necessary only to properly redraw deselected tab background, because
  339. //void CTabSheet::OnTabSelChanging(NMHDR* pNMHDR, LRESULT* pResult) // selected rect was inflated by 2 points
  340. //{
  341. // UNUSED_ALWAYS(pNMHDR);
  342. // m_ixSelOld=GetCurSel();
  343. // *pResult=0L;
  344. //}
  345. //----------------------------------------------------------------------------------------------------------
  346. //void CTabSheet::OnTabSelChanged(NMHDR* pNMHDR, LRESULT* pResult)
  347. //{
  348. // UNUSED_ALWAYS(pNMHDR);
  349. // if(m_ixSelOld>=0 && m_ixSelOld!=GetCurSel() && IsExtendedTabTheamedXP()) // else
  350. // { CWnd* pWndParent=GetParent();
  351. // m_iNowSel = GetCurSel();
  352. // if(pWndParent)
  353. // { CRect rcOldSel; GetItemRect(m_ixSelOld, rcOldSel); rcOldSel.InflateRect(2,2);
  354. // ClientToScreen(&rcOldSel); pWndParent->ScreenToClient(&rcOldSel);
  355. // pWndParent->InvalidateRect(rcOldSel);
  356. // } }
  357. // *pResult=1L;
  358. //}
  359. /***********************************************************************************************************/
  360. // Helper functions
  361. /***********************************************************************************************************/
  362. int DWordAlign(int n)
  363. { const int rem=n%4; if(rem) n+=(4-rem); return n; }
  364. //----------------------------------------------------------------------------------------------------------
  365. BOOL IsThemeActiveEx()
  366. { // check theme activity always (could change during application running)
  367. HINSTANCE hDll=LoadLibrary(CString((LPCTSTR)IDS_UTIL_UXTHEME)); // 'UxTheme.dll'
  368. if(hDll==NULL) return FALSE; // the DLL won't be available on anything except Windows XP
  369. UINT (PASCAL *pfnIsThemeActive)();
  370. (FARPROC&)pfnIsThemeActive=GetProcAddress(hDll,CString((LPCTSTR)IDS_UTIL_THEMEACT)); // 'IsThemeActive'
  371. UINT uiThemeActive=0;
  372. if(pfnIsThemeActive)
  373. uiThemeActive=pfnIsThemeActive();
  374. FreeLibrary(hDll);
  375. return uiThemeActive?TRUE:FALSE;
  376. }
  377. //----------------------------------------------------------------------------------------------------------
  378. #define PACKVERSION(major,minor) MAKELONG(minor,major)
  379. DWORD GetWinVersion()
  380. {
  381. static DWORD c_dwWinVers=0; // check win version only once (will not change during application)
  382. if(!c_dwWinVers)
  383. { OSVERSIONINFO osvi; ZeroMemory(&osvi, sizeof(OSVERSIONINFO)); // Initialize the OSVERSIONINFO structure.
  384. osvi.dwOSVersionInfoSize = sizeof(OSVERSIONINFO);
  385. GetVersionEx(&osvi);
  386. c_dwWinVers=PACKVERSION(osvi.dwMajorVersion,osvi.dwMinorVersion);
  387. }
  388. return c_dwWinVers;
  389. }
  390. //----------------------------------------------------------------------------------------------------------
  391. BOOL IsWinXP() { return GetWinVersion()>=PACKVERSION(5,1)?TRUE:FALSE; }
  392. //----------------------------------------------------------------------------------------------------------
  393. BOOL IsThemeActiveXP() { return (IsWinXP() && IsThemeActiveEx())?TRUE:FALSE; }
  394. //----------------------------------------------------------------------------------------------------------
  395. #define WPART_NAME_SZ 128
  396. HRESULT DrawThemesPart(HDC hDC, int iPartId, int iStateId, LPCSTR uiPartNameID, LPRECT prcBox)
  397. {
  398. if(!IsWinXP()) return E_FAIL;
  399. HINSTANCE hDll=LoadLibrary(CString((LPCTSTR)IDS_UTIL_UXTHEME)); // 'UxTheme.dll'
  400. if(!hDll) return E_FAIL;
  401. BOOL (PASCAL* pfnIsThemeActive)(); UINT hTheme=0;
  402. (FARPROC&)pfnIsThemeActive=GetProcAddress(hDll,CString((LPCTSTR)IDS_UTIL_THEMEACT)); // 'IsThemeActive'
  403. HRESULT hResult=E_FAIL;
  404. if(pfnIsThemeActive && pfnIsThemeActive())
  405. { CString sPartName((LPCTSTR)uiPartNameID);
  406. if(sPartName.GetLength()>0)
  407. { WCHAR swPartName[WPART_NAME_SZ];
  408. MultiByteToWideChar(CP_ACP,0,(LPCSTR)sPartName,-1,swPartName,sizeof(swPartName)/sizeof(WCHAR));
  409. UINT (PASCAL* pfnOpenThemeData)(HWND hwnd, LPCWSTR pszClassList);
  410. (FARPROC&)pfnOpenThemeData=GetProcAddress(hDll,CString((LPCTSTR)IDS_UTIL_THEMEOPN));// 'OpenThemeData'
  411. if(pfnOpenThemeData && (hTheme=pfnOpenThemeData(NULL, swPartName))!=0)
  412. { UINT (PASCAL* pfnDrawThemeBackground)(UINT htheme,HDC hdc,int iPartID,int iStateID,const RECT* prcBx,const RECT* prcClip);
  413. (FARPROC&)pfnDrawThemeBackground=GetProcAddress(hDll,CString((LPCTSTR)IDS_UTIL_THEMEBCKG)); // 'DrawThemeBackground'
  414. if(pfnDrawThemeBackground)
  415. hResult=pfnDrawThemeBackground(hTheme, hDC, iPartId, iStateId, prcBox, NULL);
  416. } } }
  417. FreeLibrary(hDll);
  418. return hResult;
  419. }