Browse Source

使用线程通讯来处理管道返回的数据信息。

JeffWang 3 years ago
parent
commit
e7acd5a0b4

+ 3095 - 0
Source/OGCAssistTool/OGCAssistTool/BCMenu.cpp

@@ -0,0 +1,3095 @@
+//*************************************************************************
+// BCMenu.cpp : implementation file
+// Version : 3.02
+// Date : March 2002
+// Author : Brent Corkum
+// Email :  corkum@rocscience.com
+// Latest Version : http://www.rocscience.com/~corkum/BCMenu.html
+// 
+// Bug Fixes and portions of code supplied by:
+//
+// Ben Ashley,Girish Bharadwaj,Jean-Edouard Lachand-Robert,
+// Robert Edward Caldecott,Kenny Goers,Leonardo Zide,
+// Stefan Kuhr,Reiner Jung,Martin Vladic,Kim Yoo Chul,
+// Oz Solomonovich,Tongzhe Cui,Stephane Clog,Warren Stevens,
+// Damir Valiulin,David Kinder,Marc Loiry
+//
+// You are free to use/modify this code but leave this header intact.
+// This class is public domain so you are free to use it any of
+// your applications (Freeware,Shareware,Commercial). All I ask is
+// that you let me know so that if you have a real winner I can
+// brag to my buddies that some of my code is in your app. I also
+// wouldn't mind if you sent me a copy of your application since I
+// like to play with new stuff.
+//*************************************************************************
+
+#include "stdafx.h"        // Standard windows header file
+#include "BCMenu.h"        // BCMenu class declaration
+#include <afxpriv.h>       //SK: makes A2W and other spiffy AFX macros work
+
+#ifdef _DEBUG
+#define new DEBUG_NEW
+#undef THIS_FILE
+static char THIS_FILE[] = __FILE__;
+#endif
+
+#define BCMENU_GAP 1
+#ifndef OBM_CHECK
+#define OBM_CHECK 32760 // from winuser.h
+#endif
+
+#if _MFC_VER <0x400
+#error This code does not work on Versions of MFC prior to 4.0
+#endif
+
+static CPINFO CPInfo;
+// how the menu's are drawn in win9x/NT/2000
+UINT BCMenu::original_drawmode=BCMENU_DRAWMODE_ORIGINAL;
+BOOL BCMenu::original_select_disabled=TRUE;
+// how the menu's are drawn in winXP
+UINT BCMenu::xp_drawmode=BCMENU_DRAWMODE_XP;
+BOOL BCMenu::xp_select_disabled=FALSE;
+BOOL BCMenu::xp_draw_3D_bitmaps=TRUE;
+
+CImageList BCMenu::m_AllImages;
+CArray<int,int&> BCMenu::m_AllImagesID;
+
+enum Win32Type{
+	Win32s,
+	WinNT3,
+	Win95,
+	Win98,
+	WinME,
+	WinNT4,
+	Win2000,
+	WinXP
+};
+
+
+Win32Type IsShellType()
+{
+	Win32Type  ShellType;
+	DWORD winVer;
+	OSVERSIONINFO *osvi;
+	
+	winVer=GetVersion();
+	if(winVer<0x80000000){/*NT */
+		ShellType=WinNT3;
+		osvi= (OSVERSIONINFO *)malloc(sizeof(OSVERSIONINFO));
+		if (osvi!=NULL){
+			memset(osvi,0,sizeof(OSVERSIONINFO));
+			osvi->dwOSVersionInfoSize=sizeof(OSVERSIONINFO);
+			GetVersionEx(osvi);
+			if(osvi->dwMajorVersion==4L)ShellType=WinNT4;
+			else if(osvi->dwMajorVersion==5L&&osvi->dwMinorVersion==0L)ShellType=Win2000;
+			else if(osvi->dwMajorVersion==5L&&osvi->dwMinorVersion==1L)ShellType=WinXP;
+			free(osvi);
+		}
+	}
+	else if  (LOBYTE(LOWORD(winVer))<4)
+		ShellType=Win32s;
+	else{
+		ShellType=Win95;
+		osvi= (OSVERSIONINFO *)malloc(sizeof(OSVERSIONINFO));
+		if (osvi!=NULL){
+			memset(osvi,0,sizeof(OSVERSIONINFO));
+			osvi->dwOSVersionInfoSize=sizeof(OSVERSIONINFO);
+			GetVersionEx(osvi);
+			if(osvi->dwMajorVersion==4L&&osvi->dwMinorVersion==10L)ShellType=Win98;
+			else if(osvi->dwMajorVersion==4L&&osvi->dwMinorVersion==90L)ShellType=WinME;
+			free(osvi);
+		}
+	}
+	return ShellType;
+}
+
+static Win32Type g_Shell=IsShellType();
+
+void BCMenuData::SetAnsiString(LPCSTR szAnsiString)
+{
+	USES_CONVERSION;
+	SetWideString(A2W(szAnsiString));  //SK:  see MFC Tech Note 059
+}
+
+CString BCMenuData::GetString(void)//returns the menu text in ANSI or UNICODE
+//depending on the MFC-Version we are using
+{
+	CString strText;
+	if (m_szMenuText)
+    {
+#ifdef UNICODE
+		strText = m_szMenuText;
+#else
+		USES_CONVERSION;
+		strText=W2A(m_szMenuText);     //SK:  see MFC Tech Note 059
+#endif    
+    }
+	return strText;
+}
+
+CTypedPtrArray<CPtrArray, HMENU> BCMenu::m_AllSubMenus;  // Stores list of all sub-menus
+
+IMPLEMENT_DYNAMIC( BCMenu, CMenu )
+
+/*
+===============================================================================
+BCMenu::BCMenu()
+BCMenu::~BCMenu()
+-----------------
+
+Constructor and Destructor.
+
+===============================================================================
+*/
+
+BCMenu::BCMenu()
+{
+	m_bDynIcons = FALSE;     // O.S. - no dynamic icons by default
+	disable_old_style=FALSE;
+	m_iconX = 16;            // Icon sizes default to 16 x 16
+	m_iconY = 15;            // ...
+	m_selectcheck = -1;
+	m_unselectcheck = -1;
+	checkmaps=NULL;
+	checkmapsshare=FALSE;
+	// set the color used for the transparent background in all bitmaps
+	m_bitmapBackground=RGB(192,192,192); //gray
+	m_bitmapBackgroundFlag=FALSE;
+	GetCPInfo(CP_ACP,&CPInfo);
+	m_loadmenu=FALSE;
+}
+
+
+BCMenu::~BCMenu()
+{
+	DestroyMenu();
+}
+
+BOOL BCMenu::IsNewShell ()
+{
+	return (g_Shell>=Win95);
+}
+
+BOOL BCMenu::IsWinXPLuna()
+{
+	if(g_Shell==WinXP){
+		if(IsWindowsClassicTheme())return(FALSE);
+		else return(TRUE);
+	}
+	return(FALSE);
+}
+
+BOOL BCMenu::IsLunaMenuStyle()
+{
+	if(IsWinXPLuna()){
+		if(xp_drawmode==BCMENU_DRAWMODE_XP)return(TRUE);
+	}
+	else{
+		if(original_drawmode==BCMENU_DRAWMODE_XP)return(TRUE);
+	}
+	return(FALSE);
+}
+
+BCMenuData::~BCMenuData()
+{
+	if(bitmap)
+		delete(bitmap);
+	
+	delete[] m_szMenuText; //Need not check for NULL because ANSI X3J16 allows "delete NULL"
+}
+
+
+void BCMenuData::SetWideString(const wchar_t *szWideString)
+{
+	delete[] m_szMenuText;//Need not check for NULL because ANSI X3J16 allows "delete NULL"
+	
+	if (szWideString)
+    {
+		m_szMenuText = new wchar_t[sizeof(wchar_t)*(wcslen(szWideString)+1)];
+		if (m_szMenuText)
+			wcscpy(m_szMenuText,szWideString);
+    }
+	else
+		m_szMenuText=NULL;//set to NULL so we need not bother about dangling non-NULL Ptrs
+}
+
+BOOL BCMenu::IsMenu(CMenu *submenu)
+{
+	int m;
+	int numSubMenus = m_AllSubMenus.GetUpperBound();
+	for(m=0;m<=numSubMenus;++m){
+		if(submenu->m_hMenu==m_AllSubMenus[m])return(TRUE);
+	}
+	return(FALSE);
+}
+
+BOOL BCMenu::IsMenu(HMENU submenu)
+{
+	int m;
+	int numSubMenus = m_AllSubMenus.GetUpperBound();
+	for(m=0;m<=numSubMenus;++m){
+		if(submenu==m_AllSubMenus[m])return(TRUE);
+	}
+	return(FALSE);
+}
+
+BOOL BCMenu::DestroyMenu()
+{
+	// Destroy Sub menus:
+	int m,n;
+	int numAllSubMenus = m_AllSubMenus.GetUpperBound();
+	for(n = numAllSubMenus; n>= 0; n--){
+		if(m_AllSubMenus[n]==this->m_hMenu)m_AllSubMenus.RemoveAt(n);
+	}
+	int numSubMenus = m_SubMenus.GetUpperBound();
+	for(m = numSubMenus; m >= 0; m--){
+		numAllSubMenus = m_AllSubMenus.GetUpperBound();
+		for(n = numAllSubMenus; n>= 0; n--){
+			if(m_AllSubMenus[n]==m_SubMenus[m])m_AllSubMenus.RemoveAt(n);
+		}
+		CMenu *ptr=FromHandle(m_SubMenus[m]);
+		BOOL flag=ptr->IsKindOf(RUNTIME_CLASS( BCMenu ));
+		if(flag)delete((BCMenu *)ptr);
+	}
+	m_SubMenus.RemoveAll();
+	// Destroy menu data
+	int numItems = m_MenuList.GetUpperBound();
+	for(m = 0; m <= numItems; m++)delete(m_MenuList[m]);
+	m_MenuList.RemoveAll();
+	if(checkmaps&&!checkmapsshare){
+		delete checkmaps;
+		checkmaps=NULL;
+	}
+	// Call base-class implementation last:
+	return(CMenu::DestroyMenu());
+};
+
+int BCMenu::GetMenuDrawMode(void)
+{
+	if(IsWinXPLuna())return(xp_drawmode);
+	return(original_drawmode);
+}
+
+BOOL BCMenu::GetSelectDisableMode(void)
+{
+	if(IsLunaMenuStyle())return(xp_select_disabled);
+	return(original_select_disabled);
+}
+
+
+/*
+==========================================================================
+void BCMenu::DrawItem(LPDRAWITEMSTRUCT)
+---------------------------------------
+
+  Called by the framework when a particular item needs to be drawn.  We
+  overide this to draw the menu item in a custom-fashion, including icons
+  and the 3D rectangle bar.
+  ==========================================================================
+*/
+
+void BCMenu::DrawItem (LPDRAWITEMSTRUCT lpDIS)
+{
+	ASSERT(lpDIS != NULL);
+	CDC* pDC = CDC::FromHandle(lpDIS->hDC);
+	if(pDC->GetDeviceCaps(RASTERCAPS) & RC_PALETTE)DrawItem_Win9xNT2000(lpDIS);
+	else{
+		if(IsWinXPLuna()){
+			if(xp_drawmode==BCMENU_DRAWMODE_XP) DrawItem_WinXP(lpDIS);
+			else DrawItem_Win9xNT2000(lpDIS);
+		}
+		else{
+			if(original_drawmode==BCMENU_DRAWMODE_XP) DrawItem_WinXP(lpDIS);
+			else DrawItem_Win9xNT2000(lpDIS);
+		}	
+	}
+}
+
+void BCMenu::DrawItem_Win9xNT2000 (LPDRAWITEMSTRUCT lpDIS)
+{
+	ASSERT(lpDIS != NULL);
+	CDC* pDC = CDC::FromHandle(lpDIS->hDC);
+	CRect rect;
+	UINT state = (((BCMenuData*)(lpDIS->itemData))->nFlags);
+	CBrush m_brBackground;
+	COLORREF m_clrBack;
+
+	if(IsWinXPLuna())m_clrBack=GetSysColor(COLOR_3DFACE);
+	else m_clrBack=GetSysColor(COLOR_MENU);
+	
+	m_brBackground.CreateSolidBrush(m_clrBack);
+
+	// remove the selected bit if it's grayed out
+	if(lpDIS->itemState & ODS_GRAYED&&!original_select_disabled){
+		if(lpDIS->itemState & ODS_SELECTED)lpDIS->itemState=lpDIS->itemState & ~ODS_SELECTED;
+	}
+	
+	if(state & MF_SEPARATOR){
+		rect.CopyRect(&lpDIS->rcItem);
+		pDC->FillRect (rect,&m_brBackground);
+		rect.top += (rect.Height()>>1);
+		pDC->DrawEdge(&rect,EDGE_ETCHED,BF_TOP);
+	}
+	else{
+		CRect rect2;
+		BOOL standardflag=FALSE,selectedflag=FALSE,disableflag=FALSE;
+		BOOL checkflag=FALSE;
+		COLORREF crText = GetSysColor(COLOR_MENUTEXT);
+		CBrush m_brSelect;
+		CPen m_penBack;
+		int x0,y0,dy;
+		int nIconNormal=-1,xoffset=-1,global_offset=-1;
+		CImageList *bitmap=NULL;
+		
+		// set some colors
+		m_penBack.CreatePen (PS_SOLID,0,m_clrBack);
+		m_brSelect.CreateSolidBrush(GetSysColor(COLOR_HIGHLIGHT));
+		
+		// draw the colored rectangle portion
+		
+		rect.CopyRect(&lpDIS->rcItem);
+		rect2=rect;
+		
+		// draw the up/down/focused/disabled state
+		
+		UINT state = lpDIS->itemState;
+		CString strText;
+		
+		if(lpDIS->itemData != NULL){
+			nIconNormal = (((BCMenuData*)(lpDIS->itemData))->menuIconNormal);
+			xoffset = (((BCMenuData*)(lpDIS->itemData))->xoffset);
+			global_offset = (((BCMenuData*)(lpDIS->itemData))->global_offset);
+			bitmap = (((BCMenuData*)(lpDIS->itemData))->bitmap);
+			strText = ((BCMenuData*) (lpDIS->itemData))->GetString();
+
+			if(nIconNormal<0&&global_offset>=0){
+				xoffset=global_offset;
+				nIconNormal=0;
+				bitmap = &m_AllImages;
+			}
+			
+			if(state&ODS_CHECKED && nIconNormal<0){
+				if(state&ODS_SELECTED && m_selectcheck>0)checkflag=TRUE;
+				else if(m_unselectcheck>0) checkflag=TRUE;
+			}
+			else if(nIconNormal != -1){
+				standardflag=TRUE;
+				if(state&ODS_SELECTED && !(state&ODS_GRAYED))selectedflag=TRUE;
+				else if(state&ODS_GRAYED) disableflag=TRUE;
+			}
+		}
+		else{
+			strText.Empty();
+		}
+		
+		if(state&ODS_SELECTED){ // draw the down edges
+			
+			CPen *pOldPen = pDC->SelectObject (&m_penBack);
+			
+			// You need only Text highlight and thats what you get
+			
+			if(checkflag||standardflag||selectedflag||disableflag||state&ODS_CHECKED)
+				rect2.SetRect(rect.left+m_iconX+4+BCMENU_GAP,rect.top,rect.right,rect.bottom);
+			pDC->FillRect (rect2,&m_brSelect);
+			
+			pDC->SelectObject (pOldPen);
+			crText = GetSysColor(COLOR_HIGHLIGHTTEXT);
+		}
+		else {
+			CPen *pOldPen = pDC->SelectObject (&m_penBack);
+			pDC->FillRect (rect,&m_brBackground);
+			pDC->SelectObject (pOldPen);
+			
+			// draw the up edges	
+			pDC->Draw3dRect (rect,m_clrBack,m_clrBack);
+		}
+		
+		// draw the text if there is any
+		//We have to paint the text only if the image is nonexistant
+		
+		dy = (rect.Height()-4-m_iconY)/2;
+		dy = dy<0 ? 0 : dy;
+		
+		if(checkflag||standardflag||selectedflag||disableflag){
+			rect2.SetRect(rect.left+1,rect.top+1+dy,rect.left+m_iconX+3,
+				rect.top+m_iconY+3+dy);
+			pDC->Draw3dRect (rect2,m_clrBack,m_clrBack);
+			if(checkflag && checkmaps){
+				pDC->FillRect (rect2,&m_brBackground);
+				rect2.SetRect(rect.left,rect.top+dy,rect.left+m_iconX+4,
+					rect.top+m_iconY+4+dy);
+				
+				pDC->Draw3dRect (rect2,m_clrBack,m_clrBack);
+				CPoint ptImage(rect.left+2,rect.top+2+dy);
+				
+				if(state&ODS_SELECTED)checkmaps->Draw(pDC,1,ptImage,ILD_TRANSPARENT);
+				else checkmaps->Draw(pDC,0,ptImage,ILD_TRANSPARENT);
+			}
+			else if(disableflag){
+				if(!selectedflag){
+					CBitmap bitmapstandard;
+					GetBitmapFromImageList(pDC,bitmap,xoffset,bitmapstandard);
+					rect2.SetRect(rect.left,rect.top+dy,rect.left+m_iconX+4,
+                        rect.top+m_iconY+4+dy);
+					pDC->Draw3dRect (rect2,m_clrBack,m_clrBack);
+					if(disable_old_style)
+						DitherBlt(lpDIS->hDC,rect.left+2,rect.top+2+dy,m_iconX,m_iconY,
+						(HBITMAP)(bitmapstandard),0,0,m_clrBack);
+					else
+						DitherBlt2(pDC,rect.left+2,rect.top+2+dy,m_iconX,m_iconY,
+						bitmapstandard,0,0,m_clrBack);
+					bitmapstandard.DeleteObject();
+				}
+			}
+			else if(selectedflag){
+				pDC->FillRect (rect2,&m_brBackground);
+				rect2.SetRect(rect.left,rect.top+dy,rect.left+m_iconX+4,
+					rect.top+m_iconY+4+dy);
+				if (IsNewShell()){
+					if(state&ODS_CHECKED)
+						pDC->Draw3dRect(rect2,GetSysColor(COLOR_3DSHADOW),
+						GetSysColor(COLOR_3DHILIGHT));
+					else
+						pDC->Draw3dRect(rect2,GetSysColor(COLOR_3DHILIGHT),
+						GetSysColor(COLOR_3DSHADOW));
+				}
+				CPoint ptImage(rect.left+2,rect.top+2+dy);
+				if(bitmap)bitmap->Draw(pDC,xoffset,ptImage,ILD_TRANSPARENT);
+			}
+			else{
+				if(state&ODS_CHECKED){
+					CBrush brush;
+					COLORREF col = m_clrBack;
+					col = LightenColor(col,0.6);
+					brush.CreateSolidBrush(col);
+					pDC->FillRect(rect2,&brush);
+					brush.DeleteObject();
+					rect2.SetRect(rect.left,rect.top+dy,rect.left+m_iconX+4,
+                        rect.top+m_iconY+4+dy);
+					if (IsNewShell())
+						pDC->Draw3dRect(rect2,GetSysColor(COLOR_3DSHADOW),
+						GetSysColor(COLOR_3DHILIGHT));
+				}
+				else{
+					pDC->FillRect (rect2,&m_brBackground);
+					rect2.SetRect(rect.left,rect.top+dy,rect.left+m_iconX+4,
+                        rect.top+m_iconY+4+dy);
+					pDC->Draw3dRect (rect2,m_clrBack,m_clrBack);
+				}
+				CPoint ptImage(rect.left+2,rect.top+2+dy);
+				if(bitmap)bitmap->Draw(pDC,xoffset,ptImage,ILD_TRANSPARENT);
+			}
+		}
+		if(nIconNormal<0 && state&ODS_CHECKED && !checkflag){
+			rect2.SetRect(rect.left+1,rect.top+2+dy,rect.left+m_iconX+1,
+				rect.top+m_iconY+2+dy);
+			CMenuItemInfo info;
+			info.fMask = MIIM_CHECKMARKS;
+			::GetMenuItemInfo((HMENU)lpDIS->hwndItem,lpDIS->itemID,
+				MF_BYCOMMAND, &info);
+			if(state&ODS_CHECKED || info.hbmpUnchecked) {
+				Draw3DCheckmark(pDC, rect2, state&ODS_SELECTED,
+					state&ODS_CHECKED ? info.hbmpChecked :
+				info.hbmpUnchecked);
+			}
+		}
+		
+		//This is needed always so that we can have the space for check marks
+		
+		x0=rect.left;y0=rect.top;
+		rect.left = rect.left + m_iconX + 8 + BCMENU_GAP; 
+		
+		if(!strText.IsEmpty()){
+			
+			CRect rectt(rect.left,rect.top-1,rect.right,rect.bottom-1);
+			
+			//   Find tabs
+			
+			CString leftStr,rightStr;
+			leftStr.Empty();rightStr.Empty();
+			int tablocr=strText.ReverseFind(_T('\t'));
+			if(tablocr!=-1){
+				rightStr=strText.Mid(tablocr+1);
+				leftStr=strText.Left(strText.Find(_T('\t')));
+				rectt.right-=m_iconX;
+			}
+			else leftStr=strText;
+			
+			int iOldMode = pDC->GetBkMode();
+			pDC->SetBkMode( TRANSPARENT);
+			
+			// Draw the text in the correct colour:
+			
+			UINT nFormat  = DT_LEFT|DT_SINGLELINE|DT_VCENTER;
+			UINT nFormatr = DT_RIGHT|DT_SINGLELINE|DT_VCENTER;
+			if(!(lpDIS->itemState & ODS_GRAYED)){
+				pDC->SetTextColor(crText);
+				pDC->DrawText (leftStr,rectt,nFormat);
+				if(tablocr!=-1) pDC->DrawText (rightStr,rectt,nFormatr);
+			}
+			else{
+				
+				// Draw the disabled text
+				if(!(state & ODS_SELECTED)){
+					RECT offset = *rectt;
+					offset.left+=1;
+					offset.right+=1;
+					offset.top+=1;
+					offset.bottom+=1;
+					pDC->SetTextColor(GetSysColor(COLOR_BTNHILIGHT));
+					pDC->DrawText(leftStr,&offset, nFormat);
+					if(tablocr!=-1) pDC->DrawText (rightStr,&offset,nFormatr);
+					pDC->SetTextColor(GetSysColor(COLOR_GRAYTEXT));
+					pDC->DrawText(leftStr,rectt, nFormat);
+					if(tablocr!=-1) pDC->DrawText (rightStr,rectt,nFormatr);
+				}
+				else{
+					// And the standard Grey text:
+					pDC->SetTextColor(m_clrBack);
+					pDC->DrawText(leftStr,rectt, nFormat);
+					if(tablocr!=-1) pDC->DrawText (rightStr,rectt,nFormatr);
+				}
+			}
+			pDC->SetBkMode( iOldMode );
+		}
+		
+		m_penBack.DeleteObject();
+		m_brSelect.DeleteObject();
+	}
+	m_brBackground.DeleteObject();
+}
+
+COLORREF BCMenu::LightenColor(COLORREF col,double factor)
+{
+	if(factor>0.0&&factor<=1.0){
+		BYTE red,green,blue,lightred,lightgreen,lightblue;
+		red = GetRValue(col);
+		green = GetGValue(col);
+		blue = GetBValue(col);
+		lightred = (BYTE)((factor*(255-red)) + red);
+		lightgreen = (BYTE)((factor*(255-green)) + green);
+		lightblue = (BYTE)((factor*(255-blue)) + blue);
+		col = RGB(lightred,lightgreen,lightblue);
+	}
+	return(col);
+}
+
+COLORREF BCMenu::DarkenColor(COLORREF col,double factor)
+{
+	if(factor>0.0&&factor<=1.0){
+		BYTE red,green,blue,lightred,lightgreen,lightblue;
+		red = GetRValue(col);
+		green = GetGValue(col);
+		blue = GetBValue(col);
+		lightred = (BYTE)(red-(factor*red));
+		lightgreen = (BYTE)(green-(factor*green));
+		lightblue = (BYTE)(blue-(factor*blue));
+		col = RGB(lightred,lightgreen,lightblue);
+	}
+	return(col);
+}
+
+
+void BCMenu::DrawItem_WinXP (LPDRAWITEMSTRUCT lpDIS)
+{
+	ASSERT(lpDIS != NULL);
+	CDC* pDC = CDC::FromHandle(lpDIS->hDC);
+#ifdef BCMENU_USE_MEMDC
+	BCMenuMemDC *pMemDC=NULL;
+#endif
+	CRect rect,rect2;
+	UINT state = (((BCMenuData*)(lpDIS->itemData))->nFlags);
+	COLORREF m_newclrBack=GetSysColor(COLOR_3DFACE);
+	COLORREF m_clrBack=GetSysColor(COLOR_WINDOW);
+	CFont m_fontMenu,*pFont=NULL;
+	LOGFONT m_lf;
+	if(!IsWinXPLuna())m_newclrBack=LightenColor(m_newclrBack,0.25);
+	CBrush m_newbrBackground,m_brBackground;
+	m_brBackground.CreateSolidBrush(m_clrBack);
+	m_newbrBackground.CreateSolidBrush(m_newclrBack);
+	int BCMENU_PAD=4;
+	if(xp_draw_3D_bitmaps)BCMENU_PAD=7;
+	int barwidth=m_iconX+BCMENU_PAD;
+	
+	// remove the selected bit if it's grayed out
+	if(lpDIS->itemState & ODS_GRAYED&&!xp_select_disabled){
+		if(lpDIS->itemState & ODS_SELECTED)lpDIS->itemState=lpDIS->itemState & ~ODS_SELECTED;
+#ifdef BCMENU_USE_MEMDC
+		pMemDC=new BCMenuMemDC(pDC,&lpDIS->rcItem);
+		pDC = pMemDC;
+		ZeroMemory ((PVOID) &m_lf,sizeof (LOGFONT));
+		NONCLIENTMETRICS nm;
+		nm.cbSize = sizeof (NONCLIENTMETRICS);
+		VERIFY (SystemParametersInfo(SPI_GETNONCLIENTMETRICS,nm.cbSize,&nm,0)); 
+		m_lf =  nm.lfMenuFont;
+		m_fontMenu.CreateFontIndirect (&m_lf);
+		pFont = pDC->SelectObject (&m_fontMenu);
+#endif
+
+	}
+	
+	if(state & MF_SEPARATOR){
+		rect.CopyRect(&lpDIS->rcItem);
+		pDC->FillRect (rect,&m_brBackground);
+		rect2.SetRect(rect.left,rect.top,rect.left+barwidth,rect.bottom);
+		rect.top+=rect.Height()>>1;
+		rect.left = rect2.right+BCMENU_PAD;
+		pDC->DrawEdge(&rect,EDGE_ETCHED,BF_TOP);
+		pDC->FillRect (rect2,&m_newbrBackground);
+		pDC->Draw3dRect (rect2,m_newclrBack,m_newclrBack);
+	}
+	else{
+		BOOL standardflag=FALSE,selectedflag=FALSE,disableflag=FALSE;
+		BOOL checkflag=FALSE;
+		COLORREF crText = GetSysColor(COLOR_MENUTEXT);
+		COLORREF crSelect = GetSysColor(COLOR_HIGHLIGHT);
+		COLORREF crSelectFill;
+		if(!IsWinXPLuna())crSelectFill=LightenColor(crSelect,0.85);
+		else crSelectFill=LightenColor(crSelect,0.7);
+		CBrush m_brSelect;
+		CPen m_penBack;
+		int x0,y0,dx,dy;
+		int nIconNormal=-1,xoffset=-1,global_offset=-1;
+		int faded_offset=1,shadow_offset=2;
+		CImageList *bitmap=NULL;
+		BOOL CanDraw3D=FALSE;
+		
+		// set some colors
+		m_penBack.CreatePen (PS_SOLID,0,m_clrBack);
+		m_brSelect.CreateSolidBrush(crSelectFill);
+		
+		// draw the colored rectangle portion
+		
+		rect.CopyRect(&lpDIS->rcItem);
+		rect2=rect;
+		
+		// draw the up/down/focused/disabled state
+		
+		UINT state = lpDIS->itemState;
+		CString strText;
+		
+		if(lpDIS->itemData != NULL){
+			nIconNormal = (((BCMenuData*)(lpDIS->itemData))->menuIconNormal);
+			xoffset = (((BCMenuData*)(lpDIS->itemData))->xoffset);
+			bitmap = (((BCMenuData*)(lpDIS->itemData))->bitmap);
+			strText = ((BCMenuData*) (lpDIS->itemData))->GetString();
+			global_offset = (((BCMenuData*)(lpDIS->itemData))->global_offset);
+
+			if(xoffset==0&&xp_draw_3D_bitmaps&&bitmap&&bitmap->GetImageCount()>2)CanDraw3D=TRUE;
+
+			if(nIconNormal<0&&xoffset<0&&global_offset>=0){
+				xoffset=global_offset;
+				nIconNormal=0;
+				bitmap = &m_AllImages;
+				if(xp_draw_3D_bitmaps&&CanDraw3DImageList(global_offset)){
+					CanDraw3D=TRUE;
+					faded_offset=global_offset+1;
+					shadow_offset=global_offset+2;
+				}
+			}
+
+			
+			if(state&ODS_CHECKED && nIconNormal<0){
+				if(state&ODS_SELECTED && m_selectcheck>0)checkflag=TRUE;
+				else if(m_unselectcheck>0) checkflag=TRUE;
+			}
+			else if(nIconNormal != -1){
+				standardflag=TRUE;
+				if(state&ODS_SELECTED && !(state&ODS_GRAYED))selectedflag=TRUE;
+				else if(state&ODS_GRAYED) disableflag=TRUE;
+			}
+		}
+		else{
+			strText.Empty();
+		}
+		
+		if(state&ODS_SELECTED){ // draw the down edges
+			
+			CPen *pOldPen = pDC->SelectObject (&m_penBack);
+			
+			pDC->FillRect (rect,&m_brSelect);
+			pDC->Draw3dRect (rect,crSelect,crSelect);
+			
+			pDC->SelectObject (pOldPen);
+		}
+		else {
+			rect2.SetRect(rect.left,rect.top,rect.left+barwidth,rect.bottom);
+			CPen *pOldPen = pDC->SelectObject (&m_penBack);
+			pDC->FillRect (rect,&m_brBackground);
+			pDC->FillRect (rect2,&m_newbrBackground);
+			pDC->SelectObject (pOldPen);
+			
+			// draw the up edges
+			
+			pDC->Draw3dRect (rect,m_clrBack,m_clrBack);
+			pDC->Draw3dRect (rect2,m_newclrBack,m_newclrBack);
+		}
+		
+		// draw the text if there is any
+		//We have to paint the text only if the image is nonexistant
+		
+		dy = (int)(0.5+(rect.Height()-m_iconY)/2.0);
+		dy = dy<0 ? 0 : dy;
+		dx = (int)(0.5+(barwidth-m_iconX)/2.0);
+		dx = dx<0 ? 0 : dx;
+		
+		if(checkflag||standardflag||selectedflag||disableflag){
+			rect2.SetRect(rect.left+1,rect.top+1,rect.left+barwidth-1,
+				rect.bottom-1);
+			if(checkflag && checkmaps){
+				pDC->FillRect (rect2,&m_newbrBackground);
+				CPoint ptImage(rect.left+dx,rect.top+dy);		
+				if(state&ODS_SELECTED)checkmaps->Draw(pDC,1,ptImage,ILD_TRANSPARENT);
+				else checkmaps->Draw(pDC,0,ptImage,ILD_TRANSPARENT);
+			}
+			else if(disableflag){
+				if(!selectedflag){
+					CBitmap bitmapstandard;
+					GetBitmapFromImageList(pDC,bitmap,xoffset,bitmapstandard);
+					COLORREF transparentcol=m_newclrBack;
+					if(state&ODS_SELECTED)transparentcol=crSelectFill;
+					if(disable_old_style)
+						DitherBlt(lpDIS->hDC,rect.left+dx,rect.top+dy,m_iconX,m_iconY,
+						(HBITMAP)(bitmapstandard),0,0,transparentcol);
+					else
+						DitherBlt2(pDC,rect.left+dx,rect.top+dy,m_iconX,m_iconY,
+						bitmapstandard,0,0,transparentcol);
+					if(state&ODS_SELECTED)pDC->Draw3dRect (rect,crSelect,crSelect);
+					bitmapstandard.DeleteObject();
+				}
+			}
+			else if(selectedflag){
+				pDC->FillRect (rect2,&m_brSelect);
+				CPoint ptImage(rect.left+dx,rect.top+dy);
+				if(state&ODS_CHECKED){
+					pDC->Draw3dRect(rect2,crSelect,crSelect);
+					ptImage.x-=1;ptImage.y-=1;
+				}
+				if(bitmap){
+					if(CanDraw3D&&!(state&ODS_CHECKED)){
+						CPoint ptImage1(ptImage.x+1,ptImage.y+1);
+						CPoint ptImage2(ptImage.x-1,ptImage.y-1);
+						bitmap->Draw(pDC,shadow_offset,ptImage1,ILD_TRANSPARENT);
+						bitmap->Draw(pDC,xoffset,ptImage2,ILD_TRANSPARENT);
+					}
+					else bitmap->Draw(pDC,xoffset,ptImage,ILD_TRANSPARENT);
+				}
+			}
+			else{
+				if(state&ODS_CHECKED){
+					CBrush brushin;
+					brushin.CreateSolidBrush(LightenColor(crSelect,0.85));
+					pDC->FillRect(rect2,&brushin);
+					brushin.DeleteObject();
+					pDC->Draw3dRect(rect2,crSelect,crSelect);
+					CPoint ptImage(rect.left+dx-1,rect.top+dy-1);
+					if(bitmap)bitmap->Draw(pDC,xoffset,ptImage,ILD_TRANSPARENT);
+				}
+				else{
+					pDC->FillRect (rect2,&m_newbrBackground);
+					pDC->Draw3dRect (rect2,m_newclrBack,m_newclrBack);
+					CPoint ptImage(rect.left+dx,rect.top+dy);
+					if(bitmap){
+						if(CanDraw3D)
+							bitmap->Draw(pDC,faded_offset,ptImage,ILD_TRANSPARENT);
+						else
+							bitmap->Draw(pDC,xoffset,ptImage,ILD_TRANSPARENT);
+					}
+				}
+			}
+		}
+		if(nIconNormal<0 && state&ODS_CHECKED && !checkflag){
+			dy = (int)(0.5+(rect.Height()-16)/2.0);
+			dy = dy<0 ? 0 : dy;
+			dx = (int)(0.5+(barwidth-16)/2.0);
+			dx = dx<0 ? 0 : dx;
+			CMenuItemInfo info;
+			info.fMask = MIIM_CHECKMARKS;
+			::GetMenuItemInfo((HMENU)lpDIS->hwndItem,lpDIS->itemID,
+				MF_BYCOMMAND, &info);
+			if(state&ODS_CHECKED || info.hbmpUnchecked) {
+				rect2.SetRect(rect.left+dx,rect.top+dy,rect.left+dx+16,rect.top+dy+16);
+				DrawXPCheckmark(pDC, rect2,state&ODS_CHECKED ? info.hbmpChecked :
+				info.hbmpUnchecked,crSelect);
+			}
+		}
+		
+		//This is needed always so that we can have the space for check marks
+		
+		x0=rect.left;y0=rect.top;
+		rect.left = rect.left + barwidth + 8; 
+		
+		if(!strText.IsEmpty()){
+			
+			CRect rectt(rect.left,rect.top-1,rect.right,rect.bottom-1);
+			
+			//   Find tabs
+			
+			CString leftStr,rightStr;
+			leftStr.Empty();rightStr.Empty();
+			int tablocr=strText.ReverseFind(_T('\t'));
+			if(tablocr!=-1){
+				rightStr=strText.Mid(tablocr+1);
+				leftStr=strText.Left(strText.Find(_T('\t')));
+				rectt.right-=m_iconX;
+			}
+			else leftStr=strText;
+			
+			int iOldMode = pDC->GetBkMode();
+			pDC->SetBkMode( TRANSPARENT);
+			
+			// Draw the text in the correct colour:
+			
+			UINT nFormat  = DT_LEFT|DT_SINGLELINE|DT_VCENTER;
+			UINT nFormatr = DT_RIGHT|DT_SINGLELINE|DT_VCENTER;
+			if(!(lpDIS->itemState & ODS_GRAYED)){
+				pDC->SetTextColor(crText);
+				pDC->DrawText (leftStr,rectt,nFormat);
+				if(tablocr!=-1) pDC->DrawText (rightStr,rectt,nFormatr);
+			}
+			else{
+				RECT offset = *rectt;
+				offset.left+=1;
+				offset.right+=1;
+				offset.top+=1;
+				offset.bottom+=1;
+				if(!IsWinXPLuna()){
+					COLORREF graycol=GetSysColor(COLOR_GRAYTEXT);
+					if(!(state&ODS_SELECTED))graycol = LightenColor(graycol,0.4);
+					pDC->SetTextColor(graycol);
+				}
+				else pDC->SetTextColor(GetSysColor(COLOR_GRAYTEXT));
+				pDC->DrawText(leftStr,rectt, nFormat);
+				if(tablocr!=-1) pDC->DrawText (rightStr,rectt,nFormatr);
+			}
+			pDC->SetBkMode( iOldMode );
+		}
+		
+		m_penBack.DeleteObject();
+		m_brSelect.DeleteObject();
+	}
+	m_brBackground.DeleteObject();
+	m_newbrBackground.DeleteObject();
+#ifdef BCMENU_USE_MEMDC
+	if(pFont)pDC->SelectObject (pFont); //set it to the old font
+	m_fontMenu.DeleteObject();
+	if(pMemDC)delete pMemDC;
+#endif
+}
+
+BOOL BCMenu::GetBitmapFromImageList(CDC* pDC,CImageList *imglist,int nIndex,CBitmap &bmp)
+{
+	HICON hIcon = imglist->ExtractIcon(nIndex);
+	CDC dc;
+	dc.CreateCompatibleDC(pDC);
+	bmp.CreateCompatibleBitmap(pDC,m_iconX,m_iconY);
+	CBitmap* pOldBmp = dc.SelectObject(&bmp);
+	CBrush brush ;
+	COLORREF m_newclrBack;
+	m_newclrBack=GetSysColor(COLOR_3DFACE);
+	brush.CreateSolidBrush(m_newclrBack);
+	::DrawIconEx(
+		dc.GetSafeHdc(),
+		0,
+		0,
+		hIcon,
+		m_iconX,
+		m_iconY,
+		0,
+		(HBRUSH)brush,
+		DI_NORMAL
+		);
+	dc.SelectObject( pOldBmp );
+	dc.DeleteDC();
+	// the icon is not longer needed
+	::DestroyIcon(hIcon);
+	return(TRUE);
+}
+
+/*
+==========================================================================
+void BCMenu::MeasureItem(LPMEASUREITEMSTRUCT)
+---------------------------------------------
+
+  Called by the framework when it wants to know what the width and height
+  of our item will be.  To accomplish this we provide the width of the
+  icon plus the width of the menu text, and then the height of the icon.
+  
+	==========================================================================
+*/
+
+void BCMenu::MeasureItem( LPMEASUREITEMSTRUCT lpMIS )
+{
+	UINT state = (((BCMenuData*)(lpMIS->itemData))->nFlags);
+	int BCMENU_PAD=4;
+	if(IsLunaMenuStyle()&&xp_draw_3D_bitmaps)BCMENU_PAD=7;
+	if(state & MF_SEPARATOR){
+		lpMIS->itemWidth = 0;
+		int temp = GetSystemMetrics(SM_CYMENU)>>1;
+		lpMIS->itemHeight = temp>(m_iconY+BCMENU_PAD)/2 ? temp : (m_iconY+BCMENU_PAD)/2;
+	}
+	else{
+		CFont m_fontMenu;
+		LOGFONT m_lf;
+		ZeroMemory ((PVOID) &m_lf,sizeof (LOGFONT));
+		NONCLIENTMETRICS nm;
+		nm.cbSize = sizeof (NONCLIENTMETRICS);
+		VERIFY(SystemParametersInfo(SPI_GETNONCLIENTMETRICS,
+			nm.cbSize,&nm,0)); 
+		m_lf =  nm.lfMenuFont;
+		m_fontMenu.CreateFontIndirect (&m_lf);
+		
+		// Obtain the width of the text:
+		CWnd *pWnd = AfxGetMainWnd();            // Get main window
+		if (pWnd == NULL) pWnd = CWnd::GetDesktopWindow();
+		CDC *pDC = pWnd->GetDC();              // Get device context
+		CFont* pFont=NULL;    // Select menu font in...
+		
+		if (IsNewShell())
+			pFont = pDC->SelectObject (&m_fontMenu);// Select menu font in...
+        
+		//Get pointer to text SK
+		const wchar_t *lpstrText = ((BCMenuData*)(lpMIS->itemData))->GetWideString();//SK: we use const to prevent misuse
+		    
+		SIZE size;
+		size.cx=size.cy=0;
+		
+		if (Win32s!=g_Shell)
+			VERIFY(::GetTextExtentPoint32W(pDC->m_hDC,lpstrText,
+			wcslen(lpstrText),&size)); //SK should also work on 95
+#ifndef UNICODE //can't be UNICODE for Win32s
+		else{//it's Win32suckx
+			RECT rect;
+			rect.left=rect.top=0;
+			size.cy=DrawText(pDC->m_hDC,(LPCTSTR)lpstrText,
+				wcslen(lpstrText),&rect,
+				DT_SINGLELINE|DT_LEFT|DT_VCENTER|DT_CALCRECT);
+			//+3 makes at least three pixels space to the menu border
+			size.cx=rect.right-rect.left+3;
+			size.cx += 3*(size.cx/wcslen(lpstrText));
+		}
+#endif    
+		
+		CSize t = CSize(size);
+		if(IsNewShell())
+			pDC->SelectObject (pFont);  // Select old font in
+		pWnd->ReleaseDC(pDC);  // Release the DC
+		
+		// Set width and height:
+		
+		if(IsLunaMenuStyle())lpMIS->itemWidth = m_iconX+BCMENU_PAD+8+t.cx;
+		else lpMIS->itemWidth = m_iconX + t.cx + m_iconX + BCMENU_GAP;
+		int temp = GetSystemMetrics(SM_CYMENU);
+		lpMIS->itemHeight = temp>m_iconY+BCMENU_PAD ? temp : m_iconY+BCMENU_PAD;
+		m_fontMenu.DeleteObject();
+	}
+}
+
+void BCMenu::SetIconSize (int width, int height)
+{
+	m_iconX = width;
+	m_iconY = height;
+}
+
+BOOL BCMenu::AppendODMenuA(LPCSTR lpstrText,UINT nFlags,UINT nID,
+                           int nIconNormal)
+{
+	USES_CONVERSION;
+	return AppendODMenuW(A2W(lpstrText),nFlags,nID,nIconNormal);//SK: See MFC Tech Note 059
+}
+
+
+BOOL BCMenu::AppendODMenuW(wchar_t *lpstrText,UINT nFlags,UINT nID,
+                           int nIconNormal)
+{
+	// Add the MF_OWNERDRAW flag if not specified:
+	if(!nID){
+		if(nFlags&MF_BYPOSITION)nFlags=MF_SEPARATOR|MF_OWNERDRAW|MF_BYPOSITION;
+		else nFlags=MF_SEPARATOR|MF_OWNERDRAW;
+	}
+	else if(!(nFlags & MF_OWNERDRAW))nFlags |= MF_OWNERDRAW;
+	
+	if(nFlags & MF_POPUP){
+		m_AllSubMenus.Add((HMENU)nID);
+		m_SubMenus.Add((HMENU)nID);
+	}
+	
+	BCMenuData *mdata = new BCMenuData;
+	m_MenuList.Add(mdata);
+	mdata->SetWideString(lpstrText);    //SK: modified for dynamic allocation
+	
+	mdata->menuIconNormal = -1;
+	mdata->xoffset = -1;
+	
+	if(nIconNormal>=0){
+		CImageList bitmap;
+		int xoffset=0;
+		LoadFromToolBar(nID,nIconNormal,xoffset);
+		if(mdata->bitmap){
+			mdata->bitmap->DeleteImageList();
+			mdata->bitmap=NULL;
+		}
+		bitmap.Create(m_iconX,m_iconY,ILC_COLORDDB|ILC_MASK,1,1);
+		if(AddBitmapToImageList(&bitmap,nIconNormal)){
+			mdata->global_offset = AddToGlobalImageList(&bitmap,xoffset,nID);
+		}
+	}
+	else mdata->global_offset = GlobalImageListOffset(nID);
+
+	mdata->nFlags = nFlags;
+	mdata->nID = nID;
+	BOOL returnflag=CMenu::AppendMenu(nFlags, nID, (LPCTSTR)mdata);
+	if(m_loadmenu)RemoveTopLevelOwnerDraw();
+	return(returnflag);
+}
+
+BOOL BCMenu::AppendODMenuA(LPCSTR lpstrText,UINT nFlags,UINT nID,
+                           CImageList *il,int xoffset)
+{
+	USES_CONVERSION;
+	return AppendODMenuW(A2W(lpstrText),nFlags,nID,il,xoffset);
+}
+
+BOOL BCMenu::AppendODMenuW(wchar_t *lpstrText,UINT nFlags,UINT nID,
+                           CImageList *il,int xoffset)
+{
+	// Add the MF_OWNERDRAW flag if not specified:
+	if(!nID){
+		if(nFlags&MF_BYPOSITION)nFlags=MF_SEPARATOR|MF_OWNERDRAW|MF_BYPOSITION;
+		else nFlags=MF_SEPARATOR|MF_OWNERDRAW;
+	}
+	else if(!(nFlags & MF_OWNERDRAW))nFlags |= MF_OWNERDRAW;
+	
+	if(nFlags & MF_POPUP){
+		m_AllSubMenus.Add((HMENU)nID);
+		m_SubMenus.Add((HMENU)nID);
+	}
+	
+	BCMenuData *mdata = new BCMenuData;
+	m_MenuList.Add(mdata);
+	mdata->SetWideString(lpstrText);    //SK: modified for dynamic allocation
+	
+	if(il){
+		mdata->menuIconNormal = 0;
+		mdata->xoffset=0;
+		if(mdata->bitmap)mdata->bitmap->DeleteImageList();
+		else mdata->bitmap=new(CImageList);
+		ImageListDuplicate(il,xoffset,mdata->bitmap);
+	}
+	else{
+		mdata->menuIconNormal = -1;
+		mdata->xoffset = -1;
+	}
+	mdata->nFlags = nFlags;
+	mdata->nID = nID;
+	return(CMenu::AppendMenu(nFlags, nID, (LPCTSTR)mdata));
+}
+
+BOOL BCMenu::InsertODMenuA(UINT nPosition,LPCSTR lpstrText,UINT nFlags,UINT nID,
+                           int nIconNormal)
+{
+	USES_CONVERSION;
+	return InsertODMenuW(nPosition,A2W(lpstrText),nFlags,nID,nIconNormal);
+}
+
+
+BOOL BCMenu::InsertODMenuW(UINT nPosition,wchar_t *lpstrText,UINT nFlags,UINT nID,
+                           int nIconNormal)
+{
+	if(!(nFlags & MF_BYPOSITION)){
+		int iPosition =0;
+		BCMenu* pMenu = FindMenuOption(nPosition,iPosition);
+		if(pMenu){
+			return(pMenu->InsertODMenuW(iPosition,lpstrText,nFlags|MF_BYPOSITION,nID,nIconNormal));
+		}
+		else return(FALSE);
+	}
+	
+	if(!nID)nFlags=MF_SEPARATOR|MF_OWNERDRAW|MF_BYPOSITION;
+	else if(!(nFlags & MF_OWNERDRAW))nFlags |= MF_OWNERDRAW;
+
+	int menustart=0;
+
+	if(nFlags & MF_POPUP){
+		if(m_loadmenu){
+			menustart=GetMenuStart();
+			if(nPosition<(UINT)menustart)menustart=0;
+		}
+		m_AllSubMenus.Add((HMENU)nID);
+		m_SubMenus.InsertAt(nPosition,(HMENU)nID);
+	}
+
+	//Stephane Clog suggested adding this, believe it or not it's in the help 
+	if(nPosition==(UINT)-1)nPosition=GetMenuItemCount();
+	
+	BCMenuData *mdata = new BCMenuData;
+	m_MenuList.InsertAt(nPosition-menustart,mdata);
+	mdata->SetWideString(lpstrText);    //SK: modified for dynamic allocation
+	
+	mdata->menuIconNormal = nIconNormal;
+	mdata->xoffset=-1;
+	if(nIconNormal>=0){
+		CImageList bitmap;
+		int xoffset=0;
+		LoadFromToolBar(nID,nIconNormal,xoffset);
+		if(mdata->bitmap){
+			mdata->bitmap->DeleteImageList();
+			mdata->bitmap=NULL;
+		}
+		bitmap.Create(m_iconX,m_iconY,ILC_COLORDDB|ILC_MASK,1,1);
+		if(AddBitmapToImageList(&bitmap,nIconNormal)){
+			mdata->global_offset = AddToGlobalImageList(&bitmap,xoffset,nID);
+		}
+	}
+	else mdata->global_offset = GlobalImageListOffset(nID);
+	mdata->nFlags = nFlags;
+	mdata->nID = nID;
+	BOOL returnflag=CMenu::InsertMenu(nPosition,nFlags,nID,(LPCTSTR)mdata);
+	if(m_loadmenu)RemoveTopLevelOwnerDraw();
+	return(returnflag);
+}
+
+BOOL BCMenu::InsertODMenuA(UINT nPosition,LPCSTR lpstrText,UINT nFlags,UINT nID,
+                           CImageList *il,int xoffset)
+{
+	USES_CONVERSION;
+	return InsertODMenuW(nPosition,A2W(lpstrText),nFlags,nID,il,xoffset);
+}
+
+BOOL BCMenu::InsertODMenuW(UINT nPosition,wchar_t *lpstrText,UINT nFlags,UINT nID,
+                           CImageList *il,int xoffset)
+{
+	if(!(nFlags & MF_BYPOSITION)){
+		int iPosition =0;
+		BCMenu* pMenu = FindMenuOption(nPosition,iPosition);
+		if(pMenu){
+			return(pMenu->InsertODMenuW(iPosition,lpstrText,nFlags|MF_BYPOSITION,nID,il,xoffset));
+		}
+		else return(FALSE);
+	}
+	
+	if(!nID)nFlags=MF_SEPARATOR|MF_OWNERDRAW|MF_BYPOSITION;
+	else if(!(nFlags & MF_OWNERDRAW))nFlags |= MF_OWNERDRAW;
+	
+	if(nFlags & MF_POPUP){
+		m_AllSubMenus.Add((HMENU)nID);
+		m_SubMenus.InsertAt(nPosition,(HMENU)nID);
+	}
+	
+	//Stephane Clog suggested adding this, believe it or not it's in the help 
+	if(nPosition==(UINT)-1)nPosition=GetMenuItemCount();
+	
+	BCMenuData *mdata = new BCMenuData;
+	m_MenuList.InsertAt(nPosition,mdata);
+	mdata->SetWideString(lpstrText);    //SK: modified for dynamic allocation
+	
+	mdata->menuIconNormal = -1;
+	mdata->xoffset = -1;
+
+	if(il){
+		if(mdata->bitmap){
+			mdata->bitmap->DeleteImageList();
+			mdata->bitmap=NULL;
+		}
+		mdata->global_offset = AddToGlobalImageList(il,xoffset,nID);
+	}
+	mdata->nFlags = nFlags;
+	mdata->nID = nID;
+	return(CMenu::InsertMenu(nPosition,nFlags,nID,(LPCTSTR)mdata));
+}
+
+BOOL BCMenu::ModifyODMenuA(const char * lpstrText,UINT nID,int nIconNormal)
+{
+	USES_CONVERSION;
+	return ModifyODMenuW(A2W(lpstrText),nID,nIconNormal);//SK: see MFC Tech Note 059
+}
+
+BOOL BCMenu::ModifyODMenuW(wchar_t *lpstrText,UINT nID,int nIconNormal)
+{
+	int nLoc;
+	BCMenuData *mdata;
+	CArray<BCMenu*,BCMenu*>bcsubs;
+	CArray<int,int&>bclocs;
+	
+	// Find the old BCMenuData structure:
+	BCMenu *psubmenu = FindMenuOption(nID,nLoc);
+	do{
+		if(psubmenu && nLoc>=0)mdata = psubmenu->m_MenuList[nLoc];
+		else{
+			// Create a new BCMenuData structure:
+			mdata = new BCMenuData;
+			m_MenuList.Add(mdata);
+		}
+		
+		ASSERT(mdata);
+		if(lpstrText)
+			mdata->SetWideString(lpstrText);  //SK: modified for dynamic allocation
+		mdata->menuIconNormal = -1;
+		mdata->xoffset = -1;
+		if(nIconNormal>=0){
+			CImageList bitmap;
+			int xoffset=0;
+			LoadFromToolBar(nID,nIconNormal,xoffset);
+			if(mdata->bitmap){
+				mdata->bitmap->DeleteImageList();
+				mdata->bitmap=NULL;
+			}
+			bitmap.Create(m_iconX,m_iconY,ILC_COLORDDB|ILC_MASK,1,1);
+			if(AddBitmapToImageList(&bitmap,nIconNormal)){
+				mdata->global_offset = AddToGlobalImageList(&bitmap,xoffset,nID);
+			}
+		}
+		else mdata->global_offset = GlobalImageListOffset(nID);
+		mdata->nFlags &= ~(MF_BYPOSITION);
+		mdata->nFlags |= MF_OWNERDRAW;
+		mdata->nID = nID;
+		bcsubs.Add(psubmenu);
+		bclocs.Add(nLoc);
+		if(psubmenu && nLoc>=0)psubmenu = FindAnotherMenuOption(nID,nLoc,bcsubs,bclocs);
+		else psubmenu=NULL;
+	}while(psubmenu);
+	return (CMenu::ModifyMenu(nID,mdata->nFlags,nID,(LPCTSTR)mdata));
+}
+
+BOOL BCMenu::ModifyODMenuA(const char * lpstrText,UINT nID,CImageList *il,int xoffset)
+{
+	USES_CONVERSION;
+	return ModifyODMenuW(A2W(lpstrText),nID,il,xoffset);
+}
+
+BOOL BCMenu::ModifyODMenuW(wchar_t *lpstrText,UINT nID,CImageList *il,int xoffset)
+{
+	int nLoc;
+	BCMenuData *mdata;
+	CArray<BCMenu*,BCMenu*>bcsubs;
+	CArray<int,int&>bclocs;
+	
+	// Find the old BCMenuData structure:
+	BCMenu *psubmenu = FindMenuOption(nID,nLoc);
+	do{
+		if(psubmenu && nLoc>=0)mdata = psubmenu->m_MenuList[nLoc];
+		else{
+			// Create a new BCMenuData structure:
+			mdata = new BCMenuData;
+			m_MenuList.Add(mdata);
+		}
+		
+		ASSERT(mdata);
+		if(lpstrText)
+			mdata->SetWideString(lpstrText);  //SK: modified for dynamic allocation
+		mdata->menuIconNormal = -1;
+		mdata->xoffset = -1;
+		if(il){
+			if(mdata->bitmap){
+				mdata->bitmap->DeleteImageList();
+				mdata->bitmap=NULL;
+			}
+			mdata->global_offset = AddToGlobalImageList(il,xoffset,nID);
+		}
+		mdata->nFlags &= ~(MF_BYPOSITION);
+		mdata->nFlags |= MF_OWNERDRAW;
+		mdata->nID = nID;
+		bcsubs.Add(psubmenu);
+		bclocs.Add(nLoc);
+		if(psubmenu && nLoc>=0)psubmenu = FindAnotherMenuOption(nID,nLoc,bcsubs,bclocs);
+		else psubmenu=NULL;
+	}while(psubmenu);
+	return (CMenu::ModifyMenu(nID,mdata->nFlags,nID,(LPCTSTR)mdata));
+}
+
+BOOL BCMenu::ModifyODMenuA(const char * lpstrText,UINT nID,CBitmap *bmp)
+{
+	USES_CONVERSION;
+	return ModifyODMenuW(A2W(lpstrText),nID,bmp);
+}
+
+BOOL BCMenu::ModifyODMenuW(wchar_t *lpstrText,UINT nID,CBitmap *bmp)
+{
+	if(bmp){
+		CImageList temp;
+		temp.Create(m_iconX,m_iconY,ILC_COLORDDB|ILC_MASK,1,1);
+		if(m_bitmapBackgroundFlag)temp.Add(bmp,m_bitmapBackground);
+		else temp.Add(bmp,GetSysColor(COLOR_3DFACE));
+		return ModifyODMenuW(lpstrText,nID,&temp,0);
+	}
+	return ModifyODMenuW(lpstrText,nID,NULL,0);
+}
+
+// courtesy of Warren Stevens
+BOOL BCMenu::ModifyODMenuA(const char * lpstrText,UINT nID,COLORREF fill,COLORREF border,int hatchstyle,CSize *pSize)
+{
+	USES_CONVERSION;
+	return ModifyODMenuW(A2W(lpstrText),nID,fill,border,hatchstyle,pSize);
+}
+
+BOOL BCMenu::ModifyODMenuW(wchar_t *lpstrText,UINT nID,COLORREF fill,COLORREF border,int hatchstyle,CSize *pSize)
+{
+	CWnd *pWnd = AfxGetMainWnd();            // Get main window
+	CDC *pDC = pWnd->GetDC();              // Get device context
+	SIZE sz;
+	if(!pSize){
+		sz.cx = m_iconX;
+		sz.cy = m_iconY;
+	}
+	else{
+		sz.cx = pSize->cx;
+		sz.cy = pSize->cy;
+	}
+	CSize bitmap_size(sz);
+	CSize icon_size(m_iconX,m_iconY);
+	CBitmap bmp;
+	ColorBitmap(pDC,bmp,bitmap_size,icon_size,fill,border,hatchstyle);		
+	pWnd->ReleaseDC(pDC);
+	return ModifyODMenuW(lpstrText,nID,&bmp);
+}
+
+
+BOOL BCMenu::ModifyODMenuA(const char *lpstrText,const char *OptionText,
+                           int nIconNormal)
+{
+	USES_CONVERSION;
+	return ModifyODMenuW(A2W(lpstrText),A2W(OptionText),nIconNormal);//SK: see MFC  Tech Note 059
+}
+
+BOOL BCMenu::ModifyODMenuW(wchar_t *lpstrText,wchar_t *OptionText,
+                           int nIconNormal)
+{
+	BCMenuData *mdata;
+	
+	// Find the old BCMenuData structure:
+	CString junk=OptionText;
+	mdata=FindMenuOption(OptionText);
+	if(mdata){
+		if(lpstrText)
+			mdata->SetWideString(lpstrText);//SK: modified for dynamic allocation
+		mdata->menuIconNormal = nIconNormal;
+		mdata->xoffset=-1;
+		if(nIconNormal>=0){
+			mdata->xoffset=0;
+			if(mdata->bitmap)mdata->bitmap->DeleteImageList();
+			else mdata->bitmap=new(CImageList);
+			mdata->bitmap->Create(m_iconX,m_iconY,ILC_COLORDDB|ILC_MASK,1,1);
+			if(!AddBitmapToImageList(mdata->bitmap,nIconNormal)){
+				mdata->bitmap->DeleteImageList();
+				delete mdata->bitmap;
+				mdata->bitmap=NULL;
+				mdata->menuIconNormal = nIconNormal = -1;
+				mdata->xoffset = -1;
+			}
+		}
+		return(TRUE);
+	}
+	return(FALSE);
+}
+
+BCMenuData *BCMenu::NewODMenu(UINT pos,UINT nFlags,UINT nID,CString string)
+{
+	BCMenuData *mdata;
+	
+	mdata = new BCMenuData;
+	mdata->menuIconNormal = -1;
+	mdata->xoffset=-1;
+#ifdef UNICODE
+	mdata->SetWideString((LPCTSTR)string);//SK: modified for dynamic allocation
+#else
+	mdata->SetAnsiString(string);
+#endif
+	mdata->nFlags = nFlags;
+	mdata->nID = nID;
+	
+//	if(nFlags & MF_POPUP)m_AllSubMenus.Add((HMENU)nID);
+		
+	if (nFlags&MF_OWNERDRAW){
+		ASSERT(!(nFlags&MF_STRING));
+		ModifyMenu(pos,nFlags,nID,(LPCTSTR)mdata);
+	}
+	else if (nFlags&MF_STRING){
+		ASSERT(!(nFlags&MF_OWNERDRAW));
+		ModifyMenu(pos,nFlags,nID,mdata->GetString());
+	}
+	else{
+		ASSERT(nFlags&MF_SEPARATOR);
+		ModifyMenu(pos,nFlags,nID);
+	}
+	
+	return(mdata);
+};
+
+BOOL BCMenu::LoadToolbars(const UINT *arID,int n)
+{
+	ASSERT(arID);
+	BOOL returnflag=TRUE;
+	for(int i=0;i<n;++i){
+		if(!LoadToolbar(arID[i]))returnflag=FALSE;
+	}
+	return(returnflag);
+}
+
+BOOL BCMenu::LoadToolbar(UINT nToolBar)
+{
+	UINT nID,nStyle;
+	BOOL returnflag=FALSE;
+	BCMenuToolBar bar;
+	int xoffset=-1,xset;
+	int iconx,icony;
+	
+	CWnd* pWnd = AfxGetMainWnd();
+	if (pWnd == NULL)pWnd = CWnd::GetDesktopWindow();
+	bar.Create(pWnd);
+	if(bar.LoadToolBar(nToolBar)){
+		bar.GetIconSize(iconx,icony);
+		if(iconx>m_iconX)m_iconX=iconx;
+		if(icony>m_iconY)m_iconY=icony;
+		CImageList imglist;
+		imglist.Create(m_iconX,m_iconY,ILC_COLORDDB|ILC_MASK,1,1);
+		if(AddBitmapToImageList(&imglist,nToolBar)){
+			returnflag=TRUE;
+			for(int i=0;i<bar.GetCount();++i){
+				nID = bar.GetItemID(i); 
+				if(nID && GetMenuState(nID, MF_BYCOMMAND)
+					!=0xFFFFFFFF){
+					xoffset=bar.CommandToIndex(nID);
+					if(xoffset>=0){
+						bar.GetButtonInfo(xoffset,nID,nStyle,xset);
+						if(xset>0)xoffset=xset;
+					}
+					ModifyODMenu(NULL,nID,&imglist,xoffset);
+				}
+			}
+		}
+	}
+	return(returnflag);
+}
+
+BOOL BCMenu::LoadFromToolBar(UINT nID,UINT nToolBar,int& xoffset)
+{
+	int xset,offset;
+	UINT nStyle;
+	BOOL returnflag=FALSE;
+	CToolBar bar;
+	
+	CWnd* pWnd = AfxGetMainWnd();
+	if (pWnd == NULL)pWnd = CWnd::GetDesktopWindow();
+	bar.Create(pWnd);
+	if(bar.LoadToolBar(nToolBar)){
+		offset=bar.CommandToIndex(nID);
+		if(offset>=0){
+			bar.GetButtonInfo(offset,nID,nStyle,xset);
+			if(xset>0)xoffset=xset;
+			returnflag=TRUE;
+		}
+	}
+	return(returnflag);
+}
+
+// O.S.
+BCMenuData *BCMenu::FindMenuItem(UINT nID)
+{
+	BCMenuData *pData = NULL;
+	int i;
+	
+	for(i = 0; i <= m_MenuList.GetUpperBound(); i++){
+		if (m_MenuList[i]->nID == nID){
+			pData = m_MenuList[i];
+			break;
+		}
+	}
+	if (!pData){
+		int loc;
+		BCMenu *pMenu = FindMenuOption(nID, loc);
+		ASSERT(pMenu != this);
+		if (loc >= 0){
+			return pMenu->FindMenuItem(nID);
+		}
+	}
+	return pData;
+}
+
+
+BCMenu *BCMenu::FindAnotherMenuOption(int nId,int& nLoc,CArray<BCMenu*,BCMenu*>&bcsubs,
+									  CArray<int,int&>&bclocs)
+{
+	int i,numsubs,j;
+	BCMenu *psubmenu,*pgoodmenu;
+	BOOL foundflag;
+	
+	for(i=0;i<(int)(GetMenuItemCount());++i){
+#ifdef _CPPRTTI 
+		psubmenu=dynamic_cast<BCMenu *>(GetSubMenu(i));
+#else
+		psubmenu=(BCMenu *)GetSubMenu(i);
+#endif
+		if(psubmenu){
+			pgoodmenu=psubmenu->FindAnotherMenuOption(nId,nLoc,bcsubs,bclocs);
+			if(pgoodmenu)return(pgoodmenu);
+		}
+		else if(nId==(int)GetMenuItemID(i)){
+			numsubs=bcsubs.GetSize();
+			foundflag=TRUE;
+			for(j=0;j<numsubs;++j){
+				if(bcsubs[j]==this&&bclocs[j]==i){
+					foundflag=FALSE;
+					break;
+				}
+			}
+			if(foundflag){
+				nLoc=i;
+				return(this);
+			}
+		}
+	}
+	nLoc = -1;
+	return(NULL);
+}
+
+BCMenu *BCMenu::FindMenuOption(int nId,int& nLoc)
+{
+	int i;
+	BCMenu *psubmenu,*pgoodmenu;
+	
+	for(i=0;i<(int)(GetMenuItemCount());++i){
+#ifdef _CPPRTTI 
+		psubmenu=dynamic_cast<BCMenu *>(GetSubMenu(i));
+#else
+		psubmenu=(BCMenu *)GetSubMenu(i);
+#endif
+		if(psubmenu){
+			pgoodmenu=psubmenu->FindMenuOption(nId,nLoc);
+			if(pgoodmenu)return(pgoodmenu);
+		}
+		else if(nId==(int)GetMenuItemID(i)){
+			nLoc=i;
+			return(this);
+		}
+	}
+	nLoc = -1;
+	return(NULL);
+}
+
+BCMenuData *BCMenu::FindMenuOption(wchar_t *lpstrText)
+{
+	int i,j;
+	BCMenu *psubmenu;
+	BCMenuData *pmenulist;
+	
+	for(i=0;i<(int)(GetMenuItemCount());++i){
+#ifdef _CPPRTTI 
+		psubmenu=dynamic_cast<BCMenu *>(GetSubMenu(i));
+#else
+		psubmenu=(BCMenu *)GetSubMenu(i);
+#endif
+		if(psubmenu){
+			pmenulist=psubmenu->FindMenuOption(lpstrText);
+			if(pmenulist)return(pmenulist);
+		}
+		else{
+			const wchar_t *szWide;//SK: we use const to prevent misuse of this Ptr
+			for(j=0;j<=m_MenuList.GetUpperBound();++j){     
+				szWide = m_MenuList[j]->GetWideString ();
+				if(szWide && !wcscmp(lpstrText,szWide))//SK: modified for dynamic allocation
+					return(m_MenuList[j]);
+			}
+		}
+	}
+	return(NULL);
+}
+
+
+BOOL BCMenu::LoadMenu(int nResource)
+{
+	return(BCMenu::LoadMenu(MAKEINTRESOURCE(nResource)));
+};
+
+BOOL BCMenu::LoadMenu(LPCTSTR lpszResourceName)
+{
+	ASSERT_VALID(this);
+	ASSERT(lpszResourceName != NULL);
+	
+	// Find the Menu Resource:
+	HINSTANCE hInst = AfxFindResourceHandle(lpszResourceName,RT_MENU);
+	HRSRC hRsrc = ::FindResource(hInst,lpszResourceName,RT_MENU);
+	if (hRsrc == NULL){
+		hInst = NULL;
+		hRsrc = ::FindResource(hInst,lpszResourceName,RT_MENU);
+	}
+	if(hRsrc == NULL)return FALSE;
+	
+	// Load the Menu Resource:
+	
+	HGLOBAL hGlobal = LoadResource(hInst, hRsrc);
+	if(hGlobal == NULL)return FALSE;
+
+	// first destroy the menu if we're trying to loadmenu again
+	DestroyMenu();
+
+	// Attempt to create us as a menu...
+	if(!CMenu::CreateMenu())return FALSE;
+	
+	// Get Item template Header, and calculate offset of MENUITEMTEMPLATES
+	
+	MENUITEMTEMPLATEHEADER *pTpHdr=
+		(MENUITEMTEMPLATEHEADER*)LockResource(hGlobal);
+	BYTE* pTp=(BYTE*)pTpHdr + 
+		(sizeof(MENUITEMTEMPLATEHEADER) + pTpHdr->offset);
+	
+	
+	// Variables needed during processing of Menu Item Templates:
+	
+	int j=0;
+	WORD    dwFlags = 0;              // Flags of the Menu Item
+	WORD    dwID  = 0;              // ID of the Menu Item
+	UINT    uFlags;                  // Actual Flags.
+	wchar_t *szCaption=NULL;
+	int      nLen   = 0;                // Length of caption
+	CTypedPtrArray<CPtrArray, BCMenu*>  m_Stack;    // Popup menu stack
+	CArray<BOOL,BOOL>  m_StackEnd;    // Popup menu stack
+	m_Stack.Add(this);                  // Add it to this...
+	m_StackEnd.Add(FALSE);
+	
+	do{
+		// Obtain Flags and (if necessary), the ID...
+		memcpy(&dwFlags, pTp, sizeof(WORD));pTp+=sizeof(WORD);// Obtain Flags
+		if(!(dwFlags & MF_POPUP)){
+			memcpy(&dwID, pTp, sizeof(WORD)); // Obtain ID
+			pTp+=sizeof(WORD);
+		}
+		else dwID = 0;
+		
+		uFlags = (UINT)dwFlags; // Remove MF_END from the flags that will
+		if(uFlags & MF_END) // be passed to the Append(OD)Menu functions.
+			uFlags -= MF_END;
+		
+		// Obtain Caption (and length)
+		
+		nLen = 0;
+		szCaption=new wchar_t[wcslen((wchar_t *)pTp)+1];
+		wcscpy(szCaption,(wchar_t *)pTp);
+		pTp=&pTp[(wcslen((wchar_t *)pTp)+1)*sizeof(wchar_t)];//modified SK
+		
+		// Handle popup menus first....
+		
+		//WideCharToMultiByte
+		if(dwFlags & MF_POPUP){
+			if(dwFlags & MF_END)m_StackEnd.SetAt(m_Stack.GetUpperBound(),TRUE);
+			BCMenu* pSubMenu = new BCMenu;
+			pSubMenu->m_unselectcheck=m_unselectcheck;
+			pSubMenu->m_selectcheck=m_selectcheck;
+			pSubMenu->checkmaps=checkmaps;
+			pSubMenu->checkmapsshare=TRUE;
+			pSubMenu->CreatePopupMenu();
+			
+			// Append it to the top of the stack:
+			
+			m_Stack[m_Stack.GetUpperBound()]->AppendODMenuW(szCaption,uFlags,
+				(UINT)pSubMenu->m_hMenu, -1);
+			m_Stack.Add(pSubMenu);
+			m_StackEnd.Add(FALSE);
+		}
+		else {
+			m_Stack[m_Stack.GetUpperBound()]->AppendODMenuW(szCaption, uFlags,
+				dwID, -1);
+			if(dwFlags & MF_END)m_StackEnd.SetAt(m_Stack.GetUpperBound(),TRUE);
+			j = m_Stack.GetUpperBound();
+			while(j>=0 && m_StackEnd.GetAt(j)){
+				m_Stack[m_Stack.GetUpperBound()]->InsertSpaces();
+				m_Stack.RemoveAt(j);
+				m_StackEnd.RemoveAt(j);
+				--j;
+			}
+		}
+		
+		delete[] szCaption;
+	}while(m_Stack.GetUpperBound() != -1);
+	
+	for(int i=0;i<(int)GetMenuItemCount();++i){
+		CString str=m_MenuList[i]->GetString();
+		if(GetSubMenu(i)){
+			m_MenuList[i]->nFlags=MF_POPUP|MF_BYPOSITION;
+			ModifyMenu(i,MF_POPUP|MF_BYPOSITION,
+				(UINT)GetSubMenu(i)->m_hMenu,str);
+		}
+		else{
+			m_MenuList[i]->nFlags=MF_STRING|MF_BYPOSITION;
+			ModifyMenu(i,MF_STRING|MF_BYPOSITION,m_MenuList[i]->nID,str);
+		}
+	}
+
+	m_loadmenu=TRUE;
+	
+	return(TRUE);
+}
+
+int BCMenu::GetMenuStart(void)
+{
+	if(!m_loadmenu)return(0);
+
+	CString name,str;
+	int menuloc=-1,listloc=-1,menustart=0,i=0,j=0;
+	int nummenulist=m_MenuList.GetSize();
+	int nummenu=(int)GetMenuItemCount();
+
+	while(i<nummenu&&menuloc==-1){
+		GetMenuString (i, name, MF_BYPOSITION);
+		if(name.GetLength()>0){
+			for(j=0;j<nummenulist;++j){
+				str=m_MenuList[j]->GetString();
+				if(name==str){
+					menuloc=i;
+					listloc=j;
+					break;
+				}
+			}
+		}
+		++i;
+	}
+	if(menuloc>=0&&listloc>=0&&menuloc>=listloc)menustart=menuloc-listloc;
+	return(menustart);
+}
+
+void BCMenu::RemoveTopLevelOwnerDraw(void)
+{
+	CString str;
+	int i=0,j=0;
+	int nummenulist=m_MenuList.GetSize(),menustart;
+
+	menustart=GetMenuStart();
+	for(i=menustart,j=0;i<(int)GetMenuItemCount();++i,++j){
+		if(j<nummenulist){
+			str=m_MenuList[j]->GetString();
+			if(GetSubMenu(i)){
+				m_MenuList[j]->nFlags=MF_POPUP|MF_BYPOSITION;
+				ModifyMenu(i,MF_POPUP|MF_BYPOSITION,
+					(UINT)GetSubMenu(i)->m_hMenu,str);
+			}
+		}
+	}
+
+}
+
+void BCMenu::InsertSpaces(void)
+{
+	int i,j,numitems,maxlength;
+	CString string,newstring;
+	CSize t;
+	CFont m_fontMenu;
+	LOGFONT m_lf;
+	
+	ZeroMemory ((PVOID) &m_lf,sizeof (LOGFONT));
+	NONCLIENTMETRICS nm;
+	nm.cbSize = sizeof (NONCLIENTMETRICS);
+	VERIFY (SystemParametersInfo (SPI_GETNONCLIENTMETRICS,nm.cbSize,&nm,0)); 
+	m_lf =  nm.lfMenuFont;
+	m_fontMenu.CreateFontIndirect (&m_lf);
+	
+	CWnd *pWnd = AfxGetMainWnd();  
+	if (pWnd == NULL)pWnd = CWnd::GetDesktopWindow();
+	CDC *pDC = pWnd->GetDC();
+	CFont* pFont = pDC->SelectObject (&m_fontMenu);
+	
+	numitems=GetMenuItemCount();
+	maxlength = -1;
+	for(i=0;i<numitems;++i){
+		string=m_MenuList[i]->GetString();
+		j=string.Find((char)9);
+		newstring.Empty();
+		if(j!=-1)newstring=string.Left(j);
+		else newstring=string;
+		newstring+=_T(" ");//SK: modified for Unicode correctness. 
+		LPCTSTR lpstrText = (LPCTSTR)newstring;
+		t=pDC->GetTextExtent(lpstrText,_tcslen(lpstrText));
+		if(t.cx>maxlength)maxlength = t.cx;
+	}
+	for(i=0;i<numitems;++i){
+		string=m_MenuList[i]->GetString();
+		j=string.Find((char)9);
+		if(j!=-1){
+			newstring.Empty();
+			newstring=string.Left(j);
+			LPCTSTR lpstrText = (LPCTSTR)(newstring);
+			t=pDC->GetTextExtent(lpstrText,_tcslen(lpstrText));
+			while(t.cx<maxlength){
+				newstring+=_T(' ');//SK: modified for Unicode correctness
+				LPCTSTR lpstrText = (LPCTSTR)(newstring);
+				t=pDC->GetTextExtent(lpstrText,_tcslen(lpstrText));
+			}
+			newstring+=string.Mid(j);
+#ifdef UNICODE      
+			m_MenuList[i]->SetWideString(newstring);//SK: modified for dynamic allocation
+#else
+			m_MenuList[i]->SetAnsiString(newstring);
+#endif
+		}
+	}
+	pDC->SelectObject (pFont);              // Select old font in
+	pWnd->ReleaseDC(pDC);       // Release the DC
+	m_fontMenu.DeleteObject();
+}
+
+void BCMenu::LoadCheckmarkBitmap(int unselect, int select)
+{
+	if(unselect>0 && select>0){
+		m_selectcheck=select;
+		m_unselectcheck=unselect;
+		if(checkmaps)checkmaps->DeleteImageList();
+		else checkmaps=new(CImageList);
+		checkmaps->Create(m_iconX,m_iconY,ILC_MASK,2,1);
+		BOOL flag1=AddBitmapToImageList(checkmaps,unselect);
+		BOOL flag2=AddBitmapToImageList(checkmaps,select);
+		if(!flag1||!flag2){
+			checkmaps->DeleteImageList();
+			delete checkmaps;
+			checkmaps=NULL;
+		}
+	}
+}
+
+//--------------------------------------------------------------------------
+//[18.06.99 rj]
+BOOL BCMenu::GetMenuText(UINT id, CString& string, UINT nFlags/*= MF_BYPOSITION*/)
+{
+	BOOL returnflag=FALSE;
+	
+	if(MF_BYPOSITION&nFlags){
+		UINT numMenuItems = m_MenuList.GetUpperBound();
+		if(id<=numMenuItems){
+			string=m_MenuList[id]->GetString();
+			returnflag=TRUE;
+		}
+	}
+	else{
+		int uiLoc;
+		BCMenu* pMenu = FindMenuOption(id,uiLoc);
+		if(NULL!=pMenu) returnflag = pMenu->GetMenuText(uiLoc,string);
+	}
+	return(returnflag);
+}
+
+
+void BCMenu::DrawRadioDot(CDC *pDC,int x,int y,COLORREF color)
+{
+	CRect rcDot(x,y,x+6,y+6);
+	CBrush brush;
+	CPen pen;
+	brush.CreateSolidBrush(color);
+	pen.CreatePen(PS_SOLID,0,color);
+	CBrush *pOldBrush=pDC->SelectObject(&brush);
+	CPen *pOldPen=pDC->SelectObject(&pen);
+	pDC->Ellipse(&rcDot);
+	pDC->SelectObject(pOldBrush);
+	pDC->SelectObject(pOldPen);
+	pen.DeleteObject();
+	brush.DeleteObject();
+}
+
+void BCMenu::DrawCheckMark(CDC* pDC,int x,int y,COLORREF color)
+{
+	CPen m_penBack;
+	m_penBack.CreatePen (PS_SOLID,0,color);
+	CPen *pOldPen = pDC->SelectObject (&m_penBack);
+	pDC->MoveTo(x,y+2);
+	pDC->LineTo(x,y+5);
+	
+	pDC->MoveTo(x+1,y+3);
+	pDC->LineTo(x+1,y+6);
+	
+	pDC->MoveTo(x+2,y+4);
+	pDC->LineTo(x+2,y+7);
+	
+	pDC->MoveTo(x+3,y+3);
+	pDC->LineTo(x+3,y+6);
+	
+	pDC->MoveTo(x+4,y+2);
+	pDC->LineTo(x+4,y+5);
+	
+	pDC->MoveTo(x+5,y+1);
+	pDC->LineTo(x+5,y+4);
+	
+	pDC->MoveTo(x+6,y);
+	pDC->LineTo(x+6,y+3);
+	
+	pDC->SelectObject (pOldPen);
+	m_penBack.DeleteObject();
+}
+
+BCMenuData *BCMenu::FindMenuList(UINT nID)
+{
+	for(int i=0;i<=m_MenuList.GetUpperBound();++i){
+		if(m_MenuList[i]->nID==nID && !m_MenuList[i]->syncflag){
+			m_MenuList[i]->syncflag=1;
+			return(m_MenuList[i]);
+		}
+	}
+	return(NULL);
+}
+
+void BCMenu::InitializeMenuList(int value)
+{
+	for(int i=0;i<=m_MenuList.GetUpperBound();++i)
+		m_MenuList[i]->syncflag=value;
+}
+
+void BCMenu::DeleteMenuList(void)
+{
+	for(int i=0;i<=m_MenuList.GetUpperBound();++i){
+		if(!m_MenuList[i]->syncflag){
+			delete m_MenuList[i];
+		}
+	}
+}
+
+void BCMenu::SynchronizeMenu(void)
+{
+	CTypedPtrArray<CPtrArray, BCMenuData*> temp;
+	BCMenuData *mdata;
+	CString string;
+	UINT submenu,nID=0,state,j;
+	
+	InitializeMenuList(0);
+	for(j=0;j<GetMenuItemCount();++j){
+		mdata=NULL;
+		state=GetMenuState(j,MF_BYPOSITION);
+		if(state&MF_POPUP){
+			submenu=(UINT)GetSubMenu(j)->m_hMenu;
+			mdata=FindMenuList(submenu);
+			GetMenuString(j,string,MF_BYPOSITION);
+			if(!mdata)mdata=NewODMenu(j,
+				(state&0xFF)|MF_BYPOSITION|MF_POPUP|MF_OWNERDRAW,submenu,string);
+			else if(string.GetLength()>0)
+#ifdef UNICODE
+				mdata->SetWideString(string);  //SK: modified for dynamic allocation
+#else
+			mdata->SetAnsiString(string);
+#endif
+		}
+		else if(state&MF_SEPARATOR){
+			mdata=FindMenuList(0);
+			if(!mdata)mdata=NewODMenu(j,
+				state|MF_BYPOSITION|MF_SEPARATOR|MF_OWNERDRAW,0,_T(""));//SK: modified for Unicode correctness
+			else ModifyMenu(j,mdata->nFlags,nID,(LPCTSTR)mdata);
+		}
+		else{
+			nID=GetMenuItemID(j);
+			mdata=FindMenuList(nID);
+			GetMenuString(j,string,MF_BYPOSITION);
+			if(!mdata)mdata=NewODMenu(j,state|MF_BYPOSITION|MF_OWNERDRAW,
+				nID,string);
+			else{
+				mdata->nFlags=state|MF_BYPOSITION|MF_OWNERDRAW;
+				if(string.GetLength()>0)
+#ifdef UNICODE
+					mdata->SetWideString(string);//SK: modified for dynamic allocation
+#else
+				mdata->SetAnsiString(string);
+#endif
+				
+				ModifyMenu(j,mdata->nFlags,nID,(LPCTSTR)mdata);
+			}
+		}
+		if(mdata)temp.Add(mdata);
+	}
+	DeleteMenuList();
+	m_MenuList.RemoveAll();
+	m_MenuList.Append(temp);
+	temp.RemoveAll(); 
+}
+
+void BCMenu::UpdateMenu(CMenu *pmenu)
+{
+#ifdef _CPPRTTI 
+	BCMenu *psubmenu = dynamic_cast<BCMenu *>(pmenu);
+#else
+	BCMenu *psubmenu = (BCMenu *)pmenu;
+#endif
+	if(psubmenu)psubmenu->SynchronizeMenu();
+}
+
+LRESULT BCMenu::FindKeyboardShortcut(UINT nChar, UINT nFlags,
+                                     CMenu *pMenu)
+{
+#ifdef _CPPRTTI 
+	BCMenu *pBCMenu = dynamic_cast<BCMenu *>(pMenu);
+#else
+	BCMenu *pBCMenu = (BCMenu *)pMenu;
+#endif
+	if(pBCMenu && nFlags&MF_POPUP){
+		CString key(_T('&'),2);//SK: modified for Unicode correctness
+		key.SetAt(1,(TCHAR)nChar);
+		key.MakeLower();
+		CString menutext;
+		int menusize = (int)pBCMenu->GetMenuItemCount();
+		if(menusize!=(pBCMenu->m_MenuList.GetUpperBound()+1))
+			pBCMenu->SynchronizeMenu();
+		for(int i=0;i<menusize;++i){
+			if(pBCMenu->GetMenuText(i,menutext)){
+				menutext.MakeLower();
+				if(menutext.Find(key)>=0)return(MAKELRESULT(i,2));
+			}
+		}
+	}
+	return(0);
+}
+
+void BCMenu::DitherBlt (HDC hdcDest, int nXDest, int nYDest, int nWidth, 
+                        int nHeight, HBITMAP hbm, int nXSrc, int nYSrc,
+						COLORREF bgcolor)
+{
+	ASSERT(hdcDest && hbm);
+	ASSERT(nWidth > 0 && nHeight > 0);
+	
+	// Create a generic DC for all BitBlts
+	HDC hDC = CreateCompatibleDC(hdcDest);
+	ASSERT(hDC);
+	
+	if (hDC)
+	{
+		// Create a DC for the monochrome DIB section
+		HDC bwDC = CreateCompatibleDC(hDC);
+		ASSERT(bwDC);
+		
+		if (bwDC)
+		{
+			// Create the monochrome DIB section with a black and white palette
+			struct {
+				BITMAPINFOHEADER bmiHeader; 
+				RGBQUAD      bmiColors[2]; 
+			} RGBBWBITMAPINFO = {
+				
+				{    // a BITMAPINFOHEADER
+					sizeof(BITMAPINFOHEADER),  // biSize 
+						nWidth,         // biWidth; 
+						nHeight,        // biHeight; 
+						1,            // biPlanes; 
+						1,            // biBitCount 
+						BI_RGB,         // biCompression; 
+						0,            // biSizeImage; 
+						0,            // biXPelsPerMeter; 
+						0,            // biYPelsPerMeter; 
+						0,            // biClrUsed; 
+						0            // biClrImportant; 
+				},    
+				{
+					{ 0x00, 0x00, 0x00, 0x00 }, { 0xFF, 0xFF, 0xFF, 0x00 }
+					} 
+			};
+			VOID *pbitsBW;
+			HBITMAP hbmBW = CreateDIBSection(bwDC,
+				(LPBITMAPINFO)&RGBBWBITMAPINFO, DIB_RGB_COLORS, &pbitsBW, NULL, 0);
+			ASSERT(hbmBW);
+			
+			if (hbmBW)
+			{
+				// Attach the monochrome DIB section and the bitmap to the DCs
+				HBITMAP olddib = (HBITMAP)SelectObject(bwDC, hbmBW);
+				HBITMAP hdcolddib = (HBITMAP)SelectObject(hDC, hbm);
+				
+				// BitBlt the bitmap into the monochrome DIB section
+				BitBlt(bwDC, 0, 0, nWidth, nHeight, hDC, nXSrc, nYSrc, SRCCOPY);
+				
+				// Paint the destination rectangle in gray
+				FillRect(hdcDest, CRect(nXDest, nYDest, nXDest + nWidth, nYDest +
+					nHeight), GetSysColorBrush(bgcolor));
+				//SK: looks better on the old shell
+				// BitBlt the black bits in the monochrome bitmap into COLOR_3DHILIGHT
+				// bits in the destination DC
+				// The magic ROP comes from the Charles Petzold's book
+				HBRUSH hb = CreateSolidBrush(GetSysColor(COLOR_3DHILIGHT));
+				HBRUSH oldBrush = (HBRUSH)SelectObject(hdcDest, hb);
+				BitBlt(hdcDest,nXDest+1,nYDest+1,nWidth,nHeight,bwDC,0,0,0xB8074A);
+				
+				// BitBlt the black bits in the monochrome bitmap into COLOR_3DSHADOW
+				// bits in the destination DC
+				hb = CreateSolidBrush(GetSysColor(COLOR_3DSHADOW));
+				DeleteObject(SelectObject(hdcDest, hb));
+				BitBlt(hdcDest, nXDest, nYDest, nWidth, nHeight,bwDC,0,0,0xB8074A);
+				DeleteObject(SelectObject(hdcDest, oldBrush));
+				VERIFY(DeleteObject(SelectObject(bwDC, olddib)));
+				SelectObject(hDC, hdcolddib);
+			}
+			
+			VERIFY(DeleteDC(bwDC));
+		}
+		
+		VERIFY(DeleteDC(hDC));
+	}
+}
+
+void BCMenu::GetFadedBitmap(CBitmap &bmp)
+{
+	CDC ddc;
+	COLORREF bgcol,col;
+	BITMAP BitMap;
+
+	bmp.GetBitmap(&BitMap);
+	ddc.CreateCompatibleDC(NULL);
+	CBitmap * pddcOldBmp = ddc.SelectObject(&bmp);
+
+	// use this to get the background color, takes into account color shifting
+	CDC ddc2;
+	CBrush brush;
+	CBitmap bmp2;
+	ddc2.CreateCompatibleDC(NULL);
+	bmp2.CreateCompatibleBitmap(&ddc,BitMap.bmWidth,BitMap.bmHeight);
+	col=GetSysColor(COLOR_3DFACE);
+	brush.CreateSolidBrush(col);
+	CBitmap * pddcOldBmp2 = ddc2.SelectObject(&bmp2);
+	CRect rect(0,0,BitMap.bmWidth,BitMap.bmHeight);
+	ddc2.FillRect(rect,&brush);
+	bgcol=ddc2.GetPixel(1,1);
+	brush.DeleteObject();
+	ddc2.SelectObject(pddcOldBmp2);
+
+	for(int i=0;i<BitMap.bmWidth;++i){
+		for(int j=0;j<BitMap.bmHeight;++j){
+			col=ddc.GetPixel(i,j);
+			if(col!=bgcol)ddc.SetPixel(i,j,LightenColor(col,0.3));
+		}
+	}
+	ddc.SelectObject(pddcOldBmp);
+}
+
+void BCMenu::GetShadowBitmap(CBitmap &bmp)
+{
+	CDC ddc;
+	COLORREF bgcol,col,shadowcol=GetSysColor(COLOR_BTNSHADOW);
+	BITMAP BitMap;
+
+	if(!IsWinXPLuna())shadowcol=LightenColor(shadowcol,0.49);
+	bmp.GetBitmap(&BitMap);
+	ddc.CreateCompatibleDC(NULL);
+	CBitmap * pddcOldBmp = ddc.SelectObject(&bmp);
+
+	// use this to get the background color, takes into account color shifting
+	CDC ddc2;
+	CBrush brush;
+	CBitmap bmp2;
+	ddc2.CreateCompatibleDC(NULL);
+	bmp2.CreateCompatibleBitmap(&ddc,BitMap.bmWidth,BitMap.bmHeight);
+	col=GetSysColor(COLOR_3DFACE);
+	brush.CreateSolidBrush(col);
+	CBitmap * pddcOldBmp2 = ddc2.SelectObject(&bmp2);
+	CRect rect(0,0,BitMap.bmWidth,BitMap.bmHeight);
+	ddc2.FillRect(rect,&brush);
+	bgcol=ddc2.GetPixel(1,1);
+	brush.DeleteObject();
+	ddc2.SelectObject(pddcOldBmp2);
+
+	for(int i=0;i<BitMap.bmWidth;++i){
+		for(int j=0;j<BitMap.bmHeight;++j){
+			col=ddc.GetPixel(i,j);
+			if(col!=bgcol)ddc.SetPixel(i,j,shadowcol);
+		}
+	}
+	ddc.SelectObject(pddcOldBmp);
+}
+
+
+BOOL BCMenu::AddBitmapToImageList(CImageList *bmplist,UINT nResourceID)
+{
+	BOOL bReturn=FALSE;
+
+	// O.S.
+	if (m_bDynIcons){
+		bmplist->Add((HICON)nResourceID);
+		bReturn=TRUE;
+	}
+	else{
+		HBITMAP hbmp=LoadSysColorBitmap(nResourceID);
+		if(hbmp){
+			CBitmap bmp;
+			bmp.Attach(hbmp);
+			if(m_bitmapBackgroundFlag){
+				if(bmplist->Add(&bmp,m_bitmapBackground)>=0)bReturn=TRUE;
+			}
+			else{
+				if(bmplist->Add(&bmp,GetSysColor(COLOR_3DFACE))>=0)bReturn=TRUE;
+			}
+			bmp.Detach();
+			DeleteObject(hbmp);
+		}
+		else{
+			CBitmap mybmp;
+			if(mybmp.LoadBitmap(nResourceID)){
+				if(m_bitmapBackgroundFlag){
+					if(bmplist->Add(&mybmp,m_bitmapBackground)>=0)bReturn=TRUE;
+				}
+				else{
+					if(bmplist->Add(&mybmp,GetSysColor(COLOR_3DFACE))>=0)bReturn=TRUE;
+				}
+			}
+		}
+	}
+	if(bReturn&&IsLunaMenuStyle()&&xp_draw_3D_bitmaps){
+		CWnd *pWnd = AfxGetMainWnd();            // Get main window
+		if (pWnd == NULL) pWnd = CWnd::GetDesktopWindow();
+		CDC *pDC = pWnd->GetDC();              // Get device context
+		CBitmap bmp,bmp2;
+		GetBitmapFromImageList(pDC,bmplist,0,bmp);
+		GetFadedBitmap(bmp);
+		bmplist->Add(&bmp,GetSysColor(COLOR_3DFACE));
+		GetBitmapFromImageList(pDC,bmplist,0,bmp2);
+		GetShadowBitmap(bmp2);
+		bmplist->Add(&bmp2,GetSysColor(COLOR_3DFACE));
+		pWnd->ReleaseDC(pDC);  // Release the DC
+	}
+	return(bReturn);
+}
+
+void BCMenu::SetBitmapBackground(COLORREF color)
+{
+	m_bitmapBackground=color;
+	m_bitmapBackgroundFlag=TRUE;
+}
+
+void BCMenu::UnSetBitmapBackground(void)
+{
+	m_bitmapBackgroundFlag=FALSE;
+}
+
+// Given a toolbar, append all the options from it to this menu
+// Passed a ptr to the toolbar object and the toolbar ID
+// Author : Robert Edward Caldecott
+void BCMenu::AddFromToolBar(CToolBar* pToolBar, int nResourceID)
+{
+	for (int i = 0; i < pToolBar->GetCount(); i++) {
+		UINT nID = pToolBar->GetItemID(i);
+		// See if this toolbar option
+		// appears as a command on this
+		// menu or is a separator
+		if (nID == 0 || GetMenuState(nID, MF_BYCOMMAND) == 0xFFFFFFFF)
+			continue; // Item doesn't exist
+		UINT nStyle;
+		int nImage;
+		// Get the toolbar button info
+		pToolBar->GetButtonInfo(i, nID, nStyle, nImage);
+		// OK, we have the command ID of the toolbar
+		// option, and the tollbar bitmap offset
+		int nLoc;
+		BCMenuData* pData;
+		BCMenu *pSubMenu = FindMenuOption(nID, nLoc);
+		if (pSubMenu && nLoc >= 0)pData = pSubMenu->m_MenuList[nLoc];
+		else {
+			// Create a new BCMenuData structure
+			pData = new BCMenuData;
+			m_MenuList.Add(pData);
+		}
+		// Set some default structure members
+		pData->menuIconNormal = nResourceID;
+		pData->nID = nID;
+		pData->nFlags =  MF_BYCOMMAND | MF_OWNERDRAW;
+		pData->xoffset = nImage;
+		if (pData->bitmap)pData->bitmap->DeleteImageList();
+		else pData->bitmap = new CImageList;
+		pData->bitmap->Create(m_iconX, m_iconY,ILC_COLORDDB|ILC_MASK, 1, 1);
+		
+		if(!AddBitmapToImageList(pData->bitmap, nResourceID)){
+			pData->bitmap->DeleteImageList();
+			delete pData->bitmap;
+			pData->bitmap=NULL;
+			pData->menuIconNormal = -1;
+			pData->xoffset = -1;
+		}
+		
+		// Modify our menu
+		ModifyMenu(nID,pData->nFlags,nID,(LPCTSTR)pData);
+	}
+}
+
+BOOL BCMenu::Draw3DCheckmark(CDC *dc, const CRect& rc,
+                             BOOL bSelected, HBITMAP hbmCheck)
+{
+	CRect rcDest = rc;
+	CBrush brush;
+	COLORREF col;
+	if(IsWinXPLuna())col=GetSysColor(COLOR_3DFACE);
+	else col=GetSysColor(COLOR_MENU);
+	if(!bSelected)col = LightenColor(col,0.6);
+	brush.CreateSolidBrush(col);
+	dc->FillRect(rcDest,&brush);
+	brush.DeleteObject();
+	if (IsNewShell()) //SK: looks better on the old shell
+		dc->DrawEdge(&rcDest, BDR_SUNKENOUTER, BF_RECT);
+	if (!hbmCheck)DrawCheckMark(dc,rc.left+4,rc.top+4,GetSysColor(COLOR_MENUTEXT));
+	else DrawRadioDot(dc,rc.left+5,rc.top+4,GetSysColor(COLOR_MENUTEXT));
+	return TRUE;
+}
+
+BOOL BCMenu::DrawXPCheckmark(CDC *dc, const CRect& rc, HBITMAP hbmCheck,COLORREF &colorout)
+{
+	CBrush brushin;
+	brushin.CreateSolidBrush(LightenColor(colorout,0.85));
+	dc->FillRect(rc,&brushin);
+	brushin.DeleteObject();
+	dc->Draw3dRect (rc,colorout,colorout);
+	if (!hbmCheck)DrawCheckMark(dc,rc.left+5,rc.top+4,GetSysColor(COLOR_MENUTEXT));
+	else DrawRadioDot(dc,rc.left+5,rc.top+4,GetSysColor(COLOR_MENUTEXT));
+	return TRUE;
+}
+
+void BCMenu::DitherBlt2(CDC *drawdc, int nXDest, int nYDest, int nWidth, 
+                        int nHeight, CBitmap &bmp, int nXSrc, int nYSrc,
+						COLORREF bgcolor)
+{
+	// create a monochrome memory DC
+	CDC ddc;
+	ddc.CreateCompatibleDC(0);
+	CBitmap bwbmp;
+	bwbmp.CreateCompatibleBitmap(&ddc, nWidth, nHeight);
+	CBitmap * pddcOldBmp = ddc.SelectObject(&bwbmp);
+	
+	CDC dc;
+	dc.CreateCompatibleDC(0);
+	CBitmap * pdcOldBmp = dc.SelectObject(&bmp);
+	
+	// build a mask
+	ddc.PatBlt(0, 0, nWidth, nHeight, WHITENESS);
+	dc.SetBkColor(GetSysColor(COLOR_BTNFACE));
+	ddc.BitBlt(0, 0, nWidth, nHeight, &dc, nXSrc,nYSrc, SRCCOPY);
+	dc.SetBkColor(GetSysColor(COLOR_BTNHILIGHT));
+	ddc.BitBlt(0, 0, nWidth, nHeight, &dc, nXSrc,nYSrc, SRCPAINT);
+	
+	// Copy the image from the toolbar into the memory DC
+	// and draw it (grayed) back into the toolbar.
+	dc.FillSolidRect(0,0, nWidth, nHeight, bgcolor);
+	//SK: Looks better on the old shell
+	dc.SetBkColor(RGB(0, 0, 0));
+	dc.SetTextColor(RGB(255, 255, 255));
+	CBrush brShadow, brHilight;
+	brHilight.CreateSolidBrush(GetSysColor(COLOR_BTNHILIGHT));
+	brShadow.CreateSolidBrush(GetSysColor(COLOR_BTNSHADOW));
+	CBrush * pOldBrush = dc.SelectObject(&brHilight);
+	dc.BitBlt(0,0, nWidth, nHeight, &ddc, 0, 0, 0x00E20746L);
+	drawdc->BitBlt(nXDest+1,nYDest+1,nWidth, nHeight, &dc,0,0,SRCCOPY);
+	dc.BitBlt(1,1, nWidth, nHeight, &ddc, 0, 0, 0x00E20746L);
+	dc.SelectObject(&brShadow);
+	dc.BitBlt(0,0, nWidth, nHeight, &ddc, 0, 0, 0x00E20746L);
+	drawdc->BitBlt(nXDest,nYDest,nWidth, nHeight, &dc,0,0,SRCCOPY);
+	// reset DCs
+	ddc.SelectObject(pddcOldBmp);
+	ddc.DeleteDC();
+	dc.SelectObject(pOldBrush);
+	dc.SelectObject(pdcOldBmp);
+	dc.DeleteDC();
+	
+	brShadow.DeleteObject();
+	brHilight.DeleteObject();
+	bwbmp.DeleteObject();
+}
+
+void BCMenu::SetDisableOldStyle(void)
+{
+	disable_old_style=TRUE;
+}
+
+void BCMenu::UnSetDisableOldStyle(void)
+{
+	disable_old_style=FALSE;
+}
+
+BOOL BCMenu::GetDisableOldStyle(void)
+{
+	return(disable_old_style);
+}
+
+
+WORD BCMenu::NumBitmapColors(LPBITMAPINFOHEADER lpBitmap)
+{
+	if ( lpBitmap->biClrUsed != 0)
+		return (WORD)lpBitmap->biClrUsed;
+	
+	switch (lpBitmap->biBitCount){
+		case 1:
+			return 2;
+		case 4:
+			return 16;
+		case 8:
+			return 256;
+		default:
+			return 0;
+	}
+	return 0;
+}
+
+HBITMAP BCMenu::LoadSysColorBitmap(int nResourceId)
+{
+	HINSTANCE hInst = 
+		AfxFindResourceHandle(MAKEINTRESOURCE(nResourceId),RT_BITMAP);
+	HRSRC hRsrc = 
+		::FindResource(hInst,MAKEINTRESOURCE(nResourceId),RT_BITMAP);
+	if (hRsrc == NULL){
+		hInst = NULL;
+		hRsrc = ::FindResource(hInst,MAKEINTRESOURCE(nResourceId),RT_BITMAP);
+	}
+	if (hRsrc == NULL)return NULL;
+
+	// determine how many colors in the bitmap
+	HGLOBAL hglb;
+	if ((hglb = LoadResource(hInst, hRsrc)) == NULL)
+		return NULL;
+	LPBITMAPINFOHEADER lpBitmap = (LPBITMAPINFOHEADER)LockResource(hglb);
+	if (lpBitmap == NULL)return NULL;
+	WORD numcol = NumBitmapColors(lpBitmap);
+	::FreeResource(hglb);
+
+	if(numcol!=16)return(NULL);
+
+	return AfxLoadSysColorBitmap(hInst, hRsrc, FALSE);
+}
+
+BOOL BCMenu::RemoveMenu(UINT uiId,UINT nFlags)
+{
+	if(MF_BYPOSITION&nFlags){
+		UINT uint = GetMenuState(uiId,MF_BYPOSITION);
+		if(uint&MF_SEPARATOR && !(uint&MF_POPUP)){
+			delete m_MenuList.GetAt(uiId);
+			m_MenuList.RemoveAt(uiId);
+		}
+		else{
+			BCMenu* pSubMenu = (BCMenu*) GetSubMenu(uiId);
+			if(NULL==pSubMenu){
+				UINT uiCommandId = GetMenuItemID(uiId);
+				for(int i=0;i<m_MenuList.GetSize(); i++){
+					if(m_MenuList[i]->nID==uiCommandId){
+						delete m_MenuList.GetAt(i);
+						m_MenuList.RemoveAt(i);
+						break;
+					}
+				}
+			}
+			else{
+				int numSubMenus = m_SubMenus.GetUpperBound();
+				for(int m = numSubMenus; m >= 0; m--){
+					if(m_SubMenus[m]==pSubMenu->m_hMenu){
+						int numAllSubMenus = m_AllSubMenus.GetUpperBound();
+						for(int n = numAllSubMenus; n>= 0; n--){
+							if(m_AllSubMenus[n]==m_SubMenus[m])m_AllSubMenus.RemoveAt(n);
+						}
+						m_SubMenus.RemoveAt(m);
+					}
+				}
+				int num = pSubMenu->GetMenuItemCount();
+				for(int i=num-1;i>=0;--i)pSubMenu->RemoveMenu(i,MF_BYPOSITION);
+				for(int i=m_MenuList.GetUpperBound();i>=0;i--){
+					if(m_MenuList[i]->nID==(UINT)pSubMenu->m_hMenu){
+						delete m_MenuList.GetAt(i);
+						m_MenuList.RemoveAt(i);
+						break;
+					}
+				}
+				delete pSubMenu; 
+			}
+		}
+	}
+	else{
+		int iPosition =0;
+		BCMenu* pMenu = FindMenuOption(uiId,iPosition);
+		// bug fix RIA 14th September 2000 
+		// failed to return correct value on call to remove menu as the item was 
+		// removed twice. The second time its not found 
+		// so a value of 0 was being returned 
+		if(pMenu) return pMenu->RemoveMenu(iPosition,MF_BYPOSITION); // added return 
+	}
+	return CMenu::RemoveMenu(uiId,nFlags);
+}
+
+BOOL BCMenu::DeleteMenu(UINT uiId,UINT nFlags)
+{
+	if(MF_BYPOSITION&nFlags){
+		UINT uint = GetMenuState(uiId,MF_BYPOSITION);
+		if(uint&MF_SEPARATOR && !(uint&MF_POPUP)){
+			// make sure it's a separator
+			int menulistsize=m_MenuList.GetSize();	
+			if(uiId<(UINT)menulistsize){
+				CString str=m_MenuList[uiId]->GetString();
+				if(str==""){
+					delete m_MenuList.GetAt(uiId);
+					m_MenuList.RemoveAt(uiId);
+				}
+			}
+		}
+		else{
+			BCMenu* pSubMenu = (BCMenu*) GetSubMenu(uiId);
+			if(NULL==pSubMenu){
+				UINT uiCommandId = GetMenuItemID(uiId);
+				for(int i=0;i<m_MenuList.GetSize(); i++){
+					if(m_MenuList[i]->nID==uiCommandId){
+						delete m_MenuList.GetAt(i);
+						m_MenuList.RemoveAt(i);
+						break;
+					}
+				}
+			}
+			else{
+				int numSubMenus = m_SubMenus.GetUpperBound();
+				for(int m = numSubMenus; m >= 0; m--){
+					if(m_SubMenus[m]==pSubMenu->m_hMenu){
+						int numAllSubMenus = m_AllSubMenus.GetUpperBound();
+						for(int n = numAllSubMenus; n>= 0; n--){
+							if(m_AllSubMenus[n]==m_SubMenus[m])m_AllSubMenus.RemoveAt(n);
+						}
+						m_SubMenus.RemoveAt(m);
+					}
+				}
+				int num = pSubMenu->GetMenuItemCount();
+				for(int i=num-1;i>=0;--i)pSubMenu->DeleteMenu(i,MF_BYPOSITION);
+				for(int i=m_MenuList.GetUpperBound();i>=0;i--){
+					if(m_MenuList[i]->nID==(UINT)pSubMenu->m_hMenu){
+						delete m_MenuList.GetAt(i);
+						m_MenuList.RemoveAt(i);
+						break;
+					}
+				}
+				delete pSubMenu;
+			}
+		}
+	}
+	else{
+		int iPosition =0;
+		BCMenu* pMenu = FindMenuOption(uiId,iPosition);
+		if(pMenu)return pMenu->DeleteMenu(iPosition,MF_BYPOSITION);
+	}
+
+	return(CMenu::DeleteMenu(uiId,nFlags));
+}
+
+
+BOOL BCMenu::AppendMenuA(UINT nFlags,UINT nIDNewItem,const char *lpszNewItem,int nIconNormal)
+{
+	USES_CONVERSION;
+	return AppendMenuW(nFlags,nIDNewItem,A2W(lpszNewItem),nIconNormal);
+}
+
+BOOL BCMenu::AppendMenuW(UINT nFlags,UINT nIDNewItem,wchar_t *lpszNewItem,int nIconNormal)
+{
+	return AppendODMenuW(lpszNewItem,nFlags,nIDNewItem,nIconNormal);
+}
+
+BOOL BCMenu::AppendMenuA(UINT nFlags,UINT nIDNewItem,const char *lpszNewItem,CImageList *il,int xoffset)
+{
+	USES_CONVERSION;
+	return AppendMenuW(nFlags,nIDNewItem,A2W(lpszNewItem),il,xoffset);
+}
+
+BOOL BCMenu::AppendMenuW(UINT nFlags,UINT nIDNewItem,wchar_t *lpszNewItem,CImageList *il,int xoffset)
+{
+	return AppendODMenuW(lpszNewItem,nFlags,nIDNewItem,il,xoffset);
+}
+
+BOOL BCMenu::AppendMenuA(UINT nFlags,UINT nIDNewItem,const char *lpszNewItem,CBitmap *bmp)
+{
+	USES_CONVERSION;
+	return AppendMenuW(nFlags,nIDNewItem,A2W(lpszNewItem),bmp);
+}
+
+BOOL BCMenu::AppendMenuW(UINT nFlags,UINT nIDNewItem,wchar_t *lpszNewItem,CBitmap *bmp)
+{
+	if(bmp){
+		CImageList temp;
+		temp.Create(m_iconX,m_iconY,ILC_COLORDDB|ILC_MASK,1,1);
+		if(m_bitmapBackgroundFlag)temp.Add(bmp,m_bitmapBackground);
+		else temp.Add(bmp,GetSysColor(COLOR_3DFACE));
+		return AppendODMenuW(lpszNewItem,nFlags,nIDNewItem,&temp,0);
+	}
+	return AppendODMenuW(lpszNewItem,nFlags,nIDNewItem,NULL,0);
+}
+
+BOOL BCMenu::InsertMenuA(UINT nPosition,UINT nFlags,UINT nIDNewItem,const char *lpszNewItem,int nIconNormal)
+{
+	USES_CONVERSION;
+	return InsertMenuW(nPosition,nFlags,nIDNewItem,A2W(lpszNewItem),nIconNormal);
+}
+
+BOOL BCMenu::InsertMenuW(UINT nPosition,UINT nFlags,UINT nIDNewItem,wchar_t *lpszNewItem,int nIconNormal)
+{
+	return InsertODMenuW(nPosition,lpszNewItem,nFlags,nIDNewItem,nIconNormal);
+}
+
+BOOL BCMenu::InsertMenuA(UINT nPosition,UINT nFlags,UINT nIDNewItem,const char *lpszNewItem,CImageList *il,int xoffset)
+{
+	USES_CONVERSION;
+	return InsertMenuW(nPosition,nFlags,nIDNewItem,A2W(lpszNewItem),il,xoffset);
+}
+
+BOOL BCMenu::InsertMenuW(UINT nPosition,UINT nFlags,UINT nIDNewItem,wchar_t *lpszNewItem,CImageList *il,int xoffset)
+{
+	return InsertODMenuW(nPosition,lpszNewItem,nFlags,nIDNewItem,il,xoffset);
+}
+
+BOOL BCMenu::InsertMenuA(UINT nPosition,UINT nFlags,UINT nIDNewItem,const char *lpszNewItem,CBitmap *bmp)
+{
+	USES_CONVERSION;
+	return InsertMenuW(nPosition,nFlags,nIDNewItem,A2W(lpszNewItem),bmp);
+}
+
+BOOL BCMenu::InsertMenuW(UINT nPosition,UINT nFlags,UINT nIDNewItem,wchar_t *lpszNewItem,CBitmap *bmp)
+{
+	if(bmp){
+		CImageList temp;
+		temp.Create(m_iconX,m_iconY,ILC_COLORDDB|ILC_MASK,1,1);
+		if(m_bitmapBackgroundFlag)temp.Add(bmp,m_bitmapBackground);
+		else temp.Add(bmp,GetSysColor(COLOR_3DFACE));
+		return InsertODMenuW(nPosition,lpszNewItem,nFlags,nIDNewItem,&temp,0);
+	}
+	return InsertODMenuW(nPosition,lpszNewItem,nFlags,nIDNewItem,NULL,0);
+}
+
+//--------------------------------------------------------------------------
+//[21.06.99 rj]
+BCMenu* BCMenu::AppendODPopupMenuW(wchar_t *lpstrText)
+{
+	BCMenu* pSubMenu = new BCMenu;
+	pSubMenu->m_unselectcheck=m_unselectcheck;
+	pSubMenu->m_selectcheck=m_selectcheck;
+	pSubMenu->checkmaps=checkmaps;
+	pSubMenu->checkmapsshare=TRUE;
+	pSubMenu->CreatePopupMenu();
+	AppendODMenuW(lpstrText,MF_POPUP,(UINT)pSubMenu->m_hMenu, -1);
+	return pSubMenu;
+}
+
+//--------------------------------------------------------------------------
+//[21.06.99 rj]
+BCMenu* BCMenu::AppendODPopupMenuA(LPCSTR lpstrText)
+{
+	USES_CONVERSION;
+	return AppendODPopupMenuW(A2W(lpstrText));
+}
+
+BOOL BCMenu::ImageListDuplicate(CImageList *il,int xoffset,CImageList *newlist)
+{
+	if (il == NULL||newlist==NULL||xoffset<0) return FALSE;
+	HICON hIcon = il->ExtractIcon(xoffset);
+	int cx, cy;
+	ImageList_GetIconSize(il->m_hImageList, &cx, &cy);
+	newlist->Create(cx,cy,ILC_COLORDDB|ILC_MASK,1,1);
+	newlist->Add(hIcon);
+	::DestroyIcon(hIcon);
+	if(IsLunaMenuStyle()&&xp_draw_3D_bitmaps){
+		CWnd *pWnd = AfxGetMainWnd();            // Get main window
+		if (pWnd == NULL) pWnd = CWnd::GetDesktopWindow();
+		CDC *pDC = pWnd->GetDC();              // Get device context
+		CBitmap bmp,bmp2;
+		GetBitmapFromImageList(pDC,newlist,0,bmp);
+		GetFadedBitmap(bmp);
+		newlist->Add(&bmp,GetSysColor(COLOR_3DFACE));
+		GetBitmapFromImageList(pDC,newlist,0,bmp2);
+		GetShadowBitmap(bmp2);
+		newlist->Add(&bmp2,GetSysColor(COLOR_3DFACE));
+		pWnd->ReleaseDC(pDC);  // Release the DC
+	}
+	return TRUE;
+}
+
+// 2001-07-12, Damir Valiulin:
+//          Added GetSubMenu (LPCTSTR lpszSubMenuName) function
+//
+
+CMenu* BCMenu::GetSubMenu(int nPos)
+{
+	return CMenu::GetSubMenu (nPos);
+}
+
+CMenu* BCMenu::GetSubMenu(LPCTSTR lpszSubMenuName)
+{
+	int num = GetMenuItemCount ();
+	CString name;
+	
+	for (int i=0; i<num; i++)
+	{
+		GetMenuString (i, name, MF_BYPOSITION);
+		if (name.Compare (lpszSubMenuName) == 0)
+		{
+			return CMenu::GetSubMenu (i);
+		}
+	}
+	
+	return NULL;
+}
+
+BCMenu* BCMenu::GetSubBCMenu(char* pText)
+{
+	USES_CONVERSION;
+	return GetSubBCMenu(A2W(pText));
+}
+
+BCMenu* BCMenu::GetSubBCMenu(wchar_t* lpszSubMenuName)
+{
+	BCMenuData *mdata;
+	mdata=FindMenuOption(lpszSubMenuName);
+	if(mdata){
+		HMENU bchmenu=(HMENU)mdata->nID;
+		CMenu *ptr=FromHandle(bchmenu);
+		BOOL flag=ptr->IsKindOf(RUNTIME_CLASS( BCMenu ));
+		if(flag)return((BCMenu *)ptr);
+	}
+	return NULL;
+}
+
+
+// Tongzhe Cui, Functions to remove a popup menu based on its name. Seperators
+// before and after the popup menu can also be removed if they exist.
+int BCMenu::GetMenuPosition(char* pText)
+{
+	USES_CONVERSION;
+	return GetMenuPosition(A2W(pText));
+}
+
+int BCMenu::GetMenuPosition(wchar_t* pText)
+{
+	int i,j;
+	BCMenu* psubmenu;
+	for(i=0;i<(int)(GetMenuItemCount());++i)
+	{
+		psubmenu=(BCMenu *)GetSubMenu(i);
+		if(!psubmenu)
+		{
+			const wchar_t *szWide;//SK: we use const to prevent misuse of this Ptr
+			for(j=0;j<=m_MenuList.GetUpperBound();++j)
+			{     
+				szWide = m_MenuList[j]->GetWideString ();
+				if(szWide && !wcscmp(pText,szWide))//SK: modified for dynamic allocation
+					return j;
+			}
+		}
+	}
+	// means no found;
+	return -1;
+}
+
+int BCMenu::RemoveMenu(char* pText, BC_Seperator sPos)
+{
+	USES_CONVERSION;
+	return RemoveMenu(A2W(pText), sPos);
+}
+
+int BCMenu::RemoveMenu(wchar_t* pText, BC_Seperator sPos)
+{
+	int nPos = GetMenuPosition(pText);
+	if(nPos != -1)
+	{
+		RemoveMenu(nPos, MF_BYPOSITION);
+	}
+	if(sPos == BCMENU_HEAD)
+	{
+		ASSERT(nPos - 1 >= 0);
+		RemoveMenu(nPos-1, MF_BYPOSITION);
+	}
+	else if(sPos == BCMENU_TAIL)
+	{
+		RemoveMenu(nPos-1, MF_BYPOSITION);
+	}
+	else if(sPos == BCMENU_BOTH)
+	{
+		// remove the end first;
+		RemoveMenu(nPos-1, MF_BYPOSITION);
+		// remove the head;
+		ASSERT(nPos - 1 >= 0);
+		RemoveMenu(nPos-1, MF_BYPOSITION);
+	}
+	return nPos;
+}
+
+int BCMenu::DeleteMenu(char* pText, BC_Seperator sPos)
+{
+	USES_CONVERSION;
+	return DeleteMenu(A2W(pText), sPos);
+}
+
+int BCMenu::DeleteMenu(wchar_t* pText, BC_Seperator sPos)
+{
+	int nPos = GetMenuPosition(pText);
+	if(nPos != -1)
+	{
+		DeleteMenu(nPos, MF_BYPOSITION);
+	}
+	if(sPos == BCMENU_HEAD)
+	{
+		ASSERT(nPos - 1 >= 0);
+		DeleteMenu(nPos-1, MF_BYPOSITION);
+	}
+	else if(sPos == BCMENU_TAIL)
+	{
+		DeleteMenu(nPos-1, MF_BYPOSITION);
+	}
+	else if(sPos == BCMENU_BOTH)
+	{
+		// remove the end first;
+		DeleteMenu(nPos-1, MF_BYPOSITION);
+		// remove the head;
+		ASSERT(nPos - 1 >= 0);
+		DeleteMenu(nPos-1, MF_BYPOSITION);
+	}
+	return nPos;
+}
+
+// Larry Antram
+BOOL BCMenu::SetMenuText(UINT id, CString string, UINT nFlags/*= MF_BYPOSITION*/ )
+{
+	BOOL returnflag=FALSE;
+	
+	if(MF_BYPOSITION&nFlags)
+	{
+		UINT numMenuItems = m_MenuList.GetUpperBound();
+		if(id<=numMenuItems){
+#ifdef UNICODE
+			m_MenuList[id]->SetWideString((LPCTSTR)string);
+#else
+			m_MenuList[id]->SetAnsiString(string);
+#endif
+			returnflag=TRUE;
+		}
+	}
+	else{
+		int uiLoc;
+		BCMenu* pMenu = FindMenuOption(id,uiLoc);
+		if(NULL!=pMenu) returnflag = pMenu->SetMenuText(uiLoc,string);
+	}
+	return(returnflag);
+}
+
+// courtesy of Warren Stevens
+void BCMenu::ColorBitmap(CDC* pDC,CBitmap& bmp,CSize bitmap_size,CSize icon_size,COLORREF fill,COLORREF border,int hatchstyle)
+{
+	CDC bmpdc;
+	COLORREF m_newclrBack;
+	int x1=0,y1=0,x2=bitmap_size.cx,y2=bitmap_size.cy;
+
+	if(IsWinXPLuna())m_newclrBack=GetSysColor(COLOR_3DFACE);
+	else m_newclrBack=GetSysColor(COLOR_MENU);
+
+	bmpdc.CreateCompatibleDC(pDC);
+
+	bmp.CreateCompatibleBitmap(pDC, icon_size.cx, icon_size.cy);	
+	CBitmap* pOldBitmap = bmpdc.SelectObject(&bmp);
+
+	if(bitmap_size!=icon_size){
+		CBrush background_brush;
+		background_brush.CreateSolidBrush(m_newclrBack);
+		CRect rect(0,0, icon_size.cx, icon_size.cy);
+		bmpdc.FillRect(rect,&background_brush);
+		x1 = (icon_size.cx-bitmap_size.cx)/2;
+		y1 = (icon_size.cy-bitmap_size.cy)/2;
+		x2 = x1+bitmap_size.cx;
+		y2 = y1+bitmap_size.cy;
+		background_brush.DeleteObject();
+	}
+	
+	CPen border_pen(PS_SOLID, 1, border);
+	CBrush fill_brush;
+	if(hatchstyle!=-1) { fill_brush.CreateHatchBrush(hatchstyle, fill); }
+	else      { fill_brush.CreateSolidBrush(fill);             }
+	
+	CPen*    pOldPen    = bmpdc.SelectObject(&border_pen);
+	CBrush*  pOldBrush  = bmpdc.SelectObject(&fill_brush);
+
+	bmpdc.Rectangle(x1,y1,x2,y2);
+
+	if(NULL!=pOldBrush)  { bmpdc.SelectObject(pOldBrush);  }
+	if(NULL!=pOldPen)    { bmpdc.SelectObject(pOldPen);    }
+	if(NULL!=pOldBitmap) { bmpdc.SelectObject(pOldBitmap); }
+}
+
+BOOL BCMenu::IsWindowsClassicTheme(void)
+{
+	TCHAR Buf[_MAX_PATH+10];
+	HKEY hKey;
+	DWORD size,type; 
+	long lRetCode; 
+	static BOOL XPTheme_returnflag=FALSE;
+	static BOOL XPTheme_checkflag=FALSE;
+	
+	if(XPTheme_checkflag)return(XPTheme_returnflag);
+
+	XPTheme_checkflag=TRUE;
+	lRetCode = RegOpenKeyEx ( HKEY_CURRENT_USER, 
+		_T("Software\\Microsoft\\Plus!\\Themes\\Current"), 
+		0,KEY_READ,&hKey);  
+	if (lRetCode == ERROR_SUCCESS){ 
+		size = _MAX_PATH;type=REG_SZ;
+		lRetCode=::RegQueryValueEx(hKey,NULL,NULL,&type,
+			(unsigned char *)Buf,&size);
+		if(lRetCode == ERROR_SUCCESS){
+			TCHAR szClassicTheme[]=_T("Windows Classic.theme");
+			int len=lstrlen(Buf);
+			if(len>=lstrlen(szClassicTheme)){
+				if(!lstrcmpi(&Buf[len-lstrlen(szClassicTheme)],szClassicTheme)){
+					XPTheme_returnflag=TRUE;
+				}
+			}
+		}
+		RegCloseKey(hKey);  
+	}
+	return(XPTheme_returnflag);
+}
+
+int BCMenu::GlobalImageListOffset(int nID)
+{
+	int numcurrent=m_AllImagesID.GetSize();
+	int existsloc = -1;
+	for(int i=0;i<numcurrent;++i){
+		if(m_AllImagesID[i]==nID){
+			existsloc=i;
+			break;
+		}
+	}
+	return existsloc;
+}
+
+BOOL BCMenu::CanDraw3DImageList(int offset)
+{
+	BOOL retflag=FALSE;
+	int numcurrent=m_AllImagesID.GetSize();
+	if(offset+1<numcurrent&&offset+2<numcurrent){
+		int nID=m_AllImagesID[offset];
+		if(m_AllImagesID[offset+1]==nID&&m_AllImagesID[offset+2]==nID)retflag=TRUE;
+	}
+	return(retflag);
+}
+
+int BCMenu::AddToGlobalImageList(CImageList *il,int xoffset,int nID)
+{
+	int loc = -1;
+	HIMAGELIST hImageList = m_AllImages.m_hImageList;
+	if(!hImageList){
+		m_AllImages.Create(m_iconX,m_iconY,ILC_COLORDDB|ILC_MASK,1,1);
+	}
+	HICON hIcon = il->ExtractIcon(xoffset);
+	if(hIcon){
+		CBitmap bmp,bmp2;
+		if(IsLunaMenuStyle()&&xp_draw_3D_bitmaps){
+			CWnd *pWnd = AfxGetMainWnd();            // Get main window
+			if (pWnd == NULL) pWnd = CWnd::GetDesktopWindow();
+			CDC *pDC = pWnd->GetDC();              // Get device context
+			GetBitmapFromImageList(pDC,il,xoffset,bmp);
+			GetFadedBitmap(bmp);
+			GetBitmapFromImageList(pDC,il,xoffset,bmp2);
+			GetShadowBitmap(bmp2);
+			pWnd->ReleaseDC(pDC);  // Release the DC
+		}
+		int numcurrent=m_AllImagesID.GetSize();
+		int existsloc = -1;
+		for(int i=0;i<numcurrent;++i){
+			if(m_AllImagesID[i]==nID){
+				existsloc=i;
+				break;
+			}
+		}
+		if(existsloc>=0){
+			m_AllImages.Replace(existsloc,hIcon);
+			loc = existsloc;
+			if(IsLunaMenuStyle()&&xp_draw_3D_bitmaps){
+				if(existsloc+1<numcurrent&&m_AllImagesID[existsloc+1]==nID){
+					if(existsloc+2<numcurrent&&m_AllImagesID[existsloc+2]==nID){
+						CImageList il2;
+						il2.Create(m_iconX,m_iconY,ILC_COLORDDB|ILC_MASK,1,1);
+						il2.Add(&bmp,GetSysColor(COLOR_3DFACE));
+						HICON hIcon2 = il2.ExtractIcon(0);
+						m_AllImages.Replace(existsloc+1,hIcon2);
+						il2.Add(&bmp2,GetSysColor(COLOR_3DFACE));
+						HICON hIcon3 = il2.ExtractIcon(1);
+						m_AllImages.Replace(existsloc+2,hIcon3);
+						::DestroyIcon(hIcon2);
+						::DestroyIcon(hIcon3);
+					}
+				}
+			}
+		}
+		else{
+			m_AllImages.Add(hIcon);
+			m_AllImagesID.Add(nID);
+			loc=numcurrent;
+			if(IsLunaMenuStyle()&&xp_draw_3D_bitmaps){
+				m_AllImages.Add(&bmp,GetSysColor(COLOR_3DFACE));
+				m_AllImages.Add(&bmp2,GetSysColor(COLOR_3DFACE));
+				m_AllImagesID.Add(nID);
+				m_AllImagesID.Add(nID);
+			}
+		}
+		::DestroyIcon(hIcon);
+	}
+	return(loc);
+}
+
+//*************************************************************************
+
+/////////////////////////////////////////////////////////////////////////////
+// Toolbar for loading images
+/////////////////////////////////////////////////////////////////////////////
+
+struct CToolBarData
+{
+	WORD wVersion;
+	WORD wWidth;
+	WORD wHeight;
+	WORD wItemCount;
+	WORD* items(){
+		return (WORD*)(this+1);
+	}
+};
+
+BOOL BCMenuToolBar::LoadToolBar(LPCTSTR lpszResourceName)
+{
+	ASSERT_VALID(this);
+	ASSERT(lpszResourceName != NULL);
+
+	HINSTANCE hInst = AfxFindResourceHandle(lpszResourceName,RT_TOOLBAR);
+	HRSRC hRsrc = ::FindResource(hInst,lpszResourceName,RT_TOOLBAR);
+	if (hRsrc == NULL){
+		hInst = NULL;
+		hRsrc = ::FindResource(hInst,lpszResourceName,RT_TOOLBAR);
+	}
+	if (hRsrc == NULL)
+		return FALSE;
+
+	HGLOBAL hGlobal = ::LoadResource(hInst,hRsrc);
+	if (hGlobal == NULL)
+		return FALSE;
+
+	CToolBarData* pData = (CToolBarData*)::LockResource(hGlobal);
+	if (pData == NULL)
+		return FALSE;
+	ASSERT(pData->wVersion == 1);
+
+	UINT* pItems = new UINT[pData->wItemCount];
+	for (int i = 0; i < pData->wItemCount; i++)
+		pItems[i] = pData->items()[i];
+	BOOL bResult = SetButtons(pItems,pData->wItemCount);
+	delete[] pItems;
+
+	if (bResult){
+		CSize sizeImage(pData->wWidth,pData->wHeight);
+		CSize sizeButton(pData->wWidth+7,pData->wHeight+7);
+		SetSizes(sizeButton,sizeImage);
+		m_iconX=pData->wWidth;
+		m_iconY=pData->wHeight;
+		bResult = LoadBitmap(lpszResourceName);
+	}
+
+	::UnlockResource(hGlobal);
+	::FreeResource(hGlobal);
+	return bResult;
+}
+
+BOOL BCMenuToolBar::LoadBitmap(LPCTSTR lpszResourceName)
+{
+	ASSERT_VALID(this);
+	ASSERT(lpszResourceName != NULL);
+
+	HINSTANCE hInstImageWell = AfxFindResourceHandle(lpszResourceName,RT_BITMAP);
+	HRSRC hRsrcImageWell = ::FindResource(hInstImageWell,lpszResourceName,RT_BITMAP);
+	if (hRsrcImageWell == NULL){
+		hInstImageWell = NULL;
+		hRsrcImageWell = ::FindResource(hInstImageWell,lpszResourceName,RT_BITMAP);
+	}
+	if (hRsrcImageWell == NULL)
+		return FALSE;
+
+	HBITMAP hbmImageWell;
+	hbmImageWell = AfxLoadSysColorBitmap(hInstImageWell,hRsrcImageWell);
+
+	if (!AddReplaceBitmap(hbmImageWell))
+		return FALSE;
+
+	m_hInstImageWell = hInstImageWell;
+	m_hRsrcImageWell = hRsrcImageWell;
+	return TRUE;
+}

+ 391 - 0
Source/OGCAssistTool/OGCAssistTool/BCMenu.h

@@ -0,0 +1,391 @@
+//*************************************************************************
+// BCMenu.h : header file
+// Version : 3.02
+// Date : March 2002
+// Author : Brent Corkum
+// Email :  corkum@rocscience.com
+// Latest Version : http://www.rocscience.com/~corkum/BCMenu.html
+// 
+// Bug Fixes and portions of code supplied by:
+//
+// Ben Ashley,Girish Bharadwaj,Jean-Edouard Lachand-Robert,
+// Robert Edward Caldecott,Kenny Goers,Leonardo Zide,
+// Stefan Kuhr,Reiner Jung,Martin Vladic,Kim Yoo Chul,
+// Oz Solomonovich,Tongzhe Cui,Stephane Clog,Warren Stevens,
+// Damir Valiulin,David Kinder,Marc Loiry
+//
+// You are free to use/modify this code but leave this header intact.
+// This class is public domain so you are free to use it any of
+// your applications (Freeware,Shareware,Commercial). All I ask is
+// that you let me know so that if you have a real winner I can
+// brag to my buddies that some of my code is in your app. I also
+// wouldn't mind if you sent me a copy of your application since I
+// like to play with new stuff.
+//*************************************************************************
+
+#ifndef BCMenu_H
+#define BCMenu_H
+
+#include <afxtempl.h>
+
+// BCMenuData class. Fill this class structure to define a single menu item:
+class BCMenuData
+{
+	wchar_t *m_szMenuText;
+public:
+	BCMenuData () {menuIconNormal=-1;xoffset=-1;bitmap=NULL;pContext=NULL;
+	nFlags=0;nID=0;syncflag=0;m_szMenuText=NULL;global_offset=-1;threeD=FALSE;};
+	void SetAnsiString(LPCSTR szAnsiString);
+	void SetWideString(const wchar_t *szWideString);
+	const wchar_t *GetWideString(void) {return m_szMenuText;};
+	~BCMenuData ();
+	CString GetString(void);//returns the menu text in ANSI or UNICODE
+	int xoffset,global_offset;
+	BOOL threeD;
+	int menuIconNormal;
+	UINT nFlags,nID,syncflag;
+	CImageList *bitmap;
+	void *pContext; // used to attach user data
+};
+
+//struct CMenuItemInfo : public MENUITEMINFO {
+struct CMenuItemInfo : public 
+//MENUITEMINFO 
+#ifndef UNICODE   //SK: this fixes warning C4097: typedef-name 'MENUITEMINFO' used as synonym for class-name 'tagMENUITEMINFOA'
+tagMENUITEMINFOA
+#else
+tagMENUITEMINFOW
+#endif
+{
+	CMenuItemInfo()
+	{
+		memset(this, 0, sizeof(MENUITEMINFO));
+		cbSize = sizeof(MENUITEMINFO);
+	}
+};
+
+// how the menu's are drawn, either original or XP style
+typedef enum {BCMENU_DRAWMODE_ORIGINAL,BCMENU_DRAWMODE_XP} BC_MenuDrawMode;
+
+// how seperators are handled when removing a menu (Tongzhe Cui)
+typedef enum {BCMENU_NONE, BCMENU_HEAD, BCMENU_TAIL, BCMENU_BOTH} BC_Seperator;
+
+// defines for unicode support
+#ifndef UNICODE
+#define AppendMenu AppendMenuA
+#define InsertMenu InsertMenuA
+#define InsertODMenu InsertODMenuA
+#define AppendODMenu AppendODMenuA
+#define AppendODPopupMenu AppendODPopupMenuA
+#define ModifyODMenu ModifyODMenuA
+#else
+#define AppendMenu AppendMenuW
+#define InsertMenu InsertMenuW
+#define InsertODMenu InsertODMenuW
+#define AppendODMenu AppendODMenuW
+#define ModifyODMenu ModifyODMenuW
+#define AppendODPopupMenu AppendODPopupMenuW
+#endif
+
+
+class BCMenu : public CMenu
+{
+	DECLARE_DYNAMIC( BCMenu )
+public:
+	BCMenu(); 
+	virtual ~BCMenu();
+
+	// Functions for loading and applying bitmaps to menus (see example application)
+	virtual BOOL LoadMenu(LPCTSTR lpszResourceName);
+	virtual BOOL LoadMenu(int nResource);
+	BOOL LoadToolbar(UINT nToolBar);
+	BOOL LoadToolbars(const UINT *arID,int n);
+	void AddFromToolBar(CToolBar* pToolBar, int nResourceID);
+	BOOL LoadFromToolBar(UINT nID,UINT nToolBar,int& xoffset);
+	BOOL AddBitmapToImageList(CImageList *list,UINT nResourceID);
+	static HBITMAP LoadSysColorBitmap(int nResourceId);
+	void LoadCheckmarkBitmap(int unselect,int select); // custom check mark bitmaps
+	
+	// functions for appending a menu option, use the AppendMenu call (see above define)
+	BOOL AppendMenuA(UINT nFlags,UINT nIDNewItem=0,const char *lpszNewItem=NULL,int nIconNormal=-1);
+	BOOL AppendMenuA(UINT nFlags,UINT nIDNewItem,const char *lpszNewItem,CImageList *il,int xoffset);
+	BOOL AppendMenuA(UINT nFlags,UINT nIDNewItem,const char *lpszNewItem,CBitmap *bmp);
+	BOOL AppendMenuW(UINT nFlags,UINT nIDNewItem=0,wchar_t *lpszNewItem=NULL,int nIconNormal=-1);
+	BOOL AppendMenuW(UINT nFlags,UINT nIDNewItem,wchar_t *lpszNewItem,CImageList *il,int xoffset);
+	BOOL AppendMenuW(UINT nFlags,UINT nIDNewItem,wchar_t *lpszNewItem,CBitmap *bmp);
+	BOOL AppendODMenuA(LPCSTR lpstrText,UINT nFlags = MF_OWNERDRAW,UINT nID = 0,int nIconNormal = -1);  
+	BOOL AppendODMenuW(wchar_t *lpstrText,UINT nFlags = MF_OWNERDRAW,UINT nID = 0,int nIconNormal = -1);  
+	BOOL AppendODMenuA(LPCSTR lpstrText,UINT nFlags,UINT nID,CImageList *il,int xoffset);
+	BOOL AppendODMenuW(wchar_t *lpstrText,UINT nFlags,UINT nID,CImageList *il,int xoffset);
+	
+	// for appending a popup menu (see example application)
+	BCMenu* AppendODPopupMenuA(LPCSTR lpstrText);
+	BCMenu* AppendODPopupMenuW(wchar_t *lpstrText);
+
+	// functions for inserting a menu option, use the InsertMenu call (see above define)
+	BOOL InsertMenuA(UINT nPosition,UINT nFlags,UINT nIDNewItem=0,const char *lpszNewItem=NULL,int nIconNormal=-1);
+	BOOL InsertMenuA(UINT nPosition,UINT nFlags,UINT nIDNewItem,const char *lpszNewItem,CImageList *il,int xoffset);
+	BOOL InsertMenuA(UINT nPosition,UINT nFlags,UINT nIDNewItem,const char *lpszNewItem,CBitmap *bmp);
+	BOOL InsertMenuW(UINT nPosition,UINT nFlags,UINT nIDNewItem=0,wchar_t *lpszNewItem=NULL,int nIconNormal=-1);
+	BOOL InsertMenuW(UINT nPosition,UINT nFlags,UINT nIDNewItem,wchar_t *lpszNewItem,CImageList *il,int xoffset);
+	BOOL InsertMenuW(UINT nPosition,UINT nFlags,UINT nIDNewItem,wchar_t *lpszNewItem,CBitmap *bmp);
+	BOOL InsertODMenuA(UINT nPosition,LPCSTR lpstrText,UINT nFlags = MF_OWNERDRAW,UINT nID = 0,int nIconNormal = -1); 
+	BOOL InsertODMenuW(UINT nPosition,wchar_t *lpstrText,UINT nFlags = MF_OWNERDRAW,UINT nID = 0,int nIconNormal = -1);  
+	BOOL InsertODMenuA(UINT nPosition,LPCSTR lpstrText,UINT nFlags,UINT nID,CImageList *il,int xoffset);
+	BOOL InsertODMenuW(UINT nPosition,wchar_t *lpstrText,UINT nFlags,UINT nID,CImageList *il,int xoffset);
+	
+	// functions for modifying a menu option, use the ModifyODMenu call (see above define)
+	BOOL ModifyODMenuA(const char *lpstrText,UINT nID=0,int nIconNormal=-1);
+	BOOL ModifyODMenuA(const char *lpstrText,UINT nID,CImageList *il,int xoffset);
+	BOOL ModifyODMenuA(const char *lpstrText,UINT nID,CBitmap *bmp);
+	BOOL ModifyODMenuA(const char *lpstrText,const char *OptionText,int nIconNormal);
+	BOOL ModifyODMenuW(wchar_t *lpstrText,UINT nID=0,int nIconNormal=-1);
+	BOOL ModifyODMenuW(wchar_t *lpstrText,UINT nID,CImageList *il,int xoffset);
+	BOOL ModifyODMenuW(wchar_t *lpstrText,UINT nID,CBitmap *bmp);
+	BOOL ModifyODMenuW(wchar_t *lpstrText,wchar_t *OptionText,int nIconNormal);
+	// use this method for adding a solid/hatched colored square beside a menu option
+	// courtesy of Warren Stevens
+	BOOL ModifyODMenuA(const char *lpstrText,UINT nID,COLORREF fill,COLORREF border,int hatchstyle=-1,CSize *pSize=NULL);
+	BOOL ModifyODMenuW(wchar_t *lpstrText,UINT nID,COLORREF fill,COLORREF border,int hatchstyle=-1,CSize *pSize=NULL);
+	
+	// for deleting and removing menu options
+	BOOL	RemoveMenu(UINT uiId,UINT nFlags);
+	BOOL	DeleteMenu(UINT uiId,UINT nFlags);
+	// sPos means Seperator's position, since we have no way to find the seperator's position in the menu
+	// we have to specify them when we call the RemoveMenu to make sure the unused seperators are removed;
+	// sPos  = None no seperator removal;
+	//       = Head  seperator in front of this menu item;
+	//       = Tail  seperator right after this menu item;
+	//       = Both  seperators at both ends;
+	// remove the menu item based on their text, return -1 if not found, otherwise return the menu position;
+	int RemoveMenu(char* pText, BC_Seperator sPos=BCMENU_NONE);
+	int RemoveMenu(wchar_t* pText, BC_Seperator sPos=BCMENU_NONE);
+	int DeleteMenu(char* pText, BC_Seperator sPos=BCMENU_NONE);
+	int DeleteMenu(wchar_t* pText, BC_Seperator sPos=BCMENU_NONE);
+	
+	// Destoying
+	virtual BOOL DestroyMenu();
+
+	// function for retrieving and setting a menu options text (use this function
+	// because it is ownerdrawn)
+	BOOL GetMenuText(UINT id,CString &string,UINT nFlags = MF_BYPOSITION);
+	BOOL SetMenuText(UINT id,CString string, UINT nFlags = MF_BYPOSITION);
+
+	// Getting a submenu from it's name or position
+	BCMenu* GetSubBCMenu(char* lpszSubMenuName);
+	BCMenu* GetSubBCMenu(wchar_t* lpszSubMenuName);
+	CMenu* GetSubMenu (LPCTSTR lpszSubMenuName);
+	CMenu* GetSubMenu (int nPos);
+	int GetMenuPosition(char* pText);
+	int GetMenuPosition(wchar_t* pText);
+
+	// Drawing: 
+	virtual void DrawItem( LPDRAWITEMSTRUCT);  // Draw an item
+	virtual void MeasureItem( LPMEASUREITEMSTRUCT );  // Measure an item
+
+	// Static functions used for handling menu's in the mainframe
+	static void UpdateMenu(CMenu *pmenu);
+	static BOOL IsMenu(CMenu *submenu);
+	static BOOL IsMenu(HMENU submenu);
+	static LRESULT FindKeyboardShortcut(UINT nChar,UINT nFlags,CMenu *pMenu);
+
+	// Function to set how menu is drawn, either original or XP style
+	static void SetMenuDrawMode(UINT mode){
+		BCMenu::original_drawmode=mode;
+		BCMenu::xp_drawmode=mode;
+	};
+	// Function to set how disabled items are drawn (mode=FALSE means they are not drawn selected)
+	static void SetSelectDisableMode(BOOL mode){
+		BCMenu::original_select_disabled=mode;
+		BCMenu::xp_select_disabled=mode;
+	};
+	static int BCMenu::GetMenuDrawMode(void);
+	static BOOL BCMenu::GetSelectDisableMode(void);
+
+	// how the bitmaps are drawn in XP Luna mode
+	static void SetXPBitmap3D(BOOL val){
+		BCMenu::xp_draw_3D_bitmaps=val;
+	};
+	static BOOL GetXPBitmap3D(void){return BCMenu::xp_draw_3D_bitmaps;}
+
+	// Customizing:
+	// Set icon size
+	void SetIconSize (int, int); 
+	// set the color in the bitmaps that is the background transparent color
+	void SetBitmapBackground(COLORREF color);
+	void UnSetBitmapBackground(void);
+	// obsolete functions for setting how menu images are dithered for disabled menu options
+	BOOL GetDisableOldStyle(void);
+	void SetDisableOldStyle(void);
+	void UnSetDisableOldStyle(void);
+	static COLORREF LightenColor(COLORREF col,double factor);
+	static COLORREF DarkenColor(COLORREF col,double factor);
+
+// Miscellaneous Protected Member functions
+protected:
+	static BOOL IsNewShell(void);
+	static BOOL IsWinXPLuna(void);
+	static BOOL IsLunaMenuStyle(void);
+	static BOOL IsWindowsClassicTheme(void);
+	BCMenuData *BCMenu::FindMenuItem(UINT nID);
+	BCMenu *FindMenuOption(int nId,int& nLoc);
+	BCMenu *FindAnotherMenuOption(int nId,int& nLoc,CArray<BCMenu*,BCMenu*>&bcsubs,
+								  CArray<int,int&>&bclocs);
+	BCMenuData *FindMenuOption(wchar_t *lpstrText);
+	void InsertSpaces(void);
+	void DrawCheckMark(CDC *pDC,int x,int y,COLORREF color);
+	void DrawRadioDot(CDC *pDC,int x,int y,COLORREF color);
+	BCMenuData *NewODMenu(UINT pos,UINT nFlags,UINT nID,CString string);
+	void SynchronizeMenu(void);
+	void BCMenu::InitializeMenuList(int value);
+	void BCMenu::DeleteMenuList(void);
+	BCMenuData *BCMenu::FindMenuList(UINT nID);
+	void DrawItem_Win9xNT2000 (LPDRAWITEMSTRUCT lpDIS);
+	void DrawItem_WinXP (LPDRAWITEMSTRUCT lpDIS);
+	BOOL Draw3DCheckmark(CDC *dc, const CRect& rc,BOOL bSelected,HBITMAP hbmCheck);
+	BOOL DrawXPCheckmark(CDC *dc, const CRect& rc, HBITMAP hbmCheck,COLORREF &colorout);
+	void DitherBlt(HDC hdcDest, int nXDest, int nYDest, int nWidth, 
+		int nHeight, HBITMAP hbm, int nXSrc, int nYSrc,COLORREF bgcolor);
+	void DitherBlt2(CDC *drawdc, int nXDest, int nYDest, int nWidth, 
+		int nHeight, CBitmap &bmp, int nXSrc, int nYSrc,COLORREF bgcolor);
+	BOOL GetBitmapFromImageList(CDC* pDC,CImageList *imglist,int nIndex,CBitmap &bmp);
+	BOOL ImageListDuplicate(CImageList *il,int xoffset,CImageList *newlist);
+	static WORD NumBitmapColors(LPBITMAPINFOHEADER lpBitmap);
+	void ColorBitmap(CDC* pDC, CBitmap& bmp,CSize bitmap_size,CSize icon_size,COLORREF fill,COLORREF border,int hatchstyle=-1);
+	void RemoveTopLevelOwnerDraw(void);
+	int GetMenuStart(void);
+	void GetFadedBitmap(CBitmap &bmp);
+	void GetShadowBitmap(CBitmap &bmp);
+	int AddToGlobalImageList(CImageList *il,int xoffset,int nID);
+	int GlobalImageListOffset(int nID);
+	BOOL CanDraw3DImageList(int offset);
+	
+// Member Variables
+protected:
+	CTypedPtrArray<CPtrArray, BCMenuData*> m_MenuList;  // Stores list of menu items 
+	// When loading an owner-drawn menu using a Resource, BCMenu must keep track of
+	// the popup menu's that it creates. Warning, this list *MUST* be destroyed
+	// last item first :)
+	CTypedPtrArray<CPtrArray, HMENU>  m_SubMenus;  // Stores list of sub-menus 
+	// Stores a list of all BCMenu's ever created 
+	static CTypedPtrArray<CPtrArray, HMENU>  m_AllSubMenus;
+	// Global ImageList
+	static CImageList m_AllImages;
+	static CArray<int,int&> m_AllImagesID;
+	// icon size
+	int m_iconX,m_iconY;
+	COLORREF m_bitmapBackground;
+	BOOL m_bitmapBackgroundFlag;
+	BOOL disable_old_style;
+	static UINT original_drawmode;
+	static BOOL original_select_disabled;
+	static UINT xp_drawmode;
+	static BOOL xp_select_disabled;
+	static BOOL xp_draw_3D_bitmaps;
+	CImageList *checkmaps;
+	BOOL checkmapsshare;
+	int m_selectcheck;
+	int m_unselectcheck;
+	BOOL m_bDynIcons;
+	BOOL m_loadmenu;
+}; 
+
+class BCMenuToolBar : public CToolBar{
+public:
+	BCMenuToolBar() : CToolBar() {m_iconX=m_iconY=0;}
+	BOOL LoadToolBar(LPCTSTR lpszResourceName);
+	BOOL LoadToolBar(UINT nIDResource){
+		return LoadToolBar(MAKEINTRESOURCE(nIDResource));
+	}
+	BOOL LoadBitmap(LPCTSTR lpszResourceName);
+	void GetIconSize(int &iconx,int &icony){iconx=m_iconX;icony=m_iconY;}
+protected:
+	int m_iconX,m_iconY;
+};
+
+#define BCMENU_USE_MEMDC
+
+#ifdef BCMENU_USE_MEMDC
+//////////////////////////////////////////////////
+// BCMenuMemDC - memory DC
+//
+// Author: Keith Rule
+// Email:  keithr@europa.com
+// Copyright 1996-1997, Keith Rule
+//
+// You may freely use or modify this code provided this
+// Copyright is included in all derived versions.
+//
+// History - 10/3/97 Fixed scrolling bug.
+//                   Added print support.
+//           25 feb 98 - fixed minor assertion bug
+//
+// This class implements a memory Device Context
+
+class BCMenuMemDC : public CDC
+{
+public:
+
+    // constructor sets up the memory DC
+    BCMenuMemDC(CDC* pDC,LPCRECT lpSrcRect) : CDC()
+    {
+        ASSERT(pDC != NULL);
+
+		m_rect.CopyRect(lpSrcRect);
+        m_pDC = pDC;
+        m_pOldBitmap = NULL;
+        m_bMemDC = !pDC->IsPrinting();
+              
+        if (m_bMemDC)    // Create a Memory DC
+        {
+            CreateCompatibleDC(pDC);
+            m_bitmap.CreateCompatibleBitmap(pDC, m_rect.Width(), m_rect.Height());
+            m_pOldBitmap = SelectObject(&m_bitmap);
+            SetWindowOrg(m_rect.left, m_rect.top);
+        }
+        else        // Make a copy of the relevent parts of the current DC for printing
+        {
+            m_bPrinting = pDC->m_bPrinting;
+            m_hDC       = pDC->m_hDC;
+            m_hAttribDC = pDC->m_hAttribDC;
+        }
+    }
+    
+    // Destructor copies the contents of the mem DC to the original DC
+    ~BCMenuMemDC()
+    {
+        if (m_bMemDC) 
+        {    
+            // Copy the offscreen bitmap onto the screen.
+            m_pDC->BitBlt(m_rect.left, m_rect.top, m_rect.Width(), m_rect.Height(),
+                          this, m_rect.left, m_rect.top, SRCCOPY);
+
+            //Swap back the original bitmap.
+            SelectObject(m_pOldBitmap);
+        } else {
+            // All we need to do is replace the DC with an illegal value,
+            // this keeps us from accidently deleting the handles associated with
+            // the CDC that was passed to the constructor.
+            m_hDC = m_hAttribDC = NULL;
+        }
+    }
+
+    // Allow usage as a pointer
+    BCMenuMemDC* operator->() {return this;}
+        
+    // Allow usage as a pointer
+    operator BCMenuMemDC*() {return this;}
+
+private:
+    CBitmap  m_bitmap;      // Offscreen bitmap
+    CBitmap* m_pOldBitmap;  // bitmap originally found in BCMenuMemDC
+    CDC*     m_pDC;         // Saves CDC passed in constructor
+    CRect    m_rect;        // Rectangle of drawing area.
+    BOOL     m_bMemDC;      // TRUE if CDC really is a Memory DC.
+};
+
+#endif
+
+#endif
+
+//*************************************************************************

+ 2460 - 0
Source/OGCAssistTool/OGCAssistTool/BtnST.cpp

@@ -0,0 +1,2460 @@
+#include "stdafx.h"
+#include "BtnST.h"
+
+#ifdef	BTNST_USE_SOUND
+#pragma comment(lib, "winmm.lib")
+#include <Mmsystem.h>
+#endif
+
+#ifdef _DEBUG
+#define new DEBUG_NEW
+#undef THIS_FILE
+static char THIS_FILE[] = __FILE__;
+#endif
+
+/////////////////////////////////////////////////////////////////////////////
+// CButtonST
+
+// Mask for control's type
+#define BS_TYPEMASK SS_TYPEMASK
+
+#ifndef	TTM_SETTITLE
+#define TTM_SETTITLEA           (WM_USER + 32)  // wParam = TTI_*, lParam = char* szTitle
+#define TTM_SETTITLEW           (WM_USER + 33)  // wParam = TTI_*, lParam = wchar* szTitle
+#ifdef	UNICODE
+#define TTM_SETTITLE            TTM_SETTITLEW
+#else
+#define TTM_SETTITLE            TTM_SETTITLEA
+#endif
+#endif
+
+#ifndef	TTS_BALLOON
+#define	TTS_BALLOON		0x40
+#endif
+
+CButtonST::CButtonST()
+{
+	m_bIsPressed		= FALSE;
+	m_bIsFocused		= FALSE;
+	m_bIsDisabled		= FALSE;
+	m_bMouseOnButton	= FALSE;
+
+	FreeResources(FALSE);
+
+	// Default type is "flat" button
+	m_bIsFlat = TRUE;
+	// Button will be tracked also if when the window is inactive (like Internet Explorer)
+	m_bAlwaysTrack = TRUE;
+  
+	// By default draw border in "flat" button 
+	m_bDrawBorder = TRUE; 
+  
+	// By default icon is aligned horizontally
+	m_byAlign = ST_ALIGN_HORIZ; 
+
+	// By default use usual pressed style
+	SetPressedStyle(BTNST_PRESSED_LEFTRIGHT, FALSE);
+  
+	// By default, for "flat" button, don't draw the focus rect
+	m_bDrawFlatFocus = FALSE;
+
+	// By default the button is not the default button
+	m_bIsDefault = FALSE;
+	// Invalid value, since type still unknown
+	m_nTypeStyle = BS_TYPEMASK;
+
+	// By default the button is not a checkbox
+	m_bIsCheckBox = FALSE;
+	m_nCheck = 0;
+
+	// Set default colors
+	SetDefaultColors(FALSE);
+
+	// No tooltip created
+	m_ToolTip.m_hWnd = NULL;
+	m_dwToolTipStyle = 0;
+
+	// Do not draw as a transparent button
+	m_bDrawTransparent = FALSE;
+	m_pbmpOldBk = NULL;
+
+	// No URL defined
+	SetURL(NULL);
+
+	// No cursor defined
+	m_hCursor = NULL;
+
+	// No associated menu
+#ifndef	BTNST_USE_BCMENU
+	m_hMenu = NULL;
+#endif
+	m_hParentWndMenu = NULL;
+	m_bMenuDisplayed = FALSE;
+
+	m_bShowDisabledBitmap = TRUE;
+
+	m_ptImageOrg.x = 3;
+	m_ptImageOrg.y = 3;
+
+	// No defined callbacks
+	::ZeroMemory(&m_csCallbacks, sizeof(m_csCallbacks));
+
+#ifdef	BTNST_USE_SOUND
+	// No defined sounds
+	::ZeroMemory(&m_csSounds, sizeof(m_csSounds));
+#endif
+} // End of CButtonST
+
+CButtonST::~CButtonST()
+{
+	// Restore old bitmap (if any)
+	if (m_dcBk.m_hDC && m_pbmpOldBk)
+	{
+		m_dcBk.SelectObject(m_pbmpOldBk);
+	} // if
+
+	FreeResources();
+
+	// Destroy the cursor (if any)
+	if (m_hCursor) ::DestroyCursor(m_hCursor);
+
+	// Destroy the menu (if any)
+#ifdef	BTNST_USE_BCMENU
+	if (m_menuPopup.m_hMenu)	m_menuPopup.DestroyMenu();
+#else
+	if (m_hMenu)	::DestroyMenu(m_hMenu);
+#endif
+} // End of ~CButtonST
+
+BEGIN_MESSAGE_MAP(CButtonST, CButton)
+    //{{AFX_MSG_MAP(CButtonST)
+	ON_WM_SETCURSOR()
+	ON_WM_KILLFOCUS()
+	ON_WM_MOUSEMOVE()
+	ON_WM_SYSCOLORCHANGE()
+	ON_CONTROL_REFLECT_EX(BN_CLICKED, OnClicked)
+	ON_WM_ACTIVATE()
+	ON_WM_ENABLE()
+	ON_WM_CANCELMODE()
+	ON_WM_GETDLGCODE()
+	ON_WM_CTLCOLOR_REFLECT()
+	//}}AFX_MSG_MAP
+#ifdef	BTNST_USE_BCMENU
+	ON_WM_MENUCHAR()
+	ON_WM_MEASUREITEM()
+#endif
+
+	ON_MESSAGE(BM_SETSTYLE, OnSetStyle)
+	ON_MESSAGE(WM_MOUSELEAVE, OnMouseLeave)
+	ON_MESSAGE(BM_SETCHECK, OnSetCheck)
+	ON_MESSAGE(BM_GETCHECK, OnGetCheck)
+END_MESSAGE_MAP()
+
+void CButtonST::FreeResources(BOOL bCheckForNULL)
+{
+	if (bCheckForNULL)
+	{
+		// Destroy icons
+		// Note: the following two lines MUST be here! even if
+		// BoundChecker says they are unnecessary!
+		if (m_csIcons[0].hIcon)	::DestroyIcon(m_csIcons[0].hIcon);
+		if (m_csIcons[1].hIcon)	::DestroyIcon(m_csIcons[1].hIcon);
+
+		// Destroy bitmaps
+		if (m_csBitmaps[0].hBitmap)	::DeleteObject(m_csBitmaps[0].hBitmap);
+		if (m_csBitmaps[1].hBitmap)	::DeleteObject(m_csBitmaps[1].hBitmap);
+
+		// Destroy mask bitmaps
+		if (m_csBitmaps[0].hMask)	::DeleteObject(m_csBitmaps[0].hMask);
+		if (m_csBitmaps[1].hMask)	::DeleteObject(m_csBitmaps[1].hMask);
+	} // if
+
+	::ZeroMemory(&m_csIcons, sizeof(m_csIcons));
+	::ZeroMemory(&m_csBitmaps, sizeof(m_csBitmaps));
+} // End of FreeResources
+
+void CButtonST::PreSubclassWindow() 
+{
+	UINT nBS;
+
+	nBS = GetButtonStyle();
+
+	// Set initial control type
+	m_nTypeStyle = nBS & BS_TYPEMASK;
+
+	// Check if this is a checkbox
+	if (nBS & BS_CHECKBOX) m_bIsCheckBox = TRUE;
+
+	// Set initial default state flag
+	if (m_nTypeStyle == BS_DEFPUSHBUTTON)
+	{
+		// Set default state for a default button
+		m_bIsDefault = TRUE;
+
+		// Adjust style for default button
+		m_nTypeStyle = BS_PUSHBUTTON;
+	} // If
+
+	// You should not set the Owner Draw before this call
+	// (don't use the resource editor "Owner Draw" or
+	// ModifyStyle(0, BS_OWNERDRAW) before calling PreSubclassWindow() )
+	ASSERT(m_nTypeStyle != BS_OWNERDRAW);
+
+	// Switch to owner-draw
+	ModifyStyle(BS_TYPEMASK, BS_OWNERDRAW, SWP_FRAMECHANGED);
+
+	CButton::PreSubclassWindow();
+} // End of PreSubclassWindow
+
+UINT CButtonST::OnGetDlgCode() 
+{
+	UINT nCode = CButton::OnGetDlgCode();
+
+	// Tell the system if we want default state handling
+	// (losing default state always allowed)
+	nCode |= (m_bIsDefault ? DLGC_DEFPUSHBUTTON : DLGC_UNDEFPUSHBUTTON);
+
+	return nCode;
+} // End of OnGetDlgCode
+
+BOOL CButtonST::PreTranslateMessage(MSG* pMsg) 
+{
+	InitToolTip();
+	m_ToolTip.RelayEvent(pMsg);
+	
+	if (pMsg->message == WM_LBUTTONDBLCLK)
+		pMsg->message = WM_LBUTTONDOWN;
+
+	return CButton::PreTranslateMessage(pMsg);
+} // End of PreTranslateMessage
+
+HBRUSH CButtonST::CtlColor(CDC* pDC, UINT nCtlColor) 
+{
+	return (HBRUSH)::GetStockObject(NULL_BRUSH); 
+} // End of CtlColor
+
+void CButtonST::OnSysColorChange() 
+{
+	CButton::OnSysColorChange();
+
+	m_dcBk.DeleteDC();
+	m_bmpBk.DeleteObject();	
+	SetDefaultColors();
+} // End of OnSysColorChange
+
+LRESULT CButtonST::OnSetStyle(WPARAM wParam, LPARAM lParam)
+{
+	UINT nNewType = (wParam & BS_TYPEMASK);
+
+	// Update default state flag
+	if (nNewType == BS_DEFPUSHBUTTON)
+	{
+		m_bIsDefault = TRUE;
+	} // if
+	else if (nNewType == BS_PUSHBUTTON)
+	{
+		// Losing default state always allowed
+		m_bIsDefault = FALSE;
+	} // if
+
+	// Can't change control type after owner-draw is set.
+	// Let the system process changes to other style bits
+	// and redrawing, while keeping owner-draw style
+	return DefWindowProc(BM_SETSTYLE,
+		(wParam & ~BS_TYPEMASK) | BS_OWNERDRAW, lParam);
+} // End of OnSetStyle
+
+LRESULT CButtonST::OnSetCheck(WPARAM wParam, LPARAM lParam)
+{
+	ASSERT(m_bIsCheckBox);
+
+	switch (wParam)
+	{
+		case BST_CHECKED:
+		case BST_INDETERMINATE:	// Indeterminate state is handled like checked state
+			SetCheck(1);
+			break;
+		default:
+			SetCheck(0);
+			break;
+	} // switch
+
+	return 0;
+} // End of OnSetCheck
+
+LRESULT CButtonST::OnGetCheck(WPARAM wParam, LPARAM lParam)
+{
+	ASSERT(m_bIsCheckBox);
+	return GetCheck();
+} // End of OnGetCheck
+
+#ifdef	BTNST_USE_BCMENU
+LRESULT CButtonST::OnMenuChar(UINT nChar, UINT nFlags, CMenu* pMenu) 
+{
+	LRESULT lResult;
+	if (BCMenu::IsMenu(pMenu))
+		lResult = BCMenu::FindKeyboardShortcut(nChar, nFlags, pMenu);
+	else
+		lResult = CButton::OnMenuChar(nChar, nFlags, pMenu);
+	return lResult;
+} // End of OnMenuChar
+#endif
+
+#ifdef	BTNST_USE_BCMENU
+void CButtonST::OnMeasureItem(int nIDCtl, LPMEASUREITEMSTRUCT lpMeasureItemStruct) 
+{
+	BOOL bSetFlag = FALSE;
+	if (lpMeasureItemStruct->CtlType == ODT_MENU)
+	{
+		if (IsMenu((HMENU)lpMeasureItemStruct->itemID) && BCMenu::IsMenu((HMENU)lpMeasureItemStruct->itemID))
+		{
+			m_menuPopup.MeasureItem(lpMeasureItemStruct);
+			bSetFlag = TRUE;
+		} // if
+	} // if
+	if (!bSetFlag) CButton::OnMeasureItem(nIDCtl, lpMeasureItemStruct);
+} // End of OnMeasureItem
+#endif
+
+void CButtonST::OnEnable(BOOL bEnable) 
+{
+	CButton::OnEnable(bEnable);
+	
+	if (bEnable == FALSE)	
+	{
+		CWnd*	pWnd = GetParent()->GetNextDlgTabItem(this);
+		if (pWnd)
+			pWnd->SetFocus();
+		else
+			GetParent()->SetFocus();
+
+		CancelHover();
+	} // if
+} // End of OnEnable
+
+void CButtonST::OnKillFocus(CWnd * pNewWnd)
+{
+	CButton::OnKillFocus(pNewWnd);
+	CancelHover();
+} // End of OnKillFocus
+
+void CButtonST::OnActivate(UINT nState, CWnd* pWndOther, BOOL bMinimized) 
+{
+	CButton::OnActivate(nState, pWndOther, bMinimized);
+	if (nState == WA_INACTIVE)	CancelHover();
+} // End of OnActivate
+
+void CButtonST::OnCancelMode() 
+{
+	CButton::OnCancelMode();
+	CancelHover();
+} // End of OnCancelMode
+
+BOOL CButtonST::OnSetCursor(CWnd* pWnd, UINT nHitTest, UINT message) 
+{
+	// If a cursor was specified then use it!
+	if (m_hCursor != NULL)
+	{
+		::SetCursor(m_hCursor);
+		return TRUE;
+	} // if
+
+	return CButton::OnSetCursor(pWnd, nHitTest, message);
+} // End of OnSetCursor
+
+void CButtonST::CancelHover()
+{
+	// Only for flat buttons
+	if (m_bIsFlat)
+	{
+		if (m_bMouseOnButton)
+		{
+			m_bMouseOnButton = FALSE;
+			Invalidate();
+		} // if
+	} // if
+} // End of CancelHover
+
+void CButtonST::OnMouseMove(UINT nFlags, CPoint point)
+{
+	CWnd*				wndUnderMouse = NULL;
+	CWnd*				wndActive = this;
+	TRACKMOUSEEVENT		csTME;
+
+	CButton::OnMouseMove(nFlags, point);
+
+	ClientToScreen(&point);
+	wndUnderMouse = WindowFromPoint(point);
+
+	// If the mouse enter the button with the left button pressed then do nothing
+	if (nFlags & MK_LBUTTON && m_bMouseOnButton == FALSE) return;
+
+	// If our button is not flat then do nothing
+	if (m_bIsFlat == FALSE) return;
+
+	if (m_bAlwaysTrack == FALSE)	wndActive = GetActiveWindow();
+
+	if (wndUnderMouse && wndUnderMouse->m_hWnd == m_hWnd && wndActive)
+	{
+		if (!m_bMouseOnButton)
+		{
+			m_bMouseOnButton = TRUE;
+
+			Invalidate();
+
+#ifdef	BTNST_USE_SOUND
+			// Play sound ?
+			if (m_csSounds[0].lpszSound)
+				::PlaySound(m_csSounds[0].lpszSound, m_csSounds[0].hMod, m_csSounds[0].dwFlags);
+#endif
+
+			csTME.cbSize = sizeof(csTME);
+			csTME.dwFlags = TME_LEAVE;
+			csTME.hwndTrack = m_hWnd;
+			::_TrackMouseEvent(&csTME);
+		} // if
+	} else CancelHover();
+} // End of OnMouseMove
+
+// Handler for WM_MOUSELEAVE
+LRESULT CButtonST::OnMouseLeave(WPARAM wParam, LPARAM lParam)
+{
+	CancelHover();
+	return 0;
+} // End of OnMouseLeave
+
+BOOL CButtonST::OnClicked() 
+{	
+	SetFocus();
+
+#ifdef	BTNST_USE_SOUND
+	// Play sound ?
+	if (m_csSounds[1].lpszSound)
+		::PlaySound(m_csSounds[1].lpszSound, m_csSounds[1].hMod, m_csSounds[1].dwFlags);
+#endif
+
+	if (m_bIsCheckBox)
+	{
+		m_nCheck = !m_nCheck;
+		Invalidate();
+	} // if
+	else
+	{
+		// Handle the menu (if any)
+#ifdef	BTNST_USE_BCMENU
+		if (m_menuPopup.m_hMenu)
+#else
+		if (m_hMenu)
+#endif
+		{
+			CRect	rWnd;
+			GetWindowRect(rWnd);
+
+			m_bMenuDisplayed = TRUE;
+			Invalidate();
+
+#ifdef	BTNST_USE_BCMENU
+			BCMenu* psub = (BCMenu*)m_menuPopup.GetSubMenu(0);
+			if (m_csCallbacks.hWnd)	::SendMessage(m_csCallbacks.hWnd, m_csCallbacks.nMessage, (WPARAM)psub, m_csCallbacks.lParam);
+			DWORD dwRetValue = psub->TrackPopupMenu(TPM_LEFTALIGN | TPM_LEFTBUTTON | TPM_RIGHTBUTTON | TPM_NONOTIFY | TPM_RETURNCMD, rWnd.left, rWnd.bottom, this, NULL);
+#else
+			HMENU hSubMenu = ::GetSubMenu(m_hMenu, 0);
+			if (m_csCallbacks.hWnd)	::SendMessage(m_csCallbacks.hWnd, m_csCallbacks.nMessage, (WPARAM)hSubMenu, m_csCallbacks.lParam);
+			DWORD dwRetValue = ::TrackPopupMenuEx(hSubMenu, TPM_LEFTALIGN | TPM_LEFTBUTTON | TPM_RIGHTBUTTON | TPM_NONOTIFY | TPM_RETURNCMD, rWnd.left, rWnd.bottom, m_hParentWndMenu, NULL);
+#endif
+
+			m_bMenuDisplayed = FALSE;
+			Invalidate();
+
+			if (dwRetValue)
+				::PostMessage(m_hParentWndMenu, WM_COMMAND, MAKEWPARAM(dwRetValue, 0), (LPARAM)NULL);
+		} // if
+		else
+		{
+			// Handle the URL (if any)
+			if (_tcslen(m_szURL) > 0)
+			{
+				SHELLEXECUTEINFO	csSEI;
+
+				memset(&csSEI, 0, sizeof(csSEI));
+				csSEI.cbSize = sizeof(SHELLEXECUTEINFO);
+				csSEI.fMask = SEE_MASK_FLAG_NO_UI;
+				csSEI.lpVerb = _T("open");
+				csSEI.lpFile = m_szURL;
+				csSEI.nShow = SW_SHOWMAXIMIZED;
+				::ShellExecuteEx(&csSEI);
+			} // if
+		} // else
+	} // else
+
+	return FALSE;
+} // End of OnClicked
+
+void CButtonST::DrawItem(LPDRAWITEMSTRUCT lpDIS)
+{
+	CDC*	pDC = CDC::FromHandle(lpDIS->hDC);
+
+	// Checkbox?
+	if (m_bIsCheckBox)
+	{
+		m_bIsPressed  =  (lpDIS->itemState & ODS_SELECTED) || (m_nCheck != 0);
+	} // if
+	else	// Normal button OR other button style ...
+	{
+		m_bIsPressed = (lpDIS->itemState & ODS_SELECTED);
+
+		// If there is a menu and it's displayed, draw the button as pressed
+		if (
+#ifdef	BTNST_USE_BCMENU
+			m_menuPopup.m_hMenu 
+#else
+			m_hMenu 
+#endif
+			&& m_bMenuDisplayed)	m_bIsPressed = TRUE;
+	} // else
+
+	m_bIsFocused  = (lpDIS->itemState & ODS_FOCUS);
+	m_bIsDisabled = (lpDIS->itemState & ODS_DISABLED);
+
+	CRect itemRect = lpDIS->rcItem;
+
+	pDC->SetBkMode(TRANSPARENT);
+
+	// Prepare draw... paint button background
+
+	// Draw transparent?
+	if (m_bDrawTransparent)
+		PaintBk(pDC);
+	else
+		OnDrawBackground(pDC, &itemRect);
+
+	// Draw button border
+	OnDrawBorder(pDC, &itemRect);
+
+	// Read the button's title
+	CString sTitle;
+	GetWindowText(sTitle);
+
+	CRect captionRect = lpDIS->rcItem;
+
+	// Draw the icon
+	if (m_csIcons[0].hIcon)
+	{
+		DrawTheIcon(pDC, !sTitle.IsEmpty(), &lpDIS->rcItem, &captionRect, m_bIsPressed, m_bIsDisabled);
+	} // if
+
+	if (m_csBitmaps[0].hBitmap)
+	{
+		pDC->SetBkColor(RGB(255,255,255));
+		DrawTheBitmap(pDC, !sTitle.IsEmpty(), &lpDIS->rcItem, &captionRect, m_bIsPressed, m_bIsDisabled);
+	} // if
+
+	// Write the button title (if any)
+	if (sTitle.IsEmpty() == FALSE)
+	{
+		DrawTheText(pDC, (LPCTSTR)sTitle, &lpDIS->rcItem, &captionRect, m_bIsPressed, m_bIsDisabled);
+	} // if
+
+	if (m_bIsFlat == FALSE || (m_bIsFlat && m_bDrawFlatFocus))
+	{
+		// Draw the focus rect
+		if (m_bIsFocused)
+		{
+			CRect focusRect = itemRect;
+			focusRect.DeflateRect(3, 3);
+			pDC->DrawFocusRect(&focusRect);
+		} // if
+	} // if
+} // End of DrawItem
+
+void CButtonST::PaintBk(CDC* pDC)
+{
+	CClientDC clDC(GetParent());
+	CRect rect;
+	CRect rect1;
+
+	GetClientRect(rect);
+
+	GetWindowRect(rect1);
+	GetParent()->ScreenToClient(rect1);
+
+	if (m_dcBk.m_hDC == NULL)
+	{
+		m_dcBk.CreateCompatibleDC(&clDC);
+		m_bmpBk.CreateCompatibleBitmap(&clDC, rect.Width(), rect.Height());
+		m_pbmpOldBk = m_dcBk.SelectObject(&m_bmpBk);
+		m_dcBk.BitBlt(0, 0, rect.Width(), rect.Height(), &clDC, rect1.left, rect1.top, SRCCOPY);
+	} // if
+
+	pDC->BitBlt(0, 0, rect.Width(), rect.Height(), &m_dcBk, 0, 0, SRCCOPY);
+} // End of PaintBk
+
+HBITMAP CButtonST::CreateBitmapMask(HBITMAP hSourceBitmap, DWORD dwWidth, DWORD dwHeight, COLORREF crTransColor)
+{
+	HBITMAP		hMask		= NULL;
+	HDC			hdcSrc		= NULL;
+	HDC			hdcDest		= NULL;
+	HBITMAP		hbmSrcT		= NULL;
+	HBITMAP		hbmDestT	= NULL;
+	COLORREF	crSaveBk;
+	COLORREF	crSaveDestText;
+
+	hMask = ::CreateBitmap(dwWidth, dwHeight, 1, 1, NULL);
+	if (hMask == NULL)	return NULL;
+
+	hdcSrc	= ::CreateCompatibleDC(NULL);
+	hdcDest	= ::CreateCompatibleDC(NULL);
+
+	hbmSrcT = (HBITMAP)::SelectObject(hdcSrc, hSourceBitmap);
+	hbmDestT = (HBITMAP)::SelectObject(hdcDest, hMask);
+
+	crSaveBk = ::SetBkColor(hdcSrc, crTransColor);
+
+	::BitBlt(hdcDest, 0, 0, dwWidth, dwHeight, hdcSrc, 0, 0, SRCCOPY);
+
+	crSaveDestText = ::SetTextColor(hdcSrc, RGB(255, 255, 255));
+	::SetBkColor(hdcSrc,RGB(0, 0, 0));
+
+	::BitBlt(hdcSrc, 0, 0, dwWidth, dwHeight, hdcDest, 0, 0, SRCAND);
+
+	SetTextColor(hdcDest, crSaveDestText);
+
+	::SetBkColor(hdcSrc, crSaveBk);
+	::SelectObject(hdcSrc, hbmSrcT);
+	::SelectObject(hdcDest, hbmDestT);
+
+	::DeleteDC(hdcSrc);
+	::DeleteDC(hdcDest);
+
+	return hMask;
+} // End of CreateBitmapMask
+
+//
+// Parameters:
+//		[IN]	bHasTitle
+//				TRUE if the button has a text
+//		[IN]	rpItem
+//				A pointer to a RECT structure indicating the allowed paint area
+//		[IN/OUT]rpTitle
+//				A pointer to a CRect object indicating the paint area reserved for the
+//				text. This structure will be modified if necessary.
+//		[IN]	bIsPressed
+//				TRUE if the button is currently pressed
+//		[IN]	dwWidth
+//				Width of the image (icon or bitmap)
+//		[IN]	dwHeight
+//				Height of the image (icon or bitmap)
+//		[OUT]	rpImage
+//				A pointer to a CRect object that will receive the area available to the image
+//
+void CButtonST::PrepareImageRect(BOOL bHasTitle, RECT* rpItem, CRect* rpTitle, BOOL bIsPressed, DWORD dwWidth, DWORD dwHeight, CRect* rpImage)
+{
+	CRect rBtn;
+
+	rpImage->CopyRect(rpItem);
+
+	switch (m_byAlign)
+	{
+		case ST_ALIGN_HORIZ:
+			if (bHasTitle == FALSE)
+			{
+				// Center image horizontally
+				rpImage->left += ((rpImage->Width() - (long)dwWidth)/2);
+			}
+			else
+			{
+				// Image must be placed just inside the focus rect
+				rpImage->left += m_ptImageOrg.x;  
+				rpTitle->left += dwWidth + m_ptImageOrg.x;
+			}
+			// Center image vertically
+			rpImage->top += ((rpImage->Height() - (long)dwHeight)/2);
+			break;
+
+		case ST_ALIGN_HORIZ_RIGHT:
+			GetClientRect(&rBtn);
+			if (bHasTitle == FALSE)
+			{
+				// Center image horizontally
+				rpImage->left += ((rpImage->Width() - (long)dwWidth)/2);
+			}
+			else
+			{
+				// Image must be placed just inside the focus rect
+				rpTitle->right = rpTitle->Width() - dwWidth - m_ptImageOrg.x;
+				rpTitle->left = m_ptImageOrg.x;
+				rpImage->left = rBtn.right - dwWidth - m_ptImageOrg.x;
+				// Center image vertically
+				rpImage->top += ((rpImage->Height() - (long)dwHeight)/2);
+			}
+			break;
+		
+		case ST_ALIGN_VERT:
+			// Center image horizontally
+			rpImage->left += ((rpImage->Width() - (long)dwWidth)/2);
+			if (bHasTitle == FALSE)
+			{
+				// Center image vertically
+				rpImage->top += ((rpImage->Height() - (long)dwHeight)/2);           
+			}
+			else
+			{
+				rpImage->top = m_ptImageOrg.y;
+				rpTitle->top += dwHeight;
+			}
+			break;
+
+		case ST_ALIGN_OVERLAP:
+			break;
+	} // switch
+    
+	// If button is pressed then press image also
+	if (bIsPressed && m_bIsCheckBox == FALSE)
+		rpImage->OffsetRect(m_ptPressedOffset.x, m_ptPressedOffset.y);
+} // End of PrepareImageRect
+
+void CButtonST::DrawTheIcon(CDC* pDC, BOOL bHasTitle, RECT* rpItem, CRect* rpCaption, BOOL bIsPressed, BOOL bIsDisabled)
+{
+	BYTE		byIndex		= 0;
+
+	// Select the icon to use
+	if ((m_bIsCheckBox && bIsPressed) || (!m_bIsCheckBox && (bIsPressed || m_bMouseOnButton)))
+		byIndex = 0;
+	else
+		byIndex = (m_csIcons[1].hIcon == NULL ? 0 : 1);
+
+	CRect	rImage;
+	PrepareImageRect(bHasTitle, rpItem, rpCaption, bIsPressed, m_csIcons[byIndex].dwWidth, m_csIcons[byIndex].dwHeight, &rImage);
+
+	// Ole'!
+	pDC->DrawState(	rImage.TopLeft(),
+					rImage.Size(), 
+					m_csIcons[byIndex].hIcon,
+					(bIsDisabled ? DSS_DISABLED : DSS_NORMAL), 
+					(CBrush*)NULL);
+} // End of DrawTheIcon
+
+void CButtonST::DrawTheBitmap(CDC* pDC, BOOL bHasTitle, RECT* rpItem, CRect* rpCaption, BOOL bIsPressed, BOOL bIsDisabled)
+{
+	HDC			hdcBmpMem	= NULL;
+	HBITMAP		hbmOldBmp	= NULL;
+	HDC			hdcMem		= NULL;
+	HBITMAP		hbmT		= NULL;
+
+	BYTE		byIndex		= 0;
+
+	// Select the bitmap to use
+	if ((m_bIsCheckBox && bIsPressed) || (!m_bIsCheckBox && (bIsPressed || m_bMouseOnButton)))
+		byIndex = 0;
+	else
+		byIndex = (m_csBitmaps[1].hBitmap == NULL ? 0 : 1);
+
+	CRect	rImage;
+	PrepareImageRect(bHasTitle, rpItem, rpCaption, bIsPressed, m_csBitmaps[byIndex].dwWidth, m_csBitmaps[byIndex].dwHeight, &rImage);
+
+	hdcBmpMem = ::CreateCompatibleDC(pDC->m_hDC);
+
+	hbmOldBmp = (HBITMAP)::SelectObject(hdcBmpMem, m_csBitmaps[byIndex].hBitmap);
+
+	hdcMem = ::CreateCompatibleDC(NULL);
+
+	hbmT = (HBITMAP)::SelectObject(hdcMem, m_csBitmaps[byIndex].hMask);
+
+	if (bIsDisabled && m_bShowDisabledBitmap)
+	{
+		HDC		hDC = NULL;
+		HBITMAP	hBitmap = NULL;
+
+		hDC = ::CreateCompatibleDC(pDC->m_hDC);
+		hBitmap = ::CreateCompatibleBitmap(pDC->m_hDC, m_csBitmaps[byIndex].dwWidth, m_csBitmaps[byIndex].dwHeight);
+		HBITMAP	hOldBmp2 = (HBITMAP)::SelectObject(hDC, hBitmap);
+
+		RECT	rRect;
+		rRect.left = 0;
+		rRect.top = 0;
+		rRect.right = rImage.right + 1;
+		rRect.bottom = rImage.bottom + 1;
+		::FillRect(hDC, &rRect, (HBRUSH)RGB(255, 255, 255));
+
+		COLORREF crOldColor = ::SetBkColor(hDC, RGB(255,255,255));
+
+		::BitBlt(hDC, 0, 0, m_csBitmaps[byIndex].dwWidth, m_csBitmaps[byIndex].dwHeight, hdcMem, 0, 0, SRCAND);
+		::BitBlt(hDC, 0, 0, m_csBitmaps[byIndex].dwWidth, m_csBitmaps[byIndex].dwHeight, hdcBmpMem, 0, 0, SRCPAINT);
+
+		::SetBkColor(hDC, crOldColor);
+		::SelectObject(hDC, hOldBmp2);
+		::DeleteDC(hDC);
+
+		pDC->DrawState(	CPoint(rImage.left/*+1*/, rImage.top), 
+						CSize(m_csBitmaps[byIndex].dwWidth, m_csBitmaps[byIndex].dwHeight), 
+						hBitmap, DST_BITMAP | DSS_DISABLED);
+
+		::DeleteObject(hBitmap);
+	} // if
+	else
+	{
+		::BitBlt(pDC->m_hDC, rImage.left, rImage.top, m_csBitmaps[byIndex].dwWidth, m_csBitmaps[byIndex].dwHeight, hdcMem, 0, 0, SRCAND);
+
+		::BitBlt(pDC->m_hDC, rImage.left, rImage.top, m_csBitmaps[byIndex].dwWidth, m_csBitmaps[byIndex].dwHeight, hdcBmpMem, 0, 0, SRCPAINT);
+	} // else
+
+	::SelectObject(hdcMem, hbmT);
+	::DeleteDC(hdcMem);
+
+	::SelectObject(hdcBmpMem, hbmOldBmp);
+	::DeleteDC(hdcBmpMem);
+} // End of DrawTheBitmap
+
+void CButtonST::DrawTheText(CDC* pDC, LPCTSTR lpszText, RECT* rpItem, CRect* rpCaption, BOOL bIsPressed, BOOL bIsDisabled)
+{
+	// Draw the button's title
+	// If button is pressed then "press" title also
+	if (m_bIsPressed && m_bIsCheckBox == FALSE)
+		rpCaption->OffsetRect(m_ptPressedOffset.x, m_ptPressedOffset.y);
+
+	// ONLY FOR DEBUG 
+	//CBrush brBtnShadow(RGB(255, 0, 0));
+	//pDC->FrameRect(rCaption, &brBtnShadow);
+
+	// Center text
+	CRect centerRect = rpCaption;
+	pDC->DrawText(lpszText, -1, rpCaption, DT_WORDBREAK | DT_CENTER | DT_CALCRECT);
+	rpCaption->OffsetRect((centerRect.Width() - rpCaption->Width())/2, (centerRect.Height() - rpCaption->Height())/2);
+	/* RFU
+	rpCaption->OffsetRect(0, (centerRect.Height() - rpCaption->Height())/2);
+	rpCaption->OffsetRect((centerRect.Width() - rpCaption->Width())-4, (centerRect.Height() - rpCaption->Height())/2);
+	*/
+
+	pDC->SetBkMode(TRANSPARENT);
+	/*
+	pDC->DrawState(rCaption->TopLeft(), rCaption->Size(), (LPCTSTR)sTitle, (bIsDisabled ? DSS_DISABLED : DSS_NORMAL), 
+					TRUE, 0, (CBrush*)NULL);
+	*/
+	if (m_bIsDisabled)
+	{
+		rpCaption->OffsetRect(1, 1);
+		pDC->SetTextColor(::GetSysColor(COLOR_3DHILIGHT));
+		pDC->DrawText(lpszText, -1, rpCaption, DT_WORDBREAK | DT_CENTER);
+		rpCaption->OffsetRect(-1, -1);
+		pDC->SetTextColor(::GetSysColor(COLOR_3DSHADOW));
+		pDC->DrawText(lpszText, -1, rpCaption, DT_WORDBREAK | DT_CENTER);
+	} // if
+	else
+	{
+		if (m_bMouseOnButton || m_bIsPressed) 
+		{
+			pDC->SetTextColor(m_crColors[BTNST_COLOR_FG_IN]);
+			pDC->SetBkColor(m_crColors[BTNST_COLOR_BK_IN]);
+		} // if
+		else 
+		{
+			if (m_bIsFocused)
+			{ 
+				pDC->SetTextColor(m_crColors[BTNST_COLOR_FG_FOCUS]); 
+				pDC->SetBkColor(m_crColors[BTNST_COLOR_BK_FOCUS]); 
+			} // if
+			else 
+			{
+				pDC->SetTextColor(m_crColors[BTNST_COLOR_FG_OUT]); 
+				pDC->SetBkColor(m_crColors[BTNST_COLOR_BK_OUT]); 
+			} // else
+		} // else
+		pDC->DrawText(lpszText, -1, rpCaption, DT_WORDBREAK | DT_CENTER);
+	} // if
+} // End of DrawTheText
+
+// This function creates a grayscale bitmap starting from a given bitmap.
+// The resulting bitmap will have the same size of the original one.
+//
+// Parameters:
+//		[IN]	hBitmap
+//				Handle to the original bitmap.
+//		[IN]	dwWidth
+//				Specifies the bitmap width, in pixels.
+//		[IN]	dwHeight
+//				Specifies the bitmap height, in pixels.
+//		[IN]	crTrans
+//				Color to be used as transparent color. This color will be left unchanged.
+//
+// Return value:
+//		If the function succeeds, the return value is the handle to the newly created
+//		grayscale bitmap.
+//		If the function fails, the return value is NULL.
+//
+HBITMAP CButtonST::CreateGrayscaleBitmap(HBITMAP hBitmap, DWORD dwWidth, DWORD dwHeight, COLORREF crTrans)
+{
+	HBITMAP		hGrayBitmap = NULL;
+	HDC			hMainDC = NULL, hMemDC1 = NULL, hMemDC2 = NULL;
+	HBITMAP		hOldBmp1 = NULL, hOldBmp2 = NULL;
+
+	hMainDC = ::GetDC(NULL);
+	if (hMainDC == NULL)	return NULL;
+	hMemDC1 = ::CreateCompatibleDC(hMainDC);
+	if (hMemDC1 == NULL)
+	{
+		::ReleaseDC(NULL, hMainDC);
+		return NULL;
+	} // if
+	hMemDC2 = ::CreateCompatibleDC(hMainDC);
+	if (hMemDC2 == NULL)
+	{
+		::DeleteDC(hMemDC1);
+		::ReleaseDC(NULL, hMainDC);
+		return NULL;
+	} // if
+
+	hGrayBitmap = ::CreateCompatibleBitmap(hMainDC, dwWidth, dwHeight);
+	if (hGrayBitmap)
+	{
+		hOldBmp1 = (HBITMAP)::SelectObject(hMemDC1, hGrayBitmap);
+		hOldBmp2 = (HBITMAP)::SelectObject(hMemDC2, hBitmap);
+
+		//::BitBlt(hMemDC1, 0, 0, dwWidth, dwHeight, hMemDC2, 0, 0, SRCCOPY);
+
+		DWORD		dwLoopY = 0, dwLoopX = 0;
+		COLORREF	crPixel = 0;
+		BYTE		byNewPixel = 0;
+
+		for (dwLoopY = 0; dwLoopY < dwHeight; dwLoopY++)
+		{
+			for (dwLoopX = 0; dwLoopX < dwWidth; dwLoopX++)
+			{
+				crPixel = ::GetPixel(hMemDC2, dwLoopX, dwLoopY);
+				byNewPixel = (BYTE)((GetRValue(crPixel) * 0.299) + (GetGValue(crPixel) * 0.587) + (GetBValue(crPixel) * 0.114));
+
+				if (crPixel != crTrans)
+					::SetPixel(hMemDC1, dwLoopX, dwLoopY, RGB(byNewPixel, byNewPixel, byNewPixel));
+				else
+					::SetPixel(hMemDC1, dwLoopX, dwLoopY, crPixel);
+			} // for
+		} // for
+
+		::SelectObject(hMemDC1, hOldBmp1);
+		::SelectObject(hMemDC2, hOldBmp2);
+	} // if
+
+	::DeleteDC(hMemDC1);
+	::DeleteDC(hMemDC2);
+	::ReleaseDC(NULL, hMainDC);
+
+	return hGrayBitmap;
+} // End of CreateGrayscaleBitmap
+
+// This function creates a bitmap that is 25% darker than the original.
+// The resulting bitmap will have the same size of the original one.
+//
+// Parameters:
+//		[IN]	hBitmap
+//				Handle to the original bitmap.
+//		[IN]	dwWidth
+//				Specifies the bitmap width, in pixels.
+//		[IN]	dwHeight
+//				Specifies the bitmap height, in pixels.
+//		[IN]	crTrans
+//				Color to be used as transparent color. This color will be left unchanged.
+//
+// Return value:
+//		If the function succeeds, the return value is the handle to the newly created
+//		darker bitmap.
+//		If the function fails, the return value is NULL.
+//
+HBITMAP CButtonST::CreateDarkerBitmap(HBITMAP hBitmap, DWORD dwWidth, DWORD dwHeight, COLORREF crTrans)
+{
+	HBITMAP		hGrayBitmap = NULL;
+	HDC			hMainDC = NULL, hMemDC1 = NULL, hMemDC2 = NULL;
+	HBITMAP		hOldBmp1 = NULL, hOldBmp2 = NULL;
+
+	hMainDC = ::GetDC(NULL);
+	if (hMainDC == NULL)	return NULL;
+	hMemDC1 = ::CreateCompatibleDC(hMainDC);
+	if (hMemDC1 == NULL)
+	{
+		::ReleaseDC(NULL, hMainDC);
+		return NULL;
+	} // if
+	hMemDC2 = ::CreateCompatibleDC(hMainDC);
+	if (hMemDC2 == NULL)
+	{
+		::DeleteDC(hMemDC1);
+		::ReleaseDC(NULL, hMainDC);
+		return NULL;
+	} // if
+
+	hGrayBitmap = ::CreateCompatibleBitmap(hMainDC, dwWidth, dwHeight);
+	if (hGrayBitmap)
+	{
+		hOldBmp1 = (HBITMAP)::SelectObject(hMemDC1, hGrayBitmap);
+		hOldBmp2 = (HBITMAP)::SelectObject(hMemDC2, hBitmap);
+
+		//::BitBlt(hMemDC1, 0, 0, dwWidth, dwHeight, hMemDC2, 0, 0, SRCCOPY);
+
+		DWORD		dwLoopY = 0, dwLoopX = 0;
+		COLORREF	crPixel = 0;
+
+		for (dwLoopY = 0; dwLoopY < dwHeight; dwLoopY++)
+		{
+			for (dwLoopX = 0; dwLoopX < dwWidth; dwLoopX++)
+			{
+				crPixel = ::GetPixel(hMemDC2, dwLoopX, dwLoopY);
+
+				if (crPixel != crTrans)
+					::SetPixel(hMemDC1, dwLoopX, dwLoopY, DarkenColor(crPixel, 0.25));
+				else
+					::SetPixel(hMemDC1, dwLoopX, dwLoopY, crPixel);
+			} // for
+		} // for
+
+		::SelectObject(hMemDC1, hOldBmp1);
+		::SelectObject(hMemDC2, hOldBmp2);
+	} // if
+
+	::DeleteDC(hMemDC1);
+	::DeleteDC(hMemDC2);
+	::ReleaseDC(NULL, hMainDC);
+
+	return hGrayBitmap;
+} // End of CreateDarkerBitmap
+
+// This function creates a grayscale icon starting from a given icon.
+// The resulting icon will have the same size of the original one.
+//
+// Parameters:
+//		[IN]	hIcon
+//				Handle to the original icon.
+//
+// Return value:
+//		If the function succeeds, the return value is the handle to the newly created
+//		grayscale icon.
+//		If the function fails, the return value is NULL.
+//
+// Updates:
+//		26/Nov/2002	Restored 1 BitBlt operation
+//		03/May/2002	Removed dependancy from m_hWnd
+//					Removed 1 BitBlt operation
+//
+HICON CButtonST::CreateGrayscaleIcon(HICON hIcon)
+{
+	HICON		hGrayIcon = NULL;
+	HDC			hMainDC = NULL, hMemDC1 = NULL, hMemDC2 = NULL;
+	BITMAP		bmp;
+	HBITMAP		hOldBmp1 = NULL, hOldBmp2 = NULL;
+	ICONINFO	csII, csGrayII;
+	BOOL		bRetValue = FALSE;
+
+	bRetValue = ::GetIconInfo(hIcon, &csII);
+	if (bRetValue == FALSE)	return NULL;
+
+	hMainDC = ::GetDC(NULL);
+	hMemDC1 = ::CreateCompatibleDC(hMainDC);
+	hMemDC2 = ::CreateCompatibleDC(hMainDC);
+	if (hMainDC == NULL || hMemDC1 == NULL || hMemDC2 == NULL)	return NULL;
+  
+	if (::GetObject(csII.hbmColor, sizeof(BITMAP), &bmp))
+	{
+		DWORD	dwWidth = csII.xHotspot*2;
+		DWORD	dwHeight = csII.yHotspot*2;
+
+		csGrayII.hbmColor = ::CreateBitmap(dwWidth, dwHeight, bmp.bmPlanes, bmp.bmBitsPixel, NULL);
+		if (csGrayII.hbmColor)
+		{
+			hOldBmp1 = (HBITMAP)::SelectObject(hMemDC1, csII.hbmColor);
+			hOldBmp2 = (HBITMAP)::SelectObject(hMemDC2, csGrayII.hbmColor);
+
+			//::BitBlt(hMemDC2, 0, 0, dwWidth, dwHeight, hMemDC1, 0, 0, SRCCOPY);
+
+			DWORD		dwLoopY = 0, dwLoopX = 0;
+			COLORREF	crPixel = 0;
+			BYTE		byNewPixel = 0;
+
+			for (dwLoopY = 0; dwLoopY < dwHeight; dwLoopY++)
+			{
+				for (dwLoopX = 0; dwLoopX < dwWidth; dwLoopX++)
+				{
+					crPixel = ::GetPixel(hMemDC1, dwLoopX, dwLoopY);
+					byNewPixel = (BYTE)((GetRValue(crPixel) * 0.299) + (GetGValue(crPixel) * 0.587) + (GetBValue(crPixel) * 0.114));
+
+					if (crPixel)	
+						::SetPixel(hMemDC2, dwLoopX, dwLoopY, RGB(byNewPixel, byNewPixel, byNewPixel));
+					else
+						::SetPixel(hMemDC2, dwLoopX, dwLoopY, crPixel);
+				} // for
+			} // for
+
+			::SelectObject(hMemDC1, hOldBmp1);
+			::SelectObject(hMemDC2, hOldBmp2);
+
+			csGrayII.hbmMask = csII.hbmMask;
+
+			csGrayII.fIcon = TRUE;
+			hGrayIcon = ::CreateIconIndirect(&csGrayII);
+		} // if
+
+		::DeleteObject(csGrayII.hbmColor);
+		//::DeleteObject(csGrayII.hbmMask);
+	} // if
+
+	::DeleteObject(csII.hbmColor);
+	::DeleteObject(csII.hbmMask);
+	::DeleteDC(hMemDC1);
+	::DeleteDC(hMemDC2);
+	::ReleaseDC(NULL, hMainDC);
+
+	return hGrayIcon;
+} // End of CreateGrayscaleIcon
+
+// This function creates a icon that is 25% darker than the original.
+// The resulting icon will have the same size of the original one.
+//
+// Parameters:
+//		[IN]	hIcon
+//				Handle to the original icon.
+//
+// Return value:
+//		If the function succeeds, the return value is the handle to the newly created
+//		darker icon.
+//		If the function fails, the return value is NULL.
+//
+HICON CButtonST::CreateDarkerIcon(HICON hIcon)
+{
+	HICON		hGrayIcon = NULL;
+	HDC			hMainDC = NULL, hMemDC1 = NULL, hMemDC2 = NULL;
+	BITMAP		bmp;
+	HBITMAP		hOldBmp1 = NULL, hOldBmp2 = NULL;
+	ICONINFO	csII, csGrayII;
+	BOOL		bRetValue = FALSE;
+
+	bRetValue = ::GetIconInfo(hIcon, &csII);
+	if (bRetValue == FALSE)	return NULL;
+
+	hMainDC = ::GetDC(NULL);
+	hMemDC1 = ::CreateCompatibleDC(hMainDC);
+	hMemDC2 = ::CreateCompatibleDC(hMainDC);
+	if (hMainDC == NULL || hMemDC1 == NULL || hMemDC2 == NULL)	return NULL;
+  
+	if (::GetObject(csII.hbmColor, sizeof(BITMAP), &bmp))
+	{
+		DWORD	dwWidth = csII.xHotspot*2;
+		DWORD	dwHeight = csII.yHotspot*2;
+
+		csGrayII.hbmColor = ::CreateBitmap(dwWidth, dwHeight, bmp.bmPlanes, bmp.bmBitsPixel, NULL);
+		if (csGrayII.hbmColor)
+		{
+			hOldBmp1 = (HBITMAP)::SelectObject(hMemDC1, csII.hbmColor);
+			hOldBmp2 = (HBITMAP)::SelectObject(hMemDC2, csGrayII.hbmColor);
+
+			//::BitBlt(hMemDC2, 0, 0, dwWidth, dwHeight, hMemDC1, 0, 0, SRCCOPY);
+
+			DWORD		dwLoopY = 0, dwLoopX = 0;
+			COLORREF	crPixel = 0;
+
+			for (dwLoopY = 0; dwLoopY < dwHeight; dwLoopY++)
+			{
+				for (dwLoopX = 0; dwLoopX < dwWidth; dwLoopX++)
+				{
+					crPixel = ::GetPixel(hMemDC1, dwLoopX, dwLoopY);
+
+					if (crPixel)	
+						::SetPixel(hMemDC2, dwLoopX, dwLoopY, DarkenColor(crPixel, 0.25));
+					else
+						::SetPixel(hMemDC2, dwLoopX, dwLoopY, crPixel);
+				} // for
+			} // for
+
+			::SelectObject(hMemDC1, hOldBmp1);
+			::SelectObject(hMemDC2, hOldBmp2);
+
+			csGrayII.hbmMask = csII.hbmMask;
+
+			csGrayII.fIcon = TRUE;
+			hGrayIcon = ::CreateIconIndirect(&csGrayII);
+		} // if
+
+		::DeleteObject(csGrayII.hbmColor);
+		//::DeleteObject(csGrayII.hbmMask);
+	} // if
+
+	::DeleteObject(csII.hbmColor);
+	::DeleteObject(csII.hbmMask);
+	::DeleteDC(hMemDC1);
+	::DeleteDC(hMemDC2);
+	::ReleaseDC(NULL, hMainDC);
+
+	return hGrayIcon;
+} // End of CreateDarkerIcon
+
+COLORREF CButtonST::DarkenColor(COLORREF crColor, double dFactor)
+{
+	if (dFactor > 0.0 && dFactor <= 1.0)
+	{
+		BYTE red,green,blue,lightred,lightgreen,lightblue;
+		red = GetRValue(crColor);
+		green = GetGValue(crColor);
+		blue = GetBValue(crColor);
+		lightred = (BYTE)(red-(dFactor * red));
+		lightgreen = (BYTE)(green-(dFactor * green));
+		lightblue = (BYTE)(blue-(dFactor * blue));
+		crColor = RGB(lightred,lightgreen,lightblue);
+	} // if
+
+	return crColor;
+} // End of DarkenColor
+
+// This function assigns icons to the button.
+// Any previous icon or bitmap will be removed.
+//
+// Parameters:
+//		[IN]	nIconIn
+//				ID number of the icon resource to show when the mouse is over the button.
+//				Pass NULL to remove any icon from the button.
+//		[IN]	nCxDesiredIn
+//				Specifies the width, in pixels, of the icon to load.
+//		[IN]	nCyDesiredIn
+//				Specifies the height, in pixels, of the icon to load.
+//		[IN]	nIconOut
+//				ID number of the icon resource to show when the mouse is outside the button.
+//				Can be NULL.
+//				If this parameter is the special value BTNST_AUTO_GRAY (cast to int) the second
+//				icon will be automatically created starting from nIconIn and converted to grayscale.
+//				If this parameter is the special value BTNST_AUTO_DARKER (cast to int) the second
+//				icon will be automatically created 25% darker starting from nIconIn.
+//		[IN]	nCxDesiredOut
+//				Specifies the width, in pixels, of the icon to load.
+//		[IN]	nCyDesiredOut
+//				Specifies the height, in pixels, of the icon to load.
+//
+// Return value:
+//		BTNST_OK
+//			Function executed successfully.
+//		BTNST_INVALIDRESOURCE
+//			Failed loading the specified resource.
+//
+DWORD CButtonST::SetIcon(int nIconIn, int nCxDesiredIn, int nCyDesiredIn, int nIconOut, int nCxDesiredOut, int nCyDesiredOut)
+{
+	HICON		hIconIn			= NULL;
+	HICON		hIconOut		= NULL;
+	HINSTANCE	hInstResource	= NULL;
+
+	// Find correct resource handle
+	hInstResource = AfxFindResourceHandle(MAKEINTRESOURCE(nIconIn), RT_GROUP_ICON);
+
+	// Set icon when the mouse is IN the button
+	hIconIn = (HICON)::LoadImage(hInstResource, MAKEINTRESOURCE(nIconIn), IMAGE_ICON, nCxDesiredIn, nCyDesiredIn, 0);
+
+  	// Set icon when the mouse is OUT the button
+	switch (nIconOut)
+	{
+		case NULL:
+			break;
+		case (int)BTNST_AUTO_GRAY:
+			hIconOut = BTNST_AUTO_GRAY;
+			break;
+		case (int)BTNST_AUTO_DARKER:
+			hIconOut = BTNST_AUTO_DARKER;
+			break;
+		default:
+			hIconOut = (HICON)::LoadImage(hInstResource, MAKEINTRESOURCE(nIconOut), IMAGE_ICON, nCxDesiredOut, nCyDesiredOut, 0);
+			break;
+	} // switch
+
+	return SetIcon(hIconIn, hIconOut);
+} // End of SetIcon
+
+// This function assigns icons to the button.
+// Any previous icon or bitmap will be removed.
+//
+// Parameters:
+//		[IN]	nIconIn
+//				ID number of the icon resource to show when the mouse is over the button.
+//				Pass NULL to remove any icon from the button.
+//		[IN]	nIconOut
+//				ID number of the icon resource to show when the mouse is outside the button.
+//				Can be NULL.
+//				If this parameter is the special value BTNST_AUTO_GRAY (cast to int) the second
+//				icon will be automatically created starting from nIconIn and converted to grayscale.
+//				If this parameter is the special value BTNST_AUTO_DARKER (cast to int) the second
+//				icon will be automatically created 25% darker starting from nIconIn.
+//
+// Return value:
+//		BTNST_OK
+//			Function executed successfully.
+//		BTNST_INVALIDRESOURCE
+//			Failed loading the specified resource.
+//
+DWORD CButtonST::SetIcon(int nIconIn, int nIconOut)
+{
+	return SetIcon(nIconIn, 0, 0, nIconOut, 0, 0);
+} // End of SetIcon
+
+// This function assigns icons to the button.
+// Any previous icon or bitmap will be removed.
+//
+// Parameters:
+//		[IN]	hIconIn
+//				Handle fo the icon to show when the mouse is over the button.
+//				Pass NULL to remove any icon from the button.
+//		[IN]	hIconOut
+//				Handle to the icon to show when the mouse is outside the button.
+//				Can be NULL.
+//				If this parameter is the special value BTNST_AUTO_GRAY the second
+//				icon will be automatically created starting from hIconIn and converted to grayscale.
+//				If this parameter is the special value BTNST_AUTO_DARKER the second
+//				icon will be automatically created 25% darker starting from hIconIn.
+//
+// Return value:
+//		BTNST_OK
+//			Function executed successfully.
+//		BTNST_INVALIDRESOURCE
+//			Failed loading the specified resource.
+//
+DWORD CButtonST::SetIcon(HICON hIconIn, HICON hIconOut)
+{
+	BOOL		bRetValue;
+	ICONINFO	ii;
+
+	// Free any loaded resource
+	FreeResources();
+
+	if (hIconIn)
+	{
+		// Icon when mouse over button?
+		m_csIcons[0].hIcon = hIconIn;
+		// Get icon dimension
+		::ZeroMemory(&ii, sizeof(ICONINFO));
+		bRetValue = ::GetIconInfo(hIconIn, &ii);
+		if (bRetValue == FALSE)
+		{
+			FreeResources();
+			return BTNST_INVALIDRESOURCE;
+		} // if
+
+		m_csIcons[0].dwWidth	= (DWORD)(ii.xHotspot * 2);
+		m_csIcons[0].dwHeight	= (DWORD)(ii.yHotspot * 2);
+		::DeleteObject(ii.hbmMask);
+		::DeleteObject(ii.hbmColor);
+
+		// Icon when mouse outside button?
+		if (hIconOut)
+		{
+			switch ((int)hIconOut)
+			{
+				case (int)BTNST_AUTO_GRAY:
+					hIconOut = CreateGrayscaleIcon(hIconIn);
+					break;
+				case (int)BTNST_AUTO_DARKER:
+					hIconOut = CreateDarkerIcon(hIconIn);
+					break;
+			} // switch
+
+			m_csIcons[1].hIcon = hIconOut;
+			// Get icon dimension
+			::ZeroMemory(&ii, sizeof(ICONINFO));
+			bRetValue = ::GetIconInfo(hIconOut, &ii);
+			if (bRetValue == FALSE)
+			{
+				FreeResources();
+				return BTNST_INVALIDRESOURCE;
+			} // if
+
+			m_csIcons[1].dwWidth	= (DWORD)(ii.xHotspot * 2);
+			m_csIcons[1].dwHeight	= (DWORD)(ii.yHotspot * 2);
+			::DeleteObject(ii.hbmMask);
+			::DeleteObject(ii.hbmColor);
+		} // if
+	} // if
+
+	Invalidate();
+
+	return BTNST_OK;
+} // End of SetIcon
+
+// This function assigns bitmaps to the button.
+// Any previous icon or bitmap will be removed.
+//
+// Parameters:
+//		[IN]	nBitmapIn
+//				ID number of the bitmap resource to show when the mouse is over the button.
+//				Pass NULL to remove any bitmap from the button.
+//		[IN]	crTransColorIn
+//				Color (inside nBitmapIn) to be used as transparent color.
+//		[IN]	nBitmapOut
+//				ID number of the bitmap resource to show when the mouse is outside the button.
+//				Can be NULL.
+//		[IN]	crTransColorOut
+//				Color (inside nBitmapOut) to be used as transparent color.
+//
+// Return value:
+//		BTNST_OK
+//			Function executed successfully.
+//		BTNST_INVALIDRESOURCE
+//			Failed loading the specified resource.
+//		BTNST_FAILEDMASK
+//			Failed creating mask bitmap.
+//
+DWORD CButtonST::SetBitmaps(int nBitmapIn, COLORREF crTransColorIn, int nBitmapOut, COLORREF crTransColorOut)
+{
+	HBITMAP		hBitmapIn		= NULL;
+	HBITMAP		hBitmapOut		= NULL;
+	HINSTANCE	hInstResource	= NULL;
+	
+	// Find correct resource handle
+	hInstResource = AfxFindResourceHandle(MAKEINTRESOURCE(nBitmapIn), RT_BITMAP);
+
+	// Load bitmap In
+	hBitmapIn = (HBITMAP)::LoadImage(hInstResource, MAKEINTRESOURCE(nBitmapIn), IMAGE_BITMAP, 0, 0, 0);
+
+	// Load bitmap Out
+	switch (nBitmapOut)
+	{
+		case NULL:
+			break;
+		case (int)BTNST_AUTO_GRAY:
+			hBitmapOut = (HBITMAP)BTNST_AUTO_GRAY;
+			break;
+		case (int)BTNST_AUTO_DARKER:
+			hBitmapOut = (HBITMAP)BTNST_AUTO_DARKER;
+			break;
+		default:
+			hBitmapOut = (HBITMAP)::LoadImage(hInstResource, MAKEINTRESOURCE(nBitmapOut), IMAGE_BITMAP, 0, 0, 0);
+			break;
+	} // if
+
+	return SetBitmaps(hBitmapIn, crTransColorIn, hBitmapOut, crTransColorOut);
+} // End of SetBitmaps
+
+// This function assigns bitmaps to the button.
+// Any previous icon or bitmap will be removed.
+//
+// Parameters:
+//		[IN]	hBitmapIn
+//				Handle fo the bitmap to show when the mouse is over the button.
+//				Pass NULL to remove any bitmap from the button.
+//		[IN]	crTransColorIn
+//				Color (inside hBitmapIn) to be used as transparent color.
+//		[IN]	hBitmapOut
+//				Handle to the bitmap to show when the mouse is outside the button.
+//				Can be NULL.
+//		[IN]	crTransColorOut
+//				Color (inside hBitmapOut) to be used as transparent color.
+//
+// Return value:
+//		BTNST_OK
+//			Function executed successfully.
+//		BTNST_INVALIDRESOURCE
+//			Failed loading the specified resource.
+//		BTNST_FAILEDMASK
+//			Failed creating mask bitmap.
+//
+DWORD CButtonST::SetBitmaps(HBITMAP hBitmapIn, COLORREF crTransColorIn, HBITMAP hBitmapOut, COLORREF crTransColorOut)
+{
+	int		nRetValue = 0;
+	BITMAP	csBitmapSize;
+
+	// Free any loaded resource
+	FreeResources();
+
+	if (hBitmapIn)
+	{
+		m_csBitmaps[0].hBitmap = hBitmapIn;
+		m_csBitmaps[0].crTransparent = crTransColorIn;
+		// Get bitmap size
+		nRetValue = ::GetObject(hBitmapIn, sizeof(csBitmapSize), &csBitmapSize);
+		if (nRetValue == 0)
+		{
+			FreeResources();
+			return BTNST_INVALIDRESOURCE;
+		} // if
+		m_csBitmaps[0].dwWidth = (DWORD)csBitmapSize.bmWidth;
+		m_csBitmaps[0].dwHeight = (DWORD)csBitmapSize.bmHeight;
+
+		// Create grayscale/darker bitmap BEFORE mask (of hBitmapIn)
+		switch ((int)hBitmapOut)
+		{
+			case (int)BTNST_AUTO_GRAY:
+				hBitmapOut = CreateGrayscaleBitmap(hBitmapIn, m_csBitmaps[0].dwWidth, m_csBitmaps[0].dwHeight, crTransColorIn);
+				m_csBitmaps[1].hBitmap = hBitmapOut;
+				crTransColorOut = crTransColorIn;
+				break;
+			case (int)BTNST_AUTO_DARKER:
+				hBitmapOut = CreateDarkerBitmap(hBitmapIn, m_csBitmaps[0].dwWidth, m_csBitmaps[0].dwHeight, crTransColorIn);
+				m_csBitmaps[1].hBitmap = hBitmapOut;
+				crTransColorOut = crTransColorIn;
+				break;
+		} // switch
+
+		// Create mask for bitmap In
+		m_csBitmaps[0].hMask = CreateBitmapMask(hBitmapIn, m_csBitmaps[0].dwWidth, m_csBitmaps[0].dwHeight, crTransColorIn);
+		if (m_csBitmaps[0].hMask == NULL)
+		{
+			FreeResources();
+			return BTNST_FAILEDMASK;
+		} // if
+
+		if (hBitmapOut)
+		{
+			m_csBitmaps[1].hBitmap = hBitmapOut;
+			m_csBitmaps[1].crTransparent = crTransColorOut;
+			// Get bitmap size
+			nRetValue = ::GetObject(hBitmapOut, sizeof(csBitmapSize), &csBitmapSize);
+			if (nRetValue == 0)
+			{
+				FreeResources();
+				return BTNST_INVALIDRESOURCE;
+			} // if
+			m_csBitmaps[1].dwWidth = (DWORD)csBitmapSize.bmWidth;
+			m_csBitmaps[1].dwHeight = (DWORD)csBitmapSize.bmHeight;
+
+			// Create mask for bitmap Out
+			m_csBitmaps[1].hMask = CreateBitmapMask(hBitmapOut, m_csBitmaps[1].dwWidth, m_csBitmaps[1].dwHeight, crTransColorOut);
+			if (m_csBitmaps[1].hMask == NULL)
+			{
+				FreeResources();
+				return BTNST_FAILEDMASK;
+			} // if
+		} // if
+	} // if
+
+	Invalidate();
+
+	return BTNST_OK;
+} // End of SetBitmaps
+
+// This functions sets the button to have a standard or flat style.
+//
+// Parameters:
+//		[IN]	bFlat
+//				If TRUE the button will have a flat style, else
+//				will have a standard style.
+//				By default, CButtonST buttons are flat.
+//		[IN]	bRepaint
+//				If TRUE the control will be repainted.
+//
+// Return value:
+//		BTNST_OK
+//			Function executed successfully.
+//
+DWORD CButtonST::SetFlat(BOOL bFlat, BOOL bRepaint)
+{
+	m_bIsFlat = bFlat;
+	if (bRepaint)	Invalidate();
+
+	return BTNST_OK;
+} // End of SetFlat
+
+// This function sets the alignment type between icon/bitmap and text.
+//
+// Parameters:
+//		[IN]	byAlign
+//				Alignment type. Can be one of the following values:
+//				ST_ALIGN_HORIZ			Icon/bitmap on the left, text on the right
+//				ST_ALIGN_VERT			Icon/bitmap on the top, text on the bottom
+//				ST_ALIGN_HORIZ_RIGHT	Icon/bitmap on the right, text on the left
+//				ST_ALIGN_OVERLAP		Icon/bitmap on the same space as text
+//				By default, CButtonST buttons have ST_ALIGN_HORIZ alignment.
+//		[IN]	bRepaint
+//				If TRUE the control will be repainted.
+//
+// Return value:
+//		BTNST_OK
+//			Function executed successfully.
+//		BTNST_INVALIDALIGN
+//			Alignment type not supported.
+//
+DWORD CButtonST::SetAlign(BYTE byAlign, BOOL bRepaint)
+{
+	switch (byAlign)
+	{    
+		case ST_ALIGN_HORIZ:
+		case ST_ALIGN_HORIZ_RIGHT:
+		case ST_ALIGN_VERT:
+		case ST_ALIGN_OVERLAP:
+			m_byAlign = byAlign;
+			if (bRepaint)	Invalidate();
+			return BTNST_OK;
+			break;
+	} // switch
+
+	return BTNST_INVALIDALIGN;
+} // End of SetAlign
+
+// This function sets the pressed style.
+//
+// Parameters:
+//		[IN]	byStyle
+//				Pressed style. Can be one of the following values:
+//				BTNST_PRESSED_LEFTRIGHT		Pressed style from left to right (as usual)
+//				BTNST_PRESSED_TOPBOTTOM		Pressed style from top to bottom
+//				By default, CButtonST buttons have BTNST_PRESSED_LEFTRIGHT style.
+//		[IN]	bRepaint
+//				If TRUE the control will be repainted.
+//
+// Return value:
+//		BTNST_OK
+//			Function executed successfully.
+//		BTNST_INVALIDPRESSEDSTYLE
+//			Pressed style not supported.
+//
+DWORD CButtonST::SetPressedStyle(BYTE byStyle, BOOL bRepaint)
+{
+	switch (byStyle)
+	{
+		case BTNST_PRESSED_LEFTRIGHT:
+			m_ptPressedOffset.x = 1;
+			m_ptPressedOffset.y = 1;
+			break;
+		case BTNST_PRESSED_TOPBOTTOM:
+			m_ptPressedOffset.x = 0;
+			m_ptPressedOffset.y = 2;
+			break;
+		default:
+			return BTNST_INVALIDPRESSEDSTYLE;
+	} // switch
+
+	if (bRepaint)	Invalidate();
+
+	return BTNST_OK;
+} // End of SetPressedStyle
+
+// This function sets the state of the checkbox.
+// If the button is not a checkbox, this function has no meaning.
+//
+// Parameters:
+//		[IN]	nCheck
+//				1 to check the checkbox.
+//				0 to un-check the checkbox.
+//		[IN]	bRepaint
+//				If TRUE the control will be repainted.
+//
+// Return value:
+//		BTNST_OK
+//			Function executed successfully.
+//
+DWORD CButtonST::SetCheck(int nCheck, BOOL bRepaint)
+{
+	if (m_bIsCheckBox)
+	{
+		if (nCheck == 0) m_nCheck = 0;
+		else m_nCheck = 1;
+
+		if (bRepaint) Invalidate();
+	} // if
+
+	return BTNST_OK;
+} // End of SetCheck
+
+// This function returns the current state of the checkbox.
+// If the button is not a checkbox, this function has no meaning.
+//
+// Return value:
+//		The current state of the checkbox.
+//			1 if checked.
+//			0 if not checked or the button is not a checkbox.
+//
+int CButtonST::GetCheck()
+{
+	return m_nCheck;
+} // End of GetCheck
+
+// This function sets all colors to a default value.
+//
+// Parameters:
+//		[IN]	bRepaint
+//				If TRUE the control will be repainted.
+//
+// Return value:
+//		BTNST_OK
+//			Function executed successfully.
+//
+DWORD CButtonST::SetDefaultColors(BOOL bRepaint)
+{
+	m_crColors[BTNST_COLOR_BK_IN]		= ::GetSysColor(COLOR_BTNFACE);
+	m_crColors[BTNST_COLOR_FG_IN]		= ::GetSysColor(COLOR_BTNTEXT);
+	m_crColors[BTNST_COLOR_BK_OUT]		= ::GetSysColor(COLOR_BTNFACE);
+	m_crColors[BTNST_COLOR_FG_OUT]		= ::GetSysColor(COLOR_BTNTEXT);
+	m_crColors[BTNST_COLOR_BK_FOCUS]	= ::GetSysColor(COLOR_BTNFACE);
+	m_crColors[BTNST_COLOR_FG_FOCUS]	= ::GetSysColor(COLOR_BTNTEXT);
+
+	if (bRepaint)	Invalidate();
+
+	return BTNST_OK;
+} // End of SetDefaultColors
+
+// This function sets the color to use for a particular state.
+//
+// Parameters:
+//		[IN]	byColorIndex
+//				Index of the color to set. Can be one of the following values:
+//				BTNST_COLOR_BK_IN		Background color when mouse is over the button
+//				BTNST_COLOR_FG_IN		Text color when mouse is over the button
+//				BTNST_COLOR_BK_OUT		Background color when mouse is outside the button
+//				BTNST_COLOR_FG_OUT		Text color when mouse is outside the button
+//				BTNST_COLOR_BK_FOCUS	Background color when the button is focused
+//				BTNST_COLOR_FG_FOCUS	Text color when the button is focused
+//		[IN]	crColor
+//				New color.
+//		[IN]	bRepaint
+//				If TRUE the control will be repainted.
+//
+// Return value:
+//		BTNST_OK
+//			Function executed successfully.
+//		BTNST_INVALIDINDEX
+//			Invalid color index.
+//
+DWORD CButtonST::SetColor(BYTE byColorIndex, COLORREF crColor, BOOL bRepaint)
+{
+	if (byColorIndex >= BTNST_MAX_COLORS)	return BTNST_INVALIDINDEX;
+
+	// Set new color
+	m_crColors[byColorIndex] = crColor;
+
+	if (bRepaint)	Invalidate();
+
+	return BTNST_OK;
+} // End of SetColor
+
+// This functions returns the color used for a particular state.
+//
+// Parameters:
+//		[IN]	byColorIndex
+//				Index of the color to get.
+//				See SetColor for the list of available colors.
+//		[OUT]	crpColor
+//				A pointer to a COLORREF that will receive the color.
+//
+// Return value:
+//		BTNST_OK
+//			Function executed successfully.
+//		BTNST_INVALIDINDEX
+//			Invalid color index.
+//
+DWORD CButtonST::GetColor(BYTE byColorIndex, COLORREF* crpColor)
+{
+	if (byColorIndex >= BTNST_MAX_COLORS)	return BTNST_INVALIDINDEX;
+
+	// Get color
+	*crpColor = m_crColors[byColorIndex];
+
+	return BTNST_OK;
+} // End of GetColor
+
+// This function applies an offset to the RGB components of the specified color.
+// This function can be seen as an easy way to make a color darker or lighter than
+// its default value.
+//
+// Parameters:
+//		[IN]	byColorIndex
+//				Index of the color to set.
+//				See SetColor for the list of available colors.
+//		[IN]	shOffsetColor
+//				A short value indicating the offset to apply to the color.
+//				This value must be between -255 and 255.
+//		[IN]	bRepaint
+//				If TRUE the control will be repainted.
+//
+// Return value:
+//		BTNST_OK
+//			Function executed successfully.
+//		BTNST_INVALIDINDEX
+//			Invalid color index.
+//		BTNST_BADPARAM
+//			The specified offset is out of range.
+//
+DWORD CButtonST::OffsetColor(BYTE byColorIndex, short shOffset, BOOL bRepaint)
+{
+	BYTE	byRed = 0;
+	BYTE	byGreen = 0;
+	BYTE	byBlue = 0;
+	short	shOffsetR = shOffset;
+	short	shOffsetG = shOffset;
+	short	shOffsetB = shOffset;
+
+	if (byColorIndex >= BTNST_MAX_COLORS)	return BTNST_INVALIDINDEX;
+	if (shOffset < -255 || shOffset > 255)	return BTNST_BADPARAM;
+
+	// Get RGB components of specified color
+	byRed = GetRValue(m_crColors[byColorIndex]);
+	byGreen = GetGValue(m_crColors[byColorIndex]);
+	byBlue = GetBValue(m_crColors[byColorIndex]);
+
+	// Calculate max. allowed real offset
+	if (shOffset > 0)
+	{
+		if (byRed + shOffset > 255)		shOffsetR = 255 - byRed;
+		if (byGreen + shOffset > 255)	shOffsetG = 255 - byGreen;
+		if (byBlue + shOffset > 255)	shOffsetB = 255 - byBlue;
+
+		shOffset = min(min(shOffsetR, shOffsetG), shOffsetB);
+	} // if
+	else
+	{
+		if (byRed + shOffset < 0)		shOffsetR = -byRed;
+		if (byGreen + shOffset < 0)		shOffsetG = -byGreen;
+		if (byBlue + shOffset < 0)		shOffsetB = -byBlue;
+
+		shOffset = max(max(shOffsetR, shOffsetG), shOffsetB);
+	} // else
+
+	// Set new color
+	m_crColors[byColorIndex] = RGB(byRed + shOffset, byGreen + shOffset, byBlue + shOffset);
+
+	if (bRepaint)	Invalidate();
+
+	return BTNST_OK;
+} // End of OffsetColor
+
+// This function sets the hilight logic for the button.
+// Applies only to flat buttons.
+//
+// Parameters:
+//		[IN]	bAlwaysTrack
+//				If TRUE the button will be hilighted even if the window that owns it, is
+//				not the active window.
+//				If FALSE the button will be hilighted only if the window that owns it,
+//				is the active window.
+//
+// Return value:
+//		BTNST_OK
+//			Function executed successfully.
+//
+DWORD CButtonST::SetAlwaysTrack(BOOL bAlwaysTrack)
+{
+	m_bAlwaysTrack = bAlwaysTrack;
+	return BTNST_OK;
+} // End of SetAlwaysTrack
+
+// This function sets the cursor to be used when the mouse is over the button.
+//
+// Parameters:
+//		[IN]	nCursorId
+//				ID number of the cursor resource.
+//				Pass NULL to remove a previously loaded cursor.
+//		[IN]	bRepaint
+//				If TRUE the control will be repainted.
+//
+// Return value:
+//		BTNST_OK
+//			Function executed successfully.
+//		BTNST_INVALIDRESOURCE
+//			Failed loading the specified resource.
+//
+DWORD CButtonST::SetBtnCursor(int nCursorId, BOOL bRepaint)
+{
+	HINSTANCE	hInstResource = NULL;
+	// Destroy any previous cursor
+	if (m_hCursor)
+	{
+		::DestroyCursor(m_hCursor);
+		m_hCursor = NULL;
+	} // if
+
+	// Load cursor
+	if (nCursorId)
+	{
+		hInstResource = AfxFindResourceHandle(MAKEINTRESOURCE(nCursorId), RT_GROUP_CURSOR);
+		// Load cursor resource
+		m_hCursor = (HCURSOR)::LoadImage(hInstResource, MAKEINTRESOURCE(nCursorId), IMAGE_CURSOR, 0, 0, 0);
+		// Repaint the button
+		if (bRepaint) Invalidate();
+		// If something wrong
+		if (m_hCursor == NULL) return BTNST_INVALIDRESOURCE;
+	} // if
+
+	return BTNST_OK;
+} // End of SetBtnCursor
+
+// This function sets if the button border must be drawn.
+// Applies only to flat buttons.
+//
+// Parameters:
+//		[IN]	bDrawBorder
+//				If TRUE the border will be drawn.
+//		[IN]	bRepaint
+//				If TRUE the control will be repainted.
+//
+// Return value:
+//		BTNST_OK
+//			Function executed successfully.
+//
+DWORD CButtonST::DrawBorder(BOOL bDrawBorder, BOOL bRepaint)
+{
+	m_bDrawBorder = bDrawBorder;
+	// Repaint the button
+	if (bRepaint) Invalidate();
+
+	return BTNST_OK;
+} // End of DrawBorder
+
+// This function sets if the focus rectangle must be drawn for flat buttons.
+//
+// Parameters:
+//		[IN]	bDrawFlatFocus
+//				If TRUE the focus rectangle will be drawn also for flat buttons.
+//		[IN]	bRepaint
+//				If TRUE the control will be repainted.
+//
+// Return value:
+//		BTNST_OK
+//			Function executed successfully.
+//
+DWORD CButtonST::DrawFlatFocus(BOOL bDrawFlatFocus, BOOL bRepaint)
+{
+	m_bDrawFlatFocus = bDrawFlatFocus;
+	// Repaint the button
+	if (bRepaint) Invalidate();
+
+	return BTNST_OK;
+} // End of DrawFlatFocus
+
+void CButtonST::InitToolTip()
+{
+	if (m_ToolTip.m_hWnd == NULL)
+	{
+		// Create ToolTip control
+		m_ToolTip.Create(this, m_dwToolTipStyle);
+		// Create inactive
+		m_ToolTip.Activate(FALSE);
+		// Enable multiline
+		m_ToolTip.SendMessage(TTM_SETMAXTIPWIDTH, 0, 400);
+		//m_ToolTip.SendMessage(TTM_SETTITLE, TTI_INFO, (LPARAM)_T("Title"));
+	} // if
+} // End of InitToolTip
+
+// This function sets the text to show in the button tooltip.
+//
+// Parameters:
+//		[IN]	nText
+//				ID number of the string resource containing the text to show.
+//		[IN]	bActivate
+//				If TRUE the tooltip will be created active.
+//
+void CButtonST::SetTooltipText(int nText, BOOL bActivate)
+{
+	CString sText;
+
+	// Load string resource
+	sText.LoadString(nText);
+	// If string resource is not empty
+	if (sText.IsEmpty() == FALSE) SetTooltipText((LPCTSTR)sText, bActivate);
+} // End of SetTooltipText
+
+// This function sets the text to show in the button tooltip.
+//
+// Parameters:
+//		[IN]	lpszText
+//				Pointer to a null-terminated string containing the text to show.
+//		[IN]	bActivate
+//				If TRUE the tooltip will be created active.
+//
+void CButtonST::SetTooltipText(LPCTSTR lpszText, BOOL bActivate)
+{
+	// We cannot accept NULL pointer
+	if (lpszText == NULL) return;
+
+	// Initialize ToolTip
+	InitToolTip();
+
+	// If there is no tooltip defined then add it
+	if (m_ToolTip.GetToolCount() == 0)
+	{
+		CRect rectBtn; 
+		GetClientRect(rectBtn);
+		m_ToolTip.AddTool(this, lpszText, rectBtn, 1);
+	} // if
+
+	// Set text for tooltip
+	m_ToolTip.UpdateTipText(lpszText, this, 1);
+	m_ToolTip.Activate(bActivate);
+} // End of SetTooltipText
+
+// This function enables or disables the button tooltip.
+//
+// Parameters:
+//		[IN]	bActivate
+//				If TRUE the tooltip will be activated.
+//
+void CButtonST::ActivateTooltip(BOOL bActivate)
+{
+	// If there is no tooltip then do nothing
+	if (m_ToolTip.GetToolCount() == 0) return;
+
+	// Activate tooltip
+	m_ToolTip.Activate(bActivate);
+} // End of EnableTooltip
+
+// This function enables the tooltip to be displayed using the balloon style.
+// This function must be called before any call to SetTooltipText is made.
+//
+// Return value:
+//		BTNST_OK
+//			Function executed successfully.
+//
+DWORD CButtonST::EnableBalloonTooltip()
+{
+	m_dwToolTipStyle |= TTS_BALLOON;
+	return BTNST_OK;
+} // End of EnableBalloonTooltip
+
+// This function returns if the button is the default button.
+//
+// Return value:
+//		TRUE
+//			The button is the default button.
+//		FALSE
+//			The button is not the default button.
+//
+BOOL CButtonST::GetDefault()
+{
+	return m_bIsDefault;
+} // End of GetDefault
+
+// This function enables the transparent mode.
+// Note: this operation is not reversible.
+// DrawTransparent should be called just after the button is created.
+// Do not use trasparent buttons until you really need it (you have a bitmapped
+// background) since each transparent button makes a copy in memory of its background.
+// This may bring unnecessary memory use and execution overload.
+//
+// Parameters:
+//		[IN]	bRepaint
+//				If TRUE the control will be repainted.
+//
+void CButtonST::DrawTransparent(BOOL bRepaint)
+{
+	m_bDrawTransparent = TRUE;
+
+	// Restore old bitmap (if any)
+	if (m_dcBk.m_hDC != NULL && m_pbmpOldBk != NULL)
+	{
+		m_dcBk.SelectObject(m_pbmpOldBk);
+	} // if
+
+	m_bmpBk.DeleteObject();
+	m_dcBk.DeleteDC();
+
+	// Repaint the button
+	if (bRepaint) Invalidate();
+} // End of DrawTransparent
+
+DWORD CButtonST::SetBk(CDC* pDC)
+{
+	if (m_bDrawTransparent && pDC)
+	{
+		// Restore old bitmap (if any)
+		if (m_dcBk.m_hDC != NULL && m_pbmpOldBk != NULL)
+		{
+			m_dcBk.SelectObject(m_pbmpOldBk);
+		} // if
+
+		m_bmpBk.DeleteObject();
+		m_dcBk.DeleteDC();
+
+		CRect rect;
+		CRect rect1;
+
+		GetClientRect(rect);
+
+		GetWindowRect(rect1);
+		GetParent()->ScreenToClient(rect1);
+
+		m_dcBk.CreateCompatibleDC(pDC);
+		m_bmpBk.CreateCompatibleBitmap(pDC, rect.Width(), rect.Height());
+		m_pbmpOldBk = m_dcBk.SelectObject(&m_bmpBk);
+		m_dcBk.BitBlt(0, 0, rect.Width(), rect.Height(), pDC, rect1.left, rect1.top, SRCCOPY);
+
+		return BTNST_OK;
+	} // if
+
+	return BTNST_BADPARAM;
+} // End of SetBk
+
+// This function sets the URL that will be opened when the button is clicked.
+//
+// Parameters:
+//		[IN]	lpszURL
+//				Pointer to a null-terminated string that contains the URL.
+//				Pass NULL to removed any previously specified URL.
+//
+// Return value:
+//		BTNST_OK
+//			Function executed successfully.
+//
+DWORD CButtonST::SetURL(LPCTSTR lpszURL)
+{
+	// Remove any existing URL
+	memset(m_szURL, 0, sizeof(m_szURL));
+
+	if (lpszURL)
+	{
+		// Store the URL
+		_tcsncpy(m_szURL, lpszURL, _MAX_PATH);
+	} // if
+
+	return BTNST_OK;
+} // End of SetURL
+
+// This function associates a menu to the button.
+// The menu will be displayed clicking the button.
+//
+// Parameters:
+//		[IN]	nMenu
+//				ID number of the menu resource.
+//				Pass NULL to remove any menu from the button.
+//		[IN]	hParentWnd
+//				Handle to the window that owns the menu.
+//				This window receives all messages from the menu.
+//		[IN]	bRepaint
+//				If TRUE the control will be repainted.
+//
+// Return value:
+//		BTNST_OK
+//			Function executed successfully.
+//		BTNST_INVALIDRESOURCE
+//			Failed loading the specified resource.
+//
+#ifndef	BTNST_USE_BCMENU
+DWORD CButtonST::SetMenu(UINT nMenu, HWND hParentWnd, BOOL bRepaint)
+{
+	HINSTANCE	hInstResource	= NULL;
+
+	// Destroy any previous menu
+	if (m_hMenu)
+	{
+		::DestroyMenu(m_hMenu);
+		m_hMenu = NULL;
+		m_hParentWndMenu = NULL;
+		m_bMenuDisplayed = FALSE;
+	} // if
+
+	// Load menu
+	if (nMenu)
+	{
+		// Find correct resource handle
+		hInstResource = AfxFindResourceHandle(MAKEINTRESOURCE(nMenu), RT_MENU);
+		// Load menu resource
+		m_hMenu = ::LoadMenu(hInstResource, MAKEINTRESOURCE(nMenu));
+		m_hParentWndMenu = hParentWnd;
+		// If something wrong
+		if (m_hMenu == NULL) return BTNST_INVALIDRESOURCE;
+	} // if
+
+	// Repaint the button
+	if (bRepaint) Invalidate();
+
+	return BTNST_OK;
+} // End of SetMenu
+#endif
+
+// This function associates a menu to the button.
+// The menu will be displayed clicking the button.
+// The menu will be handled by the BCMenu class.
+//
+// Parameters:
+//		[IN]	nMenu
+//				ID number of the menu resource.
+//				Pass NULL to remove any menu from the button.
+//		[IN]	hParentWnd
+//				Handle to the window that owns the menu.
+//				This window receives all messages from the menu.
+//		[IN]	bWinXPStyle
+//				If TRUE the menu will be displayed using the new Windows XP style.
+//				If FALSE the menu will be displayed using the standard style.
+//		[IN]	nToolbarID
+//				Resource ID of the toolbar to be associated to the menu.
+//		[IN]	sizeToolbarIcon
+//				A CSize object indicating the size (in pixels) of each icon into the toolbar.
+//				All icons into the toolbar must have the same size.
+//		[IN]	crToolbarBk
+//				A COLORREF value indicating the color to use as background for the icons into the toolbar.
+//				This color will be used as the "transparent" color.
+//		[IN]	bRepaint
+//				If TRUE the control will be repainted.
+//
+// Return value:
+//		BTNST_OK
+//			Function executed successfully.
+//		BTNST_INVALIDRESOURCE
+//			Failed loading the specified resource.
+//
+#ifdef	BTNST_USE_BCMENU
+DWORD CButtonST::SetMenu(UINT nMenu, HWND hParentWnd, BOOL bWinXPStyle, UINT nToolbarID, CSize sizeToolbarIcon, COLORREF crToolbarBk, BOOL bRepaint)
+{
+	BOOL	bRetValue = FALSE;
+
+	// Destroy any previous menu
+	if (m_menuPopup.m_hMenu)
+	{
+		m_menuPopup.DestroyMenu();
+		m_hParentWndMenu = NULL;
+		m_bMenuDisplayed = FALSE;
+	} // if
+
+	// Load menu
+	if (nMenu)
+	{
+		m_menuPopup.SetMenuDrawMode(bWinXPStyle);
+		// Load menu
+		bRetValue = m_menuPopup.LoadMenu(nMenu);
+		// If something wrong
+		if (bRetValue == FALSE) return BTNST_INVALIDRESOURCE;
+
+		// Load toolbar
+		if (nToolbarID)
+		{
+			m_menuPopup.SetBitmapBackground(crToolbarBk);
+			m_menuPopup.SetIconSize(sizeToolbarIcon.cx, sizeToolbarIcon.cy);
+
+			bRetValue = m_menuPopup.LoadToolbar(nToolbarID);
+			// If something wrong
+			if (bRetValue == FALSE) 
+			{
+				m_menuPopup.DestroyMenu();
+				return BTNST_INVALIDRESOURCE;
+			} // if
+		} // if
+
+		m_hParentWndMenu = hParentWnd;
+	} // if
+
+	// Repaint the button
+	if (bRepaint) Invalidate();
+
+	return BTNST_OK;
+} // End of SetMenu
+#endif
+
+// This function sets the callback message that will be sent to the
+// specified window just before the menu associated to the button is displayed.
+//
+// Parameters:
+//		[IN]	hWnd
+//				Handle of the window that will receive the callback message.
+//				Pass NULL to remove any previously specified callback message.
+//		[IN]	nMessage
+//				Callback message to send to window.
+//		[IN]	lParam
+//				A 32 bits user specified value that will be passed to the callback function.
+//
+// Remarks:
+//		the callback function must be in the form:
+//		LRESULT On_MenuCallback(WPARAM wParam, LPARAM lParam)
+//		Where:
+//				[IN]	wParam
+//						If support for BCMenu is enabled: a pointer to BCMenu
+//						else a HMENU handle to the menu that is being to be displayed.
+//				[IN]	lParam
+//						The 32 bits user specified value.
+//
+// Return value:
+//		BTNST_OK
+//			Function executed successfully.
+//
+DWORD CButtonST::SetMenuCallback(HWND hWnd, UINT nMessage, LPARAM lParam)
+{
+	m_csCallbacks.hWnd = hWnd;
+	m_csCallbacks.nMessage = nMessage;
+	m_csCallbacks.lParam = lParam;
+
+	return BTNST_OK;
+} // End of SetMenuCallback
+
+// This function resizes the button to the same size of the image.
+// To get good results both the IN and OUT images should have the same size.
+//
+void CButtonST::SizeToContent()
+{
+	if (m_csIcons[0].hIcon)
+	{
+		m_ptImageOrg.x = 0;
+		m_ptImageOrg.y = 0;
+	    SetWindowPos(	NULL, -1, -1, m_csIcons[0].dwWidth, m_csIcons[0].dwHeight,
+						SWP_NOMOVE | SWP_NOZORDER | SWP_NOREDRAW | SWP_NOACTIVATE);
+	} // if
+	else
+	if (m_csBitmaps[0].hBitmap)
+	{
+		m_ptImageOrg.x = 0;
+		m_ptImageOrg.y = 0;
+	    SetWindowPos(	NULL, -1, -1, m_csBitmaps[0].dwWidth, m_csBitmaps[0].dwHeight,
+						SWP_NOMOVE | SWP_NOZORDER | SWP_NOREDRAW | SWP_NOACTIVATE);
+	} // if
+} // End of SizeToContent
+
+// This function sets the sound that must be played on particular button states.
+//
+// Parameters:
+//		[IN]	lpszSound
+//				A string that specifies the sound to play.
+//				If hMod is NULL this string is interpreted as a filename, else it
+//				is interpreted as a resource identifier.
+//				Pass NULL to remove any previously specified sound.
+//		[IN]	hMod
+//				Handle to the executable file that contains the resource to be loaded.
+//				This parameter must be NULL unless lpszSound specifies a resource identifier.
+//		[IN]	bPlayOnClick
+//				TRUE if the sound must be played when the button is clicked.
+//				FALSE if the sound must be played when the mouse is moved over the button.
+//		[IN]	bPlayAsync
+//				TRUE if the sound must be played asynchronously.
+//				FALSE if the sound must be played synchronously. The application takes control
+//				when the sound is completely played.
+//
+// Return value:
+//		BTNST_OK
+//			Function executed successfully.
+//
+#ifdef	BTNST_USE_SOUND
+DWORD CButtonST::SetSound(LPCTSTR lpszSound, HMODULE hMod, BOOL bPlayOnClick, BOOL bPlayAsync)
+{
+	BYTE	byIndex = bPlayOnClick ? 1 : 0;
+
+	// Store new sound
+	if (lpszSound)
+	{
+		if (hMod)	// From resource identifier ?
+		{
+			m_csSounds[byIndex].lpszSound = lpszSound;
+		} // if
+		else
+		{
+			_tcscpy(m_csSounds[byIndex].szSound, lpszSound);
+			m_csSounds[byIndex].lpszSound = m_csSounds[byIndex].szSound;
+		} // else
+
+		m_csSounds[byIndex].hMod = hMod;
+		m_csSounds[byIndex].dwFlags = SND_NODEFAULT | SND_NOWAIT;
+		m_csSounds[byIndex].dwFlags |= hMod ? SND_RESOURCE : SND_FILENAME;
+		m_csSounds[byIndex].dwFlags |= bPlayAsync ? SND_ASYNC : SND_SYNC;
+	} // if
+	else
+	{
+		// Or remove any existing
+		::ZeroMemory(&m_csSounds[byIndex], sizeof(STRUCT_SOUND));
+	} // else
+
+	return BTNST_OK;
+} // End of SetSound
+#endif
+
+// This function is called every time the button background needs to be painted.
+// If the button is in transparent mode this function will NOT be called.
+// This is a virtual function that can be rewritten in CButtonST-derived classes
+// to produce a whole range of buttons not available by default.
+//
+// Parameters:
+//		[IN]	pDC
+//				Pointer to a CDC object that indicates the device context.
+//		[IN]	pRect
+//				Pointer to a CRect object that indicates the bounds of the
+//				area to be painted.
+//
+// Return value:
+//		BTNST_OK
+//			Function executed successfully.
+//
+DWORD CButtonST::OnDrawBackground(CDC* pDC, CRect* pRect)
+{
+	COLORREF	crColor;
+
+	if (m_bIsFlat == FALSE)
+	{
+		if (m_bIsFocused || m_bIsDefault)
+		{
+			CBrush br(RGB(0,0,0));  
+			pDC->FrameRect(pRect, &br);
+			pRect->DeflateRect(1, 1);
+		} // if
+	} // if
+
+	if (m_bMouseOnButton || m_bIsPressed)
+		crColor = m_crColors[BTNST_COLOR_BK_IN];
+	else
+	{
+		if (m_bIsFocused)
+			crColor = m_crColors[BTNST_COLOR_BK_FOCUS];
+		else
+			crColor = m_crColors[BTNST_COLOR_BK_OUT];
+	} // else
+
+	CBrush		brBackground(crColor);
+
+	pDC->FillRect(pRect, &brBackground);
+
+	return BTNST_OK;
+} // End of OnDrawBackground
+
+// This function is called every time the button border needs to be painted.
+// This is a virtual function that can be rewritten in CButtonST-derived classes
+// to produce a whole range of buttons not available by default.
+//
+// Parameters:
+//		[IN]	pDC
+//				Pointer to a CDC object that indicates the device context.
+//		[IN]	pRect
+//				Pointer to a CRect object that indicates the bounds of the
+//				area to be painted.
+//
+// Return value:
+//		BTNST_OK
+//			Function executed successfully.
+//
+DWORD CButtonST::OnDrawBorder(CDC* pDC, CRect* pRect)
+{
+	// Draw pressed button
+	if (m_bIsPressed)
+	{
+		if (m_bIsFlat)
+		{
+			if (m_bDrawBorder)
+				pDC->Draw3dRect(pRect, ::GetSysColor(COLOR_BTNSHADOW), ::GetSysColor(COLOR_BTNHILIGHT));
+		}
+		else    
+		{
+			CBrush brBtnShadow(GetSysColor(COLOR_BTNSHADOW));
+			pDC->FrameRect(pRect, &brBtnShadow);
+		}
+	}
+	else // ...else draw non pressed button
+	{
+		CPen penBtnHiLight(PS_SOLID, 0, GetSysColor(COLOR_BTNHILIGHT)); // White
+		CPen pen3DLight(PS_SOLID, 0, GetSysColor(COLOR_3DLIGHT));       // Light gray
+		CPen penBtnShadow(PS_SOLID, 0, GetSysColor(COLOR_BTNSHADOW));   // Dark gray
+		CPen pen3DDKShadow(PS_SOLID, 0, GetSysColor(COLOR_3DDKSHADOW)); // Black
+
+		if (m_bIsFlat)
+		{
+			if (m_bMouseOnButton && m_bDrawBorder)
+				pDC->Draw3dRect(pRect, ::GetSysColor(COLOR_BTNHILIGHT), ::GetSysColor(COLOR_BTNSHADOW));
+		}
+		else
+		{
+			// Draw top-left borders
+			// White line
+			CPen* pOldPen = pDC->SelectObject(&penBtnHiLight);
+			pDC->MoveTo(pRect->left, pRect->bottom-1);
+			pDC->LineTo(pRect->left, pRect->top);
+			pDC->LineTo(pRect->right, pRect->top);
+			// Light gray line
+			pDC->SelectObject(pen3DLight);
+			pDC->MoveTo(pRect->left+1, pRect->bottom-1);
+			pDC->LineTo(pRect->left+1, pRect->top+1);
+			pDC->LineTo(pRect->right, pRect->top+1);
+			// Draw bottom-right borders
+			// Black line
+			pDC->SelectObject(pen3DDKShadow);
+			pDC->MoveTo(pRect->left, pRect->bottom-1);
+			pDC->LineTo(pRect->right-1, pRect->bottom-1);
+			pDC->LineTo(pRect->right-1, pRect->top-1);
+			// Dark gray line
+			pDC->SelectObject(penBtnShadow);
+			pDC->MoveTo(pRect->left+1, pRect->bottom-2);
+			pDC->LineTo(pRect->right-2, pRect->bottom-2);
+			pDC->LineTo(pRect->right-2, pRect->top);
+			//
+			pDC->SelectObject(pOldPen);
+		} // else
+	} // else
+
+	return BTNST_OK;
+} // End of OnDrawBorder
+
+#undef BS_TYPEMASK

+ 310 - 0
Source/OGCAssistTool/OGCAssistTool/BtnST.h

@@ -0,0 +1,310 @@
+//
+//	Class:		CButtonST
+//
+//	Compiler:	Visual C++
+//	Tested on:	Visual C++ 5.0
+//				Visual C++ 6.0
+//
+//	Version:	See GetVersionC() or GetVersionI()
+//
+//	Created:	xx/xxxx/1998
+//	Updated:	03/March/2003
+//
+//	Author:		Davide Calabro'		davide_calabro@yahoo.com
+//									http://www.softechsoftware.it
+//
+//	Note:		Code for the PreSubclassWindow and OnSetStyle functions
+//				has been taken from the COddButton class
+//				published by Paolo Messina and Jerzy Kaczorowski
+//
+//	Disclaimer
+//	----------
+//	THIS SOFTWARE AND THE ACCOMPANYING FILES ARE DISTRIBUTED "AS IS" AND WITHOUT
+//	ANY WARRANTIES WHETHER EXPRESSED OR IMPLIED. NO REPONSIBILITIES FOR POSSIBLE
+//	DAMAGES OR EVEN FUNCTIONALITY CAN BE TAKEN. THE USER MUST ASSUME THE ENTIRE
+//	RISK OF USING THIS SOFTWARE.
+//
+//	Terms of use
+//	------------
+//	THIS SOFTWARE IS FREE FOR PERSONAL USE OR FREEWARE APPLICATIONS.
+//	IF YOU USE THIS SOFTWARE IN COMMERCIAL OR SHAREWARE APPLICATIONS YOU
+//	ARE GENTLY ASKED TO DONATE 5$ (FIVE U.S. DOLLARS) TO THE AUTHOR:
+//
+//		Davide Calabro'
+//		P.O. Box 65
+//		21019 Somma Lombardo (VA)
+//		Italy
+//
+#ifndef _BTNST_H
+#define _BTNST_H
+
+// Uncomment the following 2 lines to enable support for BCMenu class
+#define	BTNST_USE_BCMENU
+#include "BCMenu.h"
+
+// Uncomment the following line to enable support for sound effects
+#define	BTNST_USE_SOUND
+
+#if _MSC_VER >= 1000
+#pragma once
+#endif // _MSC_VER >= 1000
+
+// Return values
+#ifndef	BTNST_OK
+#define	BTNST_OK						0
+#endif
+#ifndef	BTNST_INVALIDRESOURCE
+#define	BTNST_INVALIDRESOURCE			1
+#endif
+#ifndef	BTNST_FAILEDMASK
+#define	BTNST_FAILEDMASK				2
+#endif
+#ifndef	BTNST_INVALIDINDEX
+#define	BTNST_INVALIDINDEX				3
+#endif
+#ifndef	BTNST_INVALIDALIGN
+#define	BTNST_INVALIDALIGN				4
+#endif
+#ifndef	BTNST_BADPARAM
+#define	BTNST_BADPARAM					5
+#endif
+#ifndef	BTNST_INVALIDPRESSEDSTYLE
+#define	BTNST_INVALIDPRESSEDSTYLE		6
+#endif
+
+// Dummy identifier for grayscale icon
+#ifndef	BTNST_AUTO_GRAY
+#define	BTNST_AUTO_GRAY					(HICON)(0xffffffff - 1L)
+#endif
+// Dummy identifier for 15% darker icon
+#ifndef	BTNST_AUTO_DARKER
+#define	BTNST_AUTO_DARKER				(HICON)(0xffffffff - 2L)
+#endif
+
+class CButtonST : public CButton
+{
+public:
+    CButtonST();
+	~CButtonST();
+
+    enum	{	ST_ALIGN_HORIZ	= 0,			// Icon/bitmap on the left, text on the right
+				ST_ALIGN_VERT,					// Icon/bitmap on the top, text on the bottom
+				ST_ALIGN_HORIZ_RIGHT,			// Icon/bitmap on the right, text on the left
+				ST_ALIGN_OVERLAP				// Icon/bitmap on the same space as text
+			};
+
+	enum	{	BTNST_COLOR_BK_IN	= 0,		// Background color when mouse is INside
+				BTNST_COLOR_FG_IN,				// Text color when mouse is INside
+				BTNST_COLOR_BK_OUT,				// Background color when mouse is OUTside
+				BTNST_COLOR_FG_OUT,				// Text color when mouse is OUTside
+				BTNST_COLOR_BK_FOCUS,			// Background color when the button is focused
+				BTNST_COLOR_FG_FOCUS,			// Text color when the button is focused
+
+				BTNST_MAX_COLORS
+			};
+
+    enum	{	BTNST_PRESSED_LEFTRIGHT = 0,	// Pressed style from left to right (as usual)
+				BTNST_PRESSED_TOPBOTTOM			// Pressed style from top to bottom
+			};
+
+	// ClassWizard generated virtual function overrides
+    //{{AFX_VIRTUAL(CButtonST)
+	public:
+	virtual void DrawItem(LPDRAWITEMSTRUCT lpDrawItemStruct);
+	virtual BOOL PreTranslateMessage(MSG* pMsg);
+	protected:
+	virtual void PreSubclassWindow();
+	//}}AFX_VIRTUAL
+
+public:
+	DWORD SetDefaultColors(BOOL bRepaint = TRUE);
+	DWORD SetColor(BYTE byColorIndex, COLORREF crColor, BOOL bRepaint = TRUE);
+	DWORD GetColor(BYTE byColorIndex, COLORREF* crpColor);
+	DWORD OffsetColor(BYTE byColorIndex, short shOffset, BOOL bRepaint = TRUE);
+
+	DWORD SetCheck(int nCheck, BOOL bRepaint = TRUE);
+	int GetCheck();
+
+	DWORD SetURL(LPCTSTR lpszURL = NULL);
+	void DrawTransparent(BOOL bRepaint = FALSE);
+	DWORD SetBk(CDC* pDC);
+
+	BOOL GetDefault();
+	DWORD SetAlwaysTrack(BOOL bAlwaysTrack = TRUE);
+
+	void SetTooltipText(int nText, BOOL bActivate = TRUE);
+	void SetTooltipText(LPCTSTR lpszText, BOOL bActivate = TRUE);
+	void ActivateTooltip(BOOL bEnable = TRUE);
+	DWORD EnableBalloonTooltip();
+
+	DWORD SetBtnCursor(int nCursorId = NULL, BOOL bRepaint = TRUE);
+
+	DWORD SetFlat(BOOL bFlat = TRUE, BOOL bRepaint = TRUE);
+	DWORD SetAlign(BYTE byAlign, BOOL bRepaint = TRUE);
+	DWORD SetPressedStyle(BYTE byStyle, BOOL bRepaint = TRUE);
+
+	DWORD DrawBorder(BOOL bDrawBorder = TRUE, BOOL bRepaint = TRUE);
+	DWORD DrawFlatFocus(BOOL bDrawFlatFocus, BOOL bRepaint = TRUE);
+
+	DWORD SetIcon(int nIconIn, int nCxDesiredIn, int nCyDesiredIn, int nIconOut = NULL, int nCxDesiredOut = 0, int nCyDesiredOut = 0);
+	DWORD SetIcon(int nIconIn, int nIconOut = NULL);
+	DWORD SetIcon(HICON hIconIn, HICON hIconOut = NULL);
+
+	DWORD SetBitmaps(int nBitmapIn, COLORREF crTransColorIn, int nBitmapOut = NULL, COLORREF crTransColorOut = 0);
+	DWORD SetBitmaps(HBITMAP hBitmapIn, COLORREF crTransColorIn, HBITMAP hBitmapOut = NULL, COLORREF crTransColorOut = 0);
+
+	void SizeToContent();
+
+#ifdef	BTNST_USE_BCMENU
+	DWORD SetMenu(UINT nMenu, HWND hParentWnd, BOOL bWinXPStyle = TRUE, UINT nToolbarID = NULL, CSize sizeToolbarIcon = CSize(16, 16), COLORREF crToolbarBk = RGB(255, 0, 255), BOOL bRepaint = TRUE);
+#else
+	DWORD SetMenu(UINT nMenu, HWND hParentWnd, BOOL bRepaint = TRUE);
+#endif
+	DWORD SetMenuCallback(HWND hWnd, UINT nMessage, LPARAM lParam = 0);
+
+#ifdef	BTNST_USE_SOUND
+	DWORD SetSound(LPCTSTR lpszSound, HMODULE hMod = NULL, BOOL bPlayOnClick = FALSE, BOOL bPlayAsync = TRUE);
+#endif
+
+	static short GetVersionI()		{return 39;}
+	static LPCTSTR GetVersionC()	{return (LPCTSTR)_T("3.9");}
+
+	BOOL	m_bShowDisabledBitmap;
+	POINT	m_ptImageOrg;
+	POINT	m_ptPressedOffset;
+
+protected:
+    //{{AFX_MSG(CButtonST)
+	afx_msg BOOL OnSetCursor(CWnd* pWnd, UINT nHitTest, UINT message);
+	afx_msg void OnKillFocus(CWnd* pNewWnd);
+	afx_msg void OnMouseMove(UINT nFlags, CPoint point);
+	afx_msg void OnSysColorChange();
+	afx_msg BOOL OnClicked();
+	afx_msg void OnActivate(UINT nState, CWnd* pWndOther, BOOL bMinimized);
+	afx_msg void OnEnable(BOOL bEnable);
+	afx_msg void OnCancelMode();
+	afx_msg UINT OnGetDlgCode();
+	//}}AFX_MSG
+
+#ifdef	BTNST_USE_BCMENU
+	afx_msg LRESULT OnMenuChar(UINT nChar, UINT nFlags, CMenu* pMenu);
+	afx_msg void OnMeasureItem(int nIDCtl, LPMEASUREITEMSTRUCT lpMeasureItemStruct);
+#endif
+
+	afx_msg HBRUSH CtlColor(CDC* pDC, UINT nCtlColor);
+	HICON CreateGrayscaleIcon(HICON hIcon);
+	HICON CreateDarkerIcon(HICON hIcon);
+	HBITMAP CreateGrayscaleBitmap(HBITMAP hBitmap, DWORD dwWidth, DWORD dwHeight, COLORREF crTrans);
+	HBITMAP CreateDarkerBitmap(HBITMAP hBitmap, DWORD dwWidth, DWORD dwHeight, COLORREF crTrans);
+	COLORREF DarkenColor(COLORREF crColor, double dFactor);
+	virtual DWORD OnDrawBackground(CDC* pDC, CRect* pRect);
+	virtual DWORD OnDrawBorder(CDC* pDC, CRect* pRect);
+
+	BOOL		m_bIsFlat;			// Is a flat button?
+	BOOL		m_bMouseOnButton;	// Is mouse over the button?
+	BOOL		m_bDrawTransparent;	// Draw transparent?
+	BOOL		m_bIsPressed;		// Is button pressed?
+	BOOL		m_bIsFocused;		// Is button focused?
+	BOOL		m_bIsDisabled;		// Is button disabled?
+	BOOL		m_bIsDefault;		// Is default button?
+	BOOL		m_bIsCheckBox;		// Is the button a checkbox?
+	BYTE		m_byAlign;			// Align mode
+	BOOL		m_bDrawBorder;		// Draw border?
+	BOOL		m_bDrawFlatFocus;	// Draw focus rectangle for flat button?
+	COLORREF	m_crColors[BTNST_MAX_COLORS];	// Colors to be used
+	HWND		m_hParentWndMenu;	// Handle to window for menu selection
+	BOOL		m_bMenuDisplayed;	// Is menu displayed ?
+
+#ifdef	BTNST_USE_BCMENU
+	BCMenu		m_menuPopup;		// BCMenu class instance
+#else
+	HMENU		m_hMenu;			// Handle to associated menu
+#endif
+
+private:
+	LRESULT OnSetCheck(WPARAM wParam, LPARAM lParam);
+	LRESULT OnGetCheck(WPARAM wParam, LPARAM lParam);
+	LRESULT OnSetStyle(WPARAM wParam, LPARAM lParam);
+	LRESULT OnMouseLeave(WPARAM wParam, LPARAM lParam);
+
+	void CancelHover();
+	void FreeResources(BOOL bCheckForNULL = TRUE);
+	void PrepareImageRect(BOOL bHasTitle, RECT* rpItem, CRect* rpTitle, BOOL bIsPressed, DWORD dwWidth, DWORD dwHeight, CRect* rpImage);
+	HBITMAP CreateBitmapMask(HBITMAP hSourceBitmap, DWORD dwWidth, DWORD dwHeight, COLORREF crTransColor);
+	virtual void DrawTheIcon(CDC* pDC, BOOL bHasTitle, RECT* rpItem, CRect* rpCaption, BOOL bIsPressed, BOOL bIsDisabled);
+	virtual void DrawTheBitmap(CDC* pDC, BOOL bHasTitle, RECT* rpItem, CRect* rpCaption, BOOL bIsPressed, BOOL bIsDisabled);
+	virtual void DrawTheText(CDC* pDC, LPCTSTR lpszText, RECT* rpItem, CRect* rpCaption, BOOL bIsPressed, BOOL bIsDisabled);
+	void PaintBk(CDC* pDC);
+
+	void InitToolTip();
+
+	HCURSOR		m_hCursor;			// Handle to cursor
+	CToolTipCtrl m_ToolTip;			// Tooltip
+
+	CDC			m_dcBk;
+	CBitmap		m_bmpBk;
+	CBitmap*	m_pbmpOldBk;
+
+	BOOL		m_bAlwaysTrack;		// Always hilight button?
+	int			m_nCheck;			// Current value for checkbox
+	UINT		m_nTypeStyle;		// Button style
+	DWORD		m_dwToolTipStyle;	// Style of tooltip control
+
+	TCHAR		m_szURL[_MAX_PATH];	// URL to open when clicked
+
+#pragma pack(1)
+	typedef struct _STRUCT_ICONS
+	{
+		HICON		hIcon;			// Handle to icon
+		DWORD		dwWidth;		// Width of icon
+		DWORD		dwHeight;		// Height of icon
+	} STRUCT_ICONS;
+#pragma pack()
+
+#pragma pack(1)
+	typedef struct _STRUCT_BITMAPS
+	{
+		HBITMAP		hBitmap;		// Handle to bitmap
+		DWORD		dwWidth;		// Width of bitmap
+		DWORD		dwHeight;		// Height of bitmap
+		HBITMAP		hMask;			// Handle to mask bitmap
+		COLORREF	crTransparent;	// Transparent color
+	} STRUCT_BITMAPS;
+#pragma pack()
+
+#pragma pack(1)
+	typedef struct _STRUCT_CALLBACK
+	{
+		HWND		hWnd;			// Handle to window
+		UINT		nMessage;		// Message identifier
+		WPARAM		wParam;
+		LPARAM		lParam;
+	} STRUCT_CALLBACK;
+#pragma pack()
+
+	STRUCT_ICONS	m_csIcons[2];
+	STRUCT_BITMAPS	m_csBitmaps[2];
+
+	STRUCT_CALLBACK	m_csCallbacks;
+
+#ifdef	BTNST_USE_SOUND
+#pragma pack(1)
+	typedef struct _STRUCT_SOUND
+	{
+		TCHAR		szSound[_MAX_PATH];
+		LPCTSTR		lpszSound;
+		HMODULE		hMod;
+		DWORD		dwFlags;
+	} STRUCT_SOUND;
+#pragma pack()
+
+	STRUCT_SOUND	m_csSounds[2];	// Index 0 = Over	1 = Clicked
+#endif
+
+	DECLARE_MESSAGE_MAP()
+};
+
+//{{AFX_INSERT_LOCATION}}
+// Microsoft Developer Studio will insert additional declarations immediately before the previous line.
+
+#endif

+ 333 - 0
Source/OGCAssistTool/OGCAssistTool/CeXDib.cpp

@@ -0,0 +1,333 @@
+#include "stdafx.h"
+#include "CeXDib.h"
+
+#ifdef _DEBUG
+#undef THIS_FILE
+static char THIS_FILE[]=__FILE__;
+#define new DEBUG_NEW
+#endif
+
+CCeXDib::CCeXDib()
+{
+	m_hDib = NULL;
+	m_dwLineWidth = 0;
+	m_wColors = 0;
+
+	m_hMemDC = NULL;
+	m_hBitmap = NULL;
+	m_lpBits = NULL;
+
+	FreeResources();
+}
+
+CCeXDib::~CCeXDib()
+{
+	FreeResources();
+}
+
+void CCeXDib::FreeResources()
+{
+	if (m_hMemDC)	::DeleteDC(m_hMemDC);
+	if (m_hBitmap)	::DeleteObject(m_hBitmap);
+	if (m_hDib)		delete m_hDib;
+
+	m_hDib = NULL;
+	m_hMemDC = NULL;
+	m_hBitmap = NULL;
+	m_lpBits = NULL;
+	memset(&m_bi, 0, sizeof(m_bi));
+} // End of FreeResources
+
+HDIB CCeXDib::Create(DWORD dwWidth, DWORD dwHeight, WORD wBitCount)
+{
+    LPBITMAPINFOHEADER  lpbi = NULL;	// Pointer to BITMAPINFOHEADER
+    DWORD               dwLen = 0;		// Size of memory block
+
+	FreeResources();
+
+	// Following <switch> is taken from
+	// CDIBSectionLite class by Chris Maunder
+    switch (wBitCount) 
+    {
+	    case 1:  m_wColors = 2;   break;
+#ifdef _WIN32_WCE
+        case 2:  m_wColors = 4;   break;   // winCE only       
+#endif
+        case 4:  m_wColors = 16;  break;
+        case 8:  m_wColors = 256; break;
+        case 16:
+        case 24:
+        case 32: m_wColors = 0;   break;   // 16,24 or 32 bpp have no color table
+
+        default:
+           m_wColors = 0;
+    } // switch
+/*
+    // Make sure bits per pixel is valid
+    if (wBitCount <= 1)			wBitCount = 1;
+    else if (wBitCount <= 4)	wBitCount = 4;
+    else if (wBitCount <= 8)	wBitCount = 8;
+    else				        wBitCount = 24;
+
+    switch (wBitCount)
+	{
+        case 1:
+            m_wColors = 2;
+			break;
+        case 4:
+            m_wColors = 16;
+			break;
+        case 8:
+            m_wColors = 256;
+			break;
+        default:
+            m_wColors = 0;
+			break;
+    } // switch
+*/
+    m_dwLineWidth = WIDTHBYTES(wBitCount * dwWidth);
+
+    // Initialize BITMAPINFOHEADER
+    m_bi.biSize = sizeof(BITMAPINFOHEADER);
+    m_bi.biWidth = dwWidth;         // fill in width from parameter
+    m_bi.biHeight = dwHeight;       // fill in height from parameter
+    m_bi.biPlanes = 1;              // must be 1
+    m_bi.biBitCount = wBitCount;    // from parameter
+    m_bi.biCompression = BI_RGB;    
+    m_bi.biSizeImage = m_dwLineWidth * dwHeight;
+    m_bi.biXPelsPerMeter = 0;
+    m_bi.biYPelsPerMeter = 0;
+    m_bi.biClrUsed = 0;
+    m_bi.biClrImportant = 0;
+
+    // Calculate size of memory block required to store the DIB.  This
+    // block should be big enough to hold the BITMAPINFOHEADER, the color
+    // table, and the bits.
+    dwLen = GetSize();
+
+	m_hDib = new HDIB[dwLen]; // Allocate memory block to store our bitmap
+    if (m_hDib == NULL) return NULL;
+
+    // Use our bitmap info structure to fill in first part of
+    // our DIB with the BITMAPINFOHEADER
+	lpbi = (LPBITMAPINFOHEADER)(m_hDib);
+    *lpbi = m_bi;
+
+    return m_hDib; // Return handle to the DIB
+} // End of Create
+
+DWORD CCeXDib::GetSize()
+{
+	return m_bi.biSize + m_bi.biSizeImage + GetPaletteSize();
+} // End of GetSize
+
+DWORD CCeXDib::GetPaletteSize()
+{
+	return (m_wColors * sizeof(RGBQUAD));
+} // End of GetPaletteSize
+
+LPBYTE CCeXDib::GetBits()
+{
+	if (m_hDib)	return ((LPBYTE)m_hDib + *(LPDWORD)m_hDib + GetPaletteSize()); 
+
+	return NULL;
+} // End of GetBits
+
+DWORD CCeXDib::GetWidth()
+{
+	return m_bi.biWidth;
+} // End of GetWidth
+
+DWORD CCeXDib::GetHeight()
+{
+	return m_bi.biHeight;
+} // End of GetHeight
+
+DWORD CCeXDib::GetLineWidth()
+{
+	return m_dwLineWidth;
+} // End of GetLineWidth
+
+void CCeXDib::BlendPalette(COLORREF crColor, DWORD dwPerc)
+{
+	if (m_hDib == NULL || m_wColors == 0) return;
+
+	LPBYTE iDst = (LPBYTE)(m_hDib) + sizeof(BITMAPINFOHEADER);
+
+	long i,r,g,b;
+
+	RGBQUAD* pPal = (RGBQUAD*)iDst;
+
+	r = GetRValue(crColor);
+	g = GetGValue(crColor);
+	b = GetBValue(crColor);
+
+	if (dwPerc > 100) dwPerc = 100;
+
+	for (i = 0; i < m_wColors; i++)
+	{
+		pPal[i].rgbBlue = (BYTE)((pPal[i].rgbBlue * (100 - dwPerc) + b * dwPerc) / 100);
+		pPal[i].rgbGreen = (BYTE)((pPal[i].rgbGreen * (100 - dwPerc) + g * dwPerc) / 100);
+		pPal[i].rgbRed = (BYTE)((pPal[i].rgbRed * (100 - dwPerc) + r * dwPerc) / 100);
+	} // for
+} // End of BlendPalette
+
+void CCeXDib::Clear(BYTE byVal)
+{
+	if (m_hDib) memset(GetBits(), byVal, m_bi.biSizeImage);
+} // End of Clear
+
+void CCeXDib::SetPixelIndex(DWORD dwX, DWORD dwY, BYTE byI)
+{
+	if ((m_hDib == NULL) || (m_wColors == 0) ||
+		((long)dwX < 0) || ((long)dwY < 0) || (dwX >= (DWORD)m_bi.biWidth) || (dwY >= (DWORD)m_bi.biHeight)) return;
+
+	LPBYTE iDst = GetBits();
+	iDst[(m_bi.biHeight - dwY - 1) * m_dwLineWidth + dwX] = byI;
+} // End of SetPixelIndex
+
+void CCeXDib::Clone(CCeXDib* src)
+{
+	Create(src->GetWidth(), src->GetHeight(), src->GetBitCount());
+	if (m_hDib) memcpy(m_hDib, src->m_hDib, GetSize());
+} // End of Clone
+
+WORD CCeXDib::GetBitCount()
+{
+	return m_bi.biBitCount;
+} // End of GetBitCount
+
+void CCeXDib::SetPaletteIndex(BYTE byIdx, BYTE byR, BYTE byG, BYTE byB)
+{
+	if (m_hDib && m_wColors)
+	{
+		LPBYTE iDst = (LPBYTE)(m_hDib) + sizeof(BITMAPINFOHEADER);
+		if ((byIdx >= 0) && (byIdx < m_wColors))
+		{	
+			long ldx = byIdx * sizeof(RGBQUAD);
+			iDst[ldx++] = (BYTE)byB;
+			iDst[ldx++] = (BYTE)byG;
+			iDst[ldx++] = (BYTE)byR;
+			iDst[ldx] = (BYTE)0;
+		} // if
+	} // if
+} // End of SetPaletteIndex
+
+void CCeXDib::Draw(HDC hDC, DWORD dwX, DWORD dwY)
+{
+	HBITMAP	hBitmap = NULL;
+	HBITMAP	hOldBitmap = NULL;
+	HDC		hMemDC = NULL;
+
+	if (m_hBitmap == NULL)
+	{
+		m_hBitmap = CreateDIBSection(hDC, (BITMAPINFO*)m_hDib, DIB_RGB_COLORS, &m_lpBits, NULL, 0);
+		if (m_hBitmap == NULL)	return;
+		if (m_lpBits == NULL)
+		{
+			::DeleteObject(m_hBitmap);
+			m_hBitmap = NULL;
+			return;
+		} // if
+	} // if
+
+    memcpy(m_lpBits, GetBits(), m_bi.biSizeImage);
+
+	if (m_hMemDC == NULL)
+	{
+		m_hMemDC = CreateCompatibleDC(hDC);
+		if (m_hMemDC == NULL)	return;
+	} // if
+
+	hOldBitmap = (HBITMAP)SelectObject(m_hMemDC, m_hBitmap);
+
+	BitBlt(hDC, dwX, dwY, m_bi.biWidth, m_bi.biHeight, m_hMemDC, 0, 0, SRCCOPY);
+
+	SelectObject(m_hMemDC, hOldBitmap);
+} // End of Draw
+
+void CCeXDib::SetGrayPalette()
+{
+	RGBQUAD		pal[256];
+	RGBQUAD*	ppal;
+	LPBYTE		iDst;
+	int			ni;
+
+	if (m_hDib == NULL || m_wColors == 0) return;
+
+	ppal = (RGBQUAD*)&pal[0];
+	iDst = (LPBYTE)(m_hDib) + sizeof(BITMAPINFOHEADER);
+	for (ni = 0; ni < m_wColors; ni++)
+	{
+		pal[ni] = RGB2RGBQUAD(RGB(ni,ni,ni));
+	} // for
+
+	pal[0] = RGB2RGBQUAD(RGB(0,0,0));
+	pal[m_wColors-1] = RGB2RGBQUAD(RGB(255,255,255));
+
+	memcpy(iDst, ppal, GetPaletteSize());
+} // End of SetGrayPalette
+
+RGBQUAD CCeXDib::RGB2RGBQUAD(COLORREF cr)
+{
+	RGBQUAD c;
+	c.rgbRed = GetRValue(cr);	/* get R, G, and B out of DWORD */
+	c.rgbGreen = GetGValue(cr);
+	c.rgbBlue = GetBValue(cr);
+	c.rgbReserved=0;
+	return c;
+} // End of RGB2RGBQUAD
+
+WORD CCeXDib::GetNumColors()
+{
+	return m_wColors;
+} // End of GetNumColors
+
+BOOL CCeXDib::WriteBMP(LPCTSTR bmpFileName)
+{
+	BITMAPFILEHEADER	hdr;
+	HANDLE	hFile;
+	DWORD	nByteWrite;
+
+	if (*bmpFileName == _T('\0') || m_hDib == 0) return 0;
+
+	hFile=CreateFile(			// open if exist ini file
+		bmpFileName,			// pointer to name of the file 
+		GENERIC_WRITE,			// access mode 
+		0,						// share mode 
+		NULL,					// pointer to security descriptor 
+		CREATE_ALWAYS,			// how to create 
+		FILE_ATTRIBUTE_NORMAL,	// file attributes 
+		NULL				 	// handle to file with attributes to copy  
+		);
+	if (hFile == INVALID_HANDLE_VALUE) return FALSE;
+
+    // Fill in the fields of the file header
+	hdr.bfType = BFT_BITMAP;
+	hdr.bfSize = GetSize() + sizeof(BITMAPFILEHEADER);
+	hdr.bfReserved1 = hdr.bfReserved2 = 0;
+	hdr.bfOffBits = (DWORD) sizeof(BITMAPFILEHEADER)+
+					m_bi.biSize + GetPaletteSize();
+
+    // Write the file header
+	WriteFile(						// write ini (sync mode <-> no overlapped)
+		hFile,						// handle of file to write 
+		(LPSTR) &hdr,				// address of buffer that contains data  
+		sizeof(BITMAPFILEHEADER),	// number of bytes to write 
+		&nByteWrite,				// address of number of bytes written 
+		NULL	 					// address of structure for data 
+		);
+
+    // Write the DIB header and the bits
+	WriteFile(						// write ini (sync mode <-> no overlapped)
+		hFile,						// handle of file to write 
+		(LPSTR) m_hDib,				// address of buffer that contains data  
+		GetSize(),					// number of bytes to write 
+		&nByteWrite,				// address of number of bytes written 
+		NULL	 					// address of structure for data 
+		);
+
+	CloseHandle(hFile);				// free file handle
+
+	return TRUE;
+} // End of WriteBMP

+ 96 - 0
Source/OGCAssistTool/OGCAssistTool/CeXDib.h

@@ -0,0 +1,96 @@
+//
+//	Class:		CCeXDib
+//
+//	Compiler:	Visual C++
+//				eMbedded Visual C++
+//	Tested on:	Visual C++ 6.0
+//				Windows CE 3.0
+//
+//	Author:		Davide Calabro'		davide_calabro@yahoo.com
+//									http://www.softechsoftware.it
+//
+//	Note:		This class uses code snippets taken from a similar class written
+//				for the Win32 enviroment by Davide Pizzolato (ing.davide.pizzolato@libero.it)
+//
+//	Disclaimer
+//	----------
+//	THIS SOFTWARE AND THE ACCOMPANYING FILES ARE DISTRIBUTED "AS IS" AND WITHOUT
+//	ANY WARRANTIES WHETHER EXPRESSED OR IMPLIED. NO REPONSIBILITIES FOR POSSIBLE
+//	DAMAGES OR EVEN FUNCTIONALITY CAN BE TAKEN. THE USER MUST ASSUME THE ENTIRE
+//	RISK OF USING THIS SOFTWARE.
+//
+//	Terms of use
+//	------------
+//	THIS SOFTWARE IS FREE FOR PERSONAL USE OR FREEWARE APPLICATIONS.
+//	IF YOU USE THIS SOFTWARE IN COMMERCIAL OR SHAREWARE APPLICATIONS YOU
+//	ARE GENTLY ASKED TO DONATE 1$ (ONE U.S. DOLLAR) TO THE AUTHOR:
+//
+//		Davide Calabro'
+//		P.O. Box 65
+//		21019 Somma Lombardo (VA)
+//		Italy
+//
+//
+#ifndef _CEXDIB_H_
+#define _CEXDIB_H_
+
+#if _MSC_VER > 1000
+#pragma once
+#endif // _MSC_VER > 1000
+
+#ifndef	HDIB
+#define HDIB	HANDLE
+#endif
+
+#ifndef WIDTHBYTES
+#define WIDTHBYTES(bits)    (((bits) + 31) / 32 * 4)
+#endif
+
+#ifndef BFT_BITMAP
+#define BFT_BITMAP 0x4d42   // 'BM'
+#endif
+
+class CCeXDib  
+{
+public:
+	CCeXDib();
+	virtual ~CCeXDib();
+
+	HDIB Create(DWORD dwWidth, DWORD dwHeight, WORD wBitCount);
+	void Clone(CCeXDib* src);
+	void Draw(HDC hDC, DWORD dwX, DWORD dwY);
+	LPBYTE GetBits();
+	void Clear(BYTE byVal = 0);
+
+	void SetGrayPalette();
+	void SetPaletteIndex(BYTE byIdx, BYTE byR, BYTE byG, BYTE byB);
+	void SetPixelIndex(DWORD dwX, DWORD dwY, BYTE byI);
+	void BlendPalette(COLORREF crColor, DWORD dwPerc);
+
+	WORD GetBitCount();
+	DWORD GetLineWidth();
+	DWORD GetWidth();
+	DWORD GetHeight();
+	WORD GetNumColors();
+
+	BOOL WriteBMP(LPCTSTR bmpFileName);
+
+private:
+	void FreeResources();
+
+	DWORD GetPaletteSize();
+	DWORD GetSize();
+
+	RGBQUAD RGB2RGBQUAD(COLORREF cr);
+
+	HDIB				m_hDib;
+    BITMAPINFOHEADER    m_bi;
+	DWORD				m_dwLineWidth;
+	WORD				m_wColors;
+
+	HBITMAP				m_hBitmap;	// Handle to bitmap
+	HDC					m_hMemDC;	// Handle to memory DC
+	LPVOID				m_lpBits;	// Pointer to actual bitmap bits
+};
+
+#endif 

+ 5 - 6
Source/OGCAssistTool/OGCAssistTool/Global.cpp

@@ -176,10 +176,10 @@ again:
 		return FALSE;
 	}
 
-	INT CheckOutData(std::vector<std::string> &vtData, std::vector<RGB_PAT> &vtResult)
+	void CheckOutData(std::vector<std::string> &vtData, std::vector<RGB_PAT> &vtResult)
 	{
 		if ( vtData.size() < 3 )
-			return 0;
+			return;
 
 		int nIndex = 0;
 		for (std::vector<std::string>::iterator it = vtData.begin(); it != vtData.end(); it++ )
@@ -203,11 +203,9 @@ again:
 
 			nIndex++;
 		}
-
-		return 0;
 	}
 
-	BOOL IsDebugPass(std::vector<RGB_PAT> &vtDebugRGB, INT nDeltaEType, DOUBLE dDeltaEValue)
+	BOOL IsDebugPass(std::vector<RGB_PAT> &vtDebugRGB, INT nDeltaEType, DOUBLE dDeltaEValue, DOUBLE &dDeltaEAVGValue)
 	{
 		BOOL bRet = FALSE;
 		DOUBLE dAllDeltaEValue = 0.0;
@@ -222,7 +220,8 @@ again:
 				dAllDeltaEValue += atof(it->deltaE00.c_str());
 		}
 
-		if ( dDeltaEValue <= dAllDeltaEValue/vtDebugRGB.size() )
+		dDeltaEAVGValue = dAllDeltaEValue/vtDebugRGB.size();
+		if ( dDeltaEValue <= dDeltaEAVGValue )
 			bRet = TRUE;
 
 		return bRet;

+ 2 - 2
Source/OGCAssistTool/OGCAssistTool/Global.h

@@ -176,8 +176,8 @@ namespace GLOBAL {
 
 	std::string GetFileData(LPCTSTR lpFile);
 	std::string GetFileLine(std::string &strFileData, int nLine);
-	INT CheckOutData(std::vector<std::string> &vtData, std::vector<RGB_PAT> &vtResult);
-	BOOL IsDebugPass(std::vector<RGB_PAT> &vtDebugRGB, INT nDeltaEType, DOUBLE dDeltaEValue);
+	void CheckOutData(std::vector<std::string> &vtData, std::vector<RGB_PAT> &vtResult);
+	BOOL IsDebugPass(std::vector<RGB_PAT> &vtDebugRGB, INT nDeltaEType, DOUBLE dDeltaEValue, DOUBLE &dDeltaEAVGValue);
 	BOOL FindString(std::vector<std::string> &vtString, std::string strFind, std::string &strResult);
 	void GetStringList(std::string strData, std::string strSplit, std::vector<std::string> &vtString);
 	BOOL GetFileVersion( IN HMODULE hModule, IN DWORD (&dwArray)[4]);

+ 494 - 0
Source/OGCAssistTool/OGCAssistTool/HyperLink.cpp

@@ -0,0 +1,494 @@
+// HyperLink.cpp : implementation file
+//
+// HyperLink static control. Will open the default browser with the given URL
+// when the user clicks on the link.
+//
+// Copyright (C) 1997 - 1999 Chris Maunder
+// All rights reserved. May not be sold for profit.
+//
+// Thanks to Pål K. Tønder for auto-size and window caption changes.
+//
+// "GotoURL" function by Stuart Patterson
+// As seen in the August, 1997 Windows Developer's Journal.
+// Copyright 1997 by Miller Freeman, Inc. All rights reserved.
+// Modified by Chris Maunder to use TCHARs instead of chars.
+//
+// "Default hand cursor" from Paul DiLascia's Jan 1998 MSJ article.
+//
+// 2/29/00 -- P. Shaffer standard font mod.
+
+#include "stdafx.h"
+#include "HyperLink.h"
+
+#include "atlconv.h"    // for Unicode conversion - requires #include <afxdisp.h> // MFC OLE automation classes
+
+#ifdef _DEBUG
+#define new DEBUG_NEW
+#undef THIS_FILE
+static char THIS_FILE[] = __FILE__;
+#endif
+
+#define TOOLTIP_ID 1
+
+/////////////////////////////////////////////////////////////////////////////
+// CHyperLink
+
+CHyperLink::CHyperLink()
+{
+    m_hLinkCursor       = NULL;                 // No cursor as yet
+    m_crLinkColour      = RGB(  0,   0, 238);   // Blue
+    m_crVisitedColour   = RGB( 85,  26, 139);   // Purple
+    m_crHoverColour     = RGB(255,   0,   0);   // Red
+    m_bOverControl      = FALSE;                // Cursor not yet over control
+    m_bVisited          = FALSE;                // Hasn't been visited yet.
+    m_nUnderline        = ulHover;              // Underline the link?
+    m_bAdjustToFit      = TRUE;                 // Resize the window to fit the text?
+    m_strURL.Empty();
+    m_nTimerID          = 100;
+}
+
+CHyperLink::~CHyperLink()
+{
+    m_UnderlineFont.DeleteObject();
+}
+
+/////////////////////////////////////////////////////////////////////////////
+// CHyperLink overrides
+
+BOOL CHyperLink::DestroyWindow() 
+{
+    KillTimer(m_nTimerID);
+	
+	return CStatic::DestroyWindow();
+}
+
+BOOL CHyperLink::PreTranslateMessage(MSG* pMsg) 
+{
+    m_ToolTip.RelayEvent(pMsg);
+    return CStatic::PreTranslateMessage(pMsg);
+}
+
+
+void CHyperLink::PreSubclassWindow() 
+{
+    // We want to get mouse clicks via STN_CLICKED
+    DWORD dwStyle = GetStyle();
+    ::SetWindowLong(GetSafeHwnd(), GWL_STYLE, dwStyle | SS_NOTIFY);
+    
+    // Set the URL as the window text
+    if (m_strURL.IsEmpty())
+        GetWindowText(m_strURL);
+
+    // Check that the window text isn't empty. If it is, set it as the URL.
+    CString strWndText;
+    GetWindowText(strWndText);
+    if (strWndText.IsEmpty()) 
+    {
+        ASSERT(!m_strURL.IsEmpty());    // Window and URL both NULL. DUH!
+        SetWindowText(m_strURL);
+    }
+
+	CFont* pFont = GetFont();
+	if (!pFont)
+	{
+		HFONT hFont = (HFONT)GetStockObject(DEFAULT_GUI_FONT);
+		if (hFont == NULL)
+			hFont = (HFONT) GetStockObject(ANSI_VAR_FONT);
+		if (hFont)
+			pFont = CFont::FromHandle(hFont);
+	}
+	ASSERT(pFont->GetSafeHandle());
+
+    // Create the underline font
+    LOGFONT lf;
+    pFont->GetLogFont(&lf);
+	m_StdFont.CreateFontIndirect(&lf);
+    lf.lfUnderline = (BYTE) TRUE;
+    m_UnderlineFont.CreateFontIndirect(&lf);
+
+    PositionWindow();        // Adjust size of window to fit URL if necessary
+    SetDefaultCursor();      // Try and load up a "hand" cursor
+    SetUnderline();
+
+    // Create the tooltip
+    CRect rect; 
+    GetClientRect(rect);
+    m_ToolTip.Create(this);
+    m_ToolTip.AddTool(this, m_strURL, rect, TOOLTIP_ID);
+
+    CStatic::PreSubclassWindow();
+}
+
+BEGIN_MESSAGE_MAP(CHyperLink, CStatic)
+    //{{AFX_MSG_MAP(CHyperLink)
+    ON_WM_CTLCOLOR_REFLECT()
+    ON_WM_SETCURSOR()
+    ON_WM_MOUSEMOVE()
+	ON_WM_TIMER()
+    ON_CONTROL_REFLECT(STN_CLICKED, OnClicked)
+	ON_WM_ERASEBKGND()
+	//}}AFX_MSG_MAP
+END_MESSAGE_MAP()
+
+/////////////////////////////////////////////////////////////////////////////
+// CHyperLink message handlers
+
+void CHyperLink::OnClicked()
+{
+    m_bOverControl = FALSE;
+    int result = (int)GotoURL(m_strURL, SW_SHOW);
+    m_bVisited = (result > HINSTANCE_ERROR);
+    if (!m_bVisited)
+    {
+        MessageBeep(MB_ICONEXCLAMATION);     // Unable to follow link
+        ReportError(result);
+    }
+    else 
+        SetVisited();                        // Repaint to show visited colour
+}
+
+HBRUSH CHyperLink::CtlColor(CDC* pDC, UINT nCtlColor) 
+{
+    ASSERT(nCtlColor == CTLCOLOR_STATIC);
+
+    if (m_bOverControl)
+        pDC->SetTextColor(m_crHoverColour);
+    else if (m_bVisited)
+        pDC->SetTextColor(m_crVisitedColour);
+    else
+        pDC->SetTextColor(m_crLinkColour);
+
+    // transparent text.
+    pDC->SetBkMode(TRANSPARENT);
+    return (HBRUSH)GetStockObject(NULL_BRUSH);
+}
+
+void CHyperLink::OnMouseMove(UINT nFlags, CPoint point) 
+{
+    if (!m_bOverControl)        // Cursor has just moved over control
+    {
+        m_bOverControl = TRUE;
+
+        if (m_nUnderline == ulHover)
+            SetFont(&m_UnderlineFont);
+        Invalidate();
+
+        SetTimer(m_nTimerID, 100, NULL);
+    }
+    CStatic::OnMouseMove(nFlags, point);
+}
+
+void CHyperLink::OnTimer(UINT nIDEvent) 
+{
+    CPoint p(GetMessagePos());
+    ScreenToClient(&p);
+
+    CRect rect;
+    GetClientRect(rect);
+    if (!rect.PtInRect(p))
+    {
+        m_bOverControl = FALSE;
+        KillTimer(m_nTimerID);
+
+        if (m_nUnderline != ulAlways)
+            SetFont(&m_StdFont);
+        rect.bottom+=10;
+        InvalidateRect(rect);
+    }
+    
+	CStatic::OnTimer(nIDEvent);
+}
+
+BOOL CHyperLink::OnSetCursor(CWnd* /*pWnd*/, UINT /*nHitTest*/, UINT /*message*/) 
+{
+    if (m_hLinkCursor)
+    {
+        ::SetCursor(m_hLinkCursor);
+        return TRUE;
+    }
+    return FALSE;
+}
+
+BOOL CHyperLink::OnEraseBkgnd(CDC* pDC) 
+{
+    CRect rect;
+    GetClientRect(rect);
+    pDC->FillSolidRect(rect, ::GetSysColor(COLOR_3DFACE));
+
+    return TRUE;
+}
+
+/////////////////////////////////////////////////////////////////////////////
+// CHyperLink operations
+
+void CHyperLink::SetURL(CString strURL)
+{
+    m_strURL = strURL;
+
+    if (::IsWindow(GetSafeHwnd())) {
+        PositionWindow();
+        m_ToolTip.UpdateTipText(strURL, this, TOOLTIP_ID);
+    }
+}
+
+CString CHyperLink::GetURL() const
+{ 
+    return m_strURL;   
+}
+
+void CHyperLink::SetColours(COLORREF crLinkColour, COLORREF crVisitedColour,
+                            COLORREF crHoverColour /* = -1 */) 
+{ 
+    m_crLinkColour    = crLinkColour; 
+    m_crVisitedColour = crVisitedColour;
+
+	if (crHoverColour == -1)
+		m_crHoverColour = ::GetSysColor(COLOR_HIGHLIGHT);
+	else
+		m_crHoverColour = crHoverColour;
+
+    if (::IsWindow(m_hWnd))
+        Invalidate(); 
+}
+
+COLORREF CHyperLink::GetLinkColour() const
+{ 
+    return m_crLinkColour; 
+}
+
+COLORREF CHyperLink::GetVisitedColour() const
+{
+    return m_crVisitedColour; 
+}
+
+COLORREF CHyperLink::GetHoverColour() const
+{
+    return m_crHoverColour;
+}
+
+void CHyperLink::SetVisited(BOOL bVisited /* = TRUE */) 
+{ 
+    m_bVisited = bVisited; 
+
+    if (::IsWindow(GetSafeHwnd()))
+        Invalidate(); 
+}
+
+BOOL CHyperLink::GetVisited() const
+{ 
+    return m_bVisited; 
+}
+
+void CHyperLink::SetLinkCursor(HCURSOR hCursor)
+{ 
+    m_hLinkCursor = hCursor;
+    if (m_hLinkCursor == NULL)
+        SetDefaultCursor();
+}
+
+HCURSOR CHyperLink::GetLinkCursor() const
+{
+    return m_hLinkCursor;
+}
+
+void CHyperLink::SetUnderline(int nUnderline /*=ulHover*/)
+{
+    if (m_nUnderline == nUnderline)
+        return;
+
+    if (::IsWindow(GetSafeHwnd()))
+    {
+        if (nUnderline == ulAlways)
+            SetFont(&m_UnderlineFont);
+        else
+            SetFont(&m_StdFont);
+
+        Invalidate(); 
+    }
+
+    m_nUnderline = nUnderline;
+}
+
+int CHyperLink::GetUnderline() const
+{ 
+    return m_nUnderline; 
+}
+
+void CHyperLink::SetAutoSize(BOOL bAutoSize /* = TRUE */)
+{
+    m_bAdjustToFit = bAutoSize;
+
+    if (::IsWindow(GetSafeHwnd()))
+        PositionWindow();
+}
+
+BOOL CHyperLink::GetAutoSize() const
+{ 
+    return m_bAdjustToFit; 
+}
+
+
+// Move and resize the window so that the window is the same size
+// as the hyperlink text. This stops the hyperlink cursor being active
+// when it is not directly over the text. If the text is left justified
+// then the window is merely shrunk, but if it is centred or right
+// justified then the window will have to be moved as well.
+//
+// Suggested by Pål K. Tønder 
+
+void CHyperLink::PositionWindow()
+{
+    if (!::IsWindow(GetSafeHwnd()) || !m_bAdjustToFit) 
+        return;
+
+    // Get the current window position
+    CRect WndRect, ClientRect;
+    GetWindowRect(WndRect);
+    GetClientRect(ClientRect);
+
+    ClientToScreen(ClientRect);
+
+    CWnd* pParent = GetParent();
+    if (pParent)
+    {
+        pParent->ScreenToClient(WndRect);
+        pParent->ScreenToClient(ClientRect);
+    }
+
+    // Get the size of the window text
+    CString strWndText;
+    GetWindowText(strWndText);
+
+    CDC* pDC = GetDC();
+    CFont* pOldFont = pDC->SelectObject(&m_UnderlineFont);
+    CSize Extent = pDC->GetTextExtent(strWndText);
+    pDC->SelectObject(pOldFont);
+    ReleaseDC(pDC);
+
+    // Adjust for window borders
+    Extent.cx += WndRect.Width() - ClientRect.Width(); 
+    Extent.cy += WndRect.Height() - ClientRect.Height(); 
+
+    // Get the text justification via the window style
+    DWORD dwStyle = GetStyle();
+
+    // Recalc the window size and position based on the text justification
+    if (dwStyle & SS_CENTERIMAGE)
+        WndRect.DeflateRect(0, (WndRect.Height() - Extent.cy)/2);
+    else
+        WndRect.bottom = WndRect.top + Extent.cy;
+
+    if (dwStyle & SS_CENTER)   
+        WndRect.DeflateRect((WndRect.Width() - Extent.cx)/2, 0);
+    else if (dwStyle & SS_RIGHT) 
+        WndRect.left  = WndRect.right - Extent.cx;
+    else // SS_LEFT = 0, so we can't test for it explicitly 
+        WndRect.right = WndRect.left + Extent.cx;
+
+    // Move the window
+    SetWindowPos(NULL, WndRect.left, WndRect.top, WndRect.Width(), WndRect.Height(), SWP_NOZORDER);
+}
+
+/////////////////////////////////////////////////////////////////////////////
+// CHyperLink implementation
+
+// The following appeared in Paul DiLascia's Jan 1998 MSJ articles.
+// It loads a "hand" cursor from the winhlp32.exe module
+void CHyperLink::SetDefaultCursor()
+{
+    if (m_hLinkCursor == NULL)                // No cursor handle - load our own
+    {
+        // Get the windows directory
+        CString strWndDir;
+        GetWindowsDirectory(strWndDir.GetBuffer(MAX_PATH), MAX_PATH);
+        strWndDir.ReleaseBuffer();
+
+        strWndDir += _T("\\winhlp32.exe");
+        // This retrieves cursor #106 from winhlp32.exe, which is a hand pointer
+        HMODULE hModule = LoadLibrary(strWndDir);
+        if (hModule) {
+            HCURSOR hHandCursor = ::LoadCursor(hModule, MAKEINTRESOURCE(106));
+            if (hHandCursor)
+                m_hLinkCursor = CopyCursor(hHandCursor);
+        }
+        FreeLibrary(hModule);
+    }
+}
+
+LONG CHyperLink::GetRegKey(HKEY key, LPCTSTR subkey, LPTSTR retdata)
+{
+    HKEY hkey;
+    LONG retval = RegOpenKeyEx(key, subkey, 0, KEY_QUERY_VALUE, &hkey);
+
+    if (retval == ERROR_SUCCESS) {
+        long datasize = MAX_PATH;
+        TCHAR data[MAX_PATH];
+        RegQueryValue(hkey, NULL, data, &datasize);
+        lstrcpy(retdata,data);
+        RegCloseKey(hkey);
+    }
+
+    return retval;
+}
+
+void CHyperLink::ReportError(int nError)
+{
+    CString str;
+    switch (nError) {
+        case 0:                       str = _T("The operating system is out\nof memory or resources."); break;
+        case SE_ERR_PNF:              str = _T("The specified path was not found."); break;
+        case SE_ERR_FNF:              str = _T("The specified file was not found."); break;
+        case ERROR_BAD_FORMAT:        str = _T("The .EXE file is invalid\n(non-Win32 .EXE or error in .EXE image)."); break;
+        case SE_ERR_ACCESSDENIED:     str = _T("The operating system denied\naccess to the specified file."); break;
+        case SE_ERR_ASSOCINCOMPLETE:  str = _T("The filename association is\nincomplete or invalid."); break;
+        case SE_ERR_DDEBUSY:          str = _T("The DDE transaction could not\nbe completed because other DDE transactions\nwere being processed."); break;
+        case SE_ERR_DDEFAIL:          str = _T("The DDE transaction failed."); break;
+        case SE_ERR_DDETIMEOUT:       str = _T("The DDE transaction could not\nbe completed because the request timed out."); break;
+        case SE_ERR_DLLNOTFOUND:      str = _T("The specified dynamic-link library was not found."); break;
+        case SE_ERR_NOASSOC:          str = _T("There is no application associated\nwith the given filename extension."); break;
+        case SE_ERR_OOM:              str = _T("There was not enough memory to complete the operation."); break;
+        case SE_ERR_SHARE:            str = _T("A sharing violation occurred. ");
+        default:                      str.Format(_T("Unknown Error (%d) occurred."), nError); break;
+    }
+    str = _T("Unable to open hyperlink:\n\n") + str;
+    AfxMessageBox(str, MB_ICONEXCLAMATION | MB_OK);
+}
+
+HINSTANCE CHyperLink::GotoURL(LPCTSTR url, int showcmd)
+{
+    TCHAR key[MAX_PATH + MAX_PATH];
+
+    // First try ShellExecute()
+    HINSTANCE result = ShellExecute(NULL, _T("open"), url, NULL,NULL, showcmd);
+
+    // If it failed, get the .htm regkey and lookup the program
+    if ((UINT)result <= HINSTANCE_ERROR) {
+
+        if (GetRegKey(HKEY_CLASSES_ROOT, _T(".htm"), key) == ERROR_SUCCESS) {
+            lstrcat(key, _T("\\shell\\open\\command"));
+
+            if (GetRegKey(HKEY_CLASSES_ROOT,key,key) == ERROR_SUCCESS) {
+                TCHAR *pos;
+                pos = _tcsstr(key, _T("\"%1\""));
+                if (pos == NULL) {                     // No quotes found
+                    pos = _tcsstr(key, _T("%1"));      // Check for %1, without quotes 
+                    if (pos == NULL)                   // No parameter at all...
+                        pos = key+lstrlen(key)-1;
+                    else
+                        *pos = '\0';                   // Remove the parameter
+                }
+                else
+                    *pos = '\0';                       // Remove the parameter
+
+                lstrcat(pos, _T(" "));
+                lstrcat(pos, url);
+
+                USES_CONVERSION;
+                result = (HINSTANCE) WinExec(T2A(key),showcmd);
+            }
+        }
+    }
+
+    return result;
+}
+

+ 106 - 0
Source/OGCAssistTool/OGCAssistTool/HyperLink.h

@@ -0,0 +1,106 @@
+// HyperLink.h : header file
+//
+//
+// HyperLink static control. Will open the default browser with the given URL
+// when the user clicks on the link.
+//
+// Copyright Chris Maunder, 1997-1999 (cmaunder@mail.com)
+// Feel free to use and distribute. May not be sold for profit. 
+
+// 2/29/00 -- P. Shaffer standard font mod.
+
+#if !defined(AFX_HYPERLINK_H__D1625061_574B_11D1_ABBA_00A0243D1382__INCLUDED_)
+#define AFX_HYPERLINK_H__D1625061_574B_11D1_ABBA_00A0243D1382__INCLUDED_
+
+#if _MSC_VER >= 1000
+#pragma once
+#endif // _MSC_VER >= 1000
+
+/////////////////////////////////////////////////////////////////////////////
+// CHyperLink window
+
+class CHyperLink : public CStatic
+{
+// Construction/destruction
+public:
+    CHyperLink();
+    virtual ~CHyperLink();
+
+public:
+    enum UnderLineOptions { ulHover = -1, ulNone = 0, ulAlways = 1};
+
+// Attributes
+public:
+    void SetURL(CString strURL);
+    CString GetURL() const;
+
+    void SetColours(COLORREF crLinkColour, COLORREF crVisitedColour, 
+                    COLORREF crHoverColour = -1);
+    COLORREF GetLinkColour() const;
+    COLORREF GetVisitedColour() const;
+    COLORREF GetHoverColour() const;
+
+    void SetVisited(BOOL bVisited = TRUE);
+    BOOL GetVisited() const;
+
+    void SetLinkCursor(HCURSOR hCursor);
+    HCURSOR GetLinkCursor() const;
+
+    void SetUnderline(int nUnderline = ulHover);
+    int  GetUnderline() const;
+
+    void SetAutoSize(BOOL bAutoSize = TRUE);
+    BOOL GetAutoSize() const;
+
+// Overrides
+    // ClassWizard generated virtual function overrides
+    //{{AFX_VIRTUAL(CHyperLink)
+	public:
+    virtual BOOL PreTranslateMessage(MSG* pMsg);
+	virtual BOOL DestroyWindow();
+	protected:
+    virtual void PreSubclassWindow();
+	//}}AFX_VIRTUAL
+
+// Implementation
+protected:
+    HINSTANCE GotoURL(LPCTSTR url, int showcmd);
+    void ReportError(int nError);
+    LONG GetRegKey(HKEY key, LPCTSTR subkey, LPTSTR retdata);
+    void PositionWindow();
+    void SetDefaultCursor();
+
+// Protected attributes
+protected:
+    COLORREF m_crLinkColour, m_crVisitedColour;     // Hyperlink colours
+    COLORREF m_crHoverColour;                       // Hover colour
+    BOOL     m_bOverControl;                        // cursor over control?
+    BOOL     m_bVisited;                            // Has it been visited?
+    int      m_nUnderline;                          // underline hyperlink?
+    BOOL     m_bAdjustToFit;                        // Adjust window size to fit text?
+    CString  m_strURL;                              // hyperlink URL
+    CFont    m_UnderlineFont;                       // Font for underline display
+    CFont    m_StdFont;                             // Standard font
+    HCURSOR  m_hLinkCursor;                         // Cursor for hyperlink
+    CToolTipCtrl m_ToolTip;                         // The tooltip
+    UINT     m_nTimerID;
+
+    // Generated message map functions
+protected:
+    //{{AFX_MSG(CHyperLink)
+    afx_msg HBRUSH CtlColor(CDC* pDC, UINT nCtlColor);
+    afx_msg BOOL OnSetCursor(CWnd* pWnd, UINT nHitTest, UINT message);
+    afx_msg void OnMouseMove(UINT nFlags, CPoint point);
+	afx_msg void OnTimer(UINT nIDEvent);
+	afx_msg BOOL OnEraseBkgnd(CDC* pDC);
+	//}}AFX_MSG
+    afx_msg void OnClicked();
+    DECLARE_MESSAGE_MAP()
+};
+
+/////////////////////////////////////////////////////////////////////////////
+
+//{{AFX_INSERT_LOCATION}}
+// Microsoft Developer Studio will insert additional declarations immediately before the previous line.
+
+#endif // !defined(AFX_HYPERLINK_H__D1625061_574B_11D1_ABBA_00A0243D1382__INCLUDED_)

+ 4 - 5
Source/OGCAssistTool/OGCAssistTool/OGCAssistTool.cpp

@@ -128,17 +128,15 @@ BOOL COGCAssistToolApp::InitInstance()
 
 	MTVERIFY(GLOBAL::GetConfigInfo());
 
-	GLOBAL::g_IOCP.Start();
-
 	GLOBAL::g_db.Open();
-#ifdef _DEBUG
+#if 0
 	TB_ORDER order;
 	std::vector<TB_ORDER> vtOrder;
 	GLOBAL::g_db.QueryOrder("3322", order);
 	GLOBAL::g_db.InsertOrder("5555", "DeltaE00", "3.6", 1);
 	GLOBAL::g_db.UpdateOrder("5555", "DeltaE98", "1.02", 1);
-	GLOBAL::g_db.InsertSN("5555", "T302", "dfdfdf", "2022-03-19 09:25:19", "2022-03-19 09:25:59", 25532, 1, 3.2, "");
-	GLOBAL::g_db.UpdateSNData("5555", "dfdfdf", "T302",  "2022-03-19 09:25:19", "2022-03-19 09:25:59", 25532, 1, 3.2, "3.02/128/128/128\r\n3.02/128/128/128\r\n3.02/128/128/128\r\n3.02/128/128/128\r\n3.02/128/128/128\r\n3.02/128/128/128\r\n3.02/128/128/128\r\n3.02/128/128/128\r\n3.02/128/128/128\r\n3.02/128/128/128\r\n3.02/128/128/128\r\n3.02/128/128/128\r\n3.02/128/128/128\r\n3.02/128/128/128\r\n3.02/128/128/128\r\n3.02/128/128/128\r\n3.02/128/128/128\r\n3.02/128/128/128\r\n3.02/128/128/128\r\n3.02/128/128/128\r\n3.02/128/128/128\r\n3.02/128/128/128\r\n3.02/128/128/128\r\n3.02/128/128/128\r\n3.02/128/128/128\r\n3.02/128/128/128\r\n3.02/128/128/128\r\n3.02/128/128/128\r\n3.02/128/128/128\r\n3.02/128/128/128\r\n3.02/128/128/128\r\n3.02/128/128/128\r\n3.02/128/128/128\r\n");
+	GLOBAL::g_db.InsertSN("5555", "T302", "dfdfdf", "2022-03-19 09:25:19", "2022-03-19 09:25:59", 25532, 1, 3.2, 2.0, "");
+	GLOBAL::g_db.UpdateSNData("5555", "dfdfdf", "T302",  "2022-03-19 09:25:19", "2022-03-19 09:25:59", 25532, 1, 3.2, 2.0, "3.02/128/128/128\r\n3.02/128/128/128\r\n3.02/128/128/128\r\n3.02/128/128/128\r\n3.02/128/128/128\r\n3.02/128/128/128\r\n3.02/128/128/128\r\n3.02/128/128/128\r\n3.02/128/128/128\r\n3.02/128/128/128\r\n3.02/128/128/128\r\n3.02/128/128/128\r\n3.02/128/128/128\r\n3.02/128/128/128\r\n3.02/128/128/128\r\n3.02/128/128/128\r\n3.02/128/128/128\r\n3.02/128/128/128\r\n3.02/128/128/128\r\n3.02/128/128/128\r\n3.02/128/128/128\r\n3.02/128/128/128\r\n3.02/128/128/128\r\n3.02/128/128/128\r\n3.02/128/128/128\r\n3.02/128/128/128\r\n3.02/128/128/128\r\n3.02/128/128/128\r\n3.02/128/128/128\r\n3.02/128/128/128\r\n3.02/128/128/128\r\n3.02/128/128/128\r\n3.02/128/128/128\r\n");
 	GLOBAL::g_db.QueryOrders(vtOrder, "2022-04-01 02:25:19", "2022-04-21 02:25:19");
 
 	TCHAR szCSV[MAX_PATH] = {0};
@@ -149,6 +147,7 @@ BOOL COGCAssistToolApp::InitInstance()
 	GLOBAL::GetStringList(strFileData, strFindString, vtString);
 	std::vector<GLOBAL::RGB_PAT> vtRGB;
 	GLOBAL::CheckOutData(vtString, vtRGB);
+	GLOBAL::IsDebugPass(vtRGB, 0, 1.3);
 #endif
 
 #pragma region ´ò¿ªÄ¿±ê½ø³Ì;

+ 0 - 9
Source/OGCAssistTool/OGCAssistTool/OGCAssistTool.rc

@@ -147,9 +147,6 @@ STYLE DS_SETFONT | DS_FIXEDSYS | WS_CHILD
 EXSTYLE WS_EX_STATICEDGE
 FONT 8, "MS Shell Dlg", 400, 0, 0x1
 BEGIN
-    DEFPUSHBUTTON   "确定",IDOK,388,222,50,14
-    PUSHBUTTON      "取消",IDCANCEL,443,222,50,14
-    PUSHBUTTON      "日志",IDC_BUTTON1,95,86,50,14
 END
 
 PAGE_STATISTICS DIALOGEX 0, 0, 732, 322
@@ -157,9 +154,6 @@ STYLE DS_SETFONT | DS_FIXEDSYS | WS_CHILD
 EXSTYLE WS_EX_STATICEDGE
 FONT 8, "MS Shell Dlg", 400, 0, 0x1
 BEGIN
-    DEFPUSHBUTTON   "确定",IDOK,388,222,50,14
-    PUSHBUTTON      "取消",IDCANCEL,443,222,50,14
-    PUSHBUTTON      "统计",IDC_BUTTON1,95,86,50,14
 END
 
 PAGE_CONFIG DIALOGEX 0, 0, 732, 322
@@ -167,9 +161,6 @@ STYLE DS_SETFONT | DS_FIXEDSYS | WS_CHILD
 EXSTYLE WS_EX_STATICEDGE
 FONT 8, "MS Shell Dlg", 400, 0, 0x1
 BEGIN
-    DEFPUSHBUTTON   "确定",IDOK,388,222,50,14
-    PUSHBUTTON      "取消",IDCANCEL,443,222,50,14
-    PUSHBUTTON      "设置",IDC_BUTTON1,95,86,50,14
 END
 
 

+ 52 - 0
Source/OGCAssistTool/OGCAssistTool/OGCAssistTool.vcproj

@@ -404,6 +404,58 @@
 				>
 			</File>
 		</Filter>
+		<Filter
+			Name="UI"
+			>
+			<File
+				RelativePath=".\BCMenu.cpp"
+				>
+			</File>
+			<File
+				RelativePath=".\BCMenu.h"
+				>
+			</File>
+			<File
+				RelativePath=".\BtnST.cpp"
+				>
+			</File>
+			<File
+				RelativePath=".\BtnST.h"
+				>
+			</File>
+			<File
+				RelativePath=".\CeXDib.cpp"
+				>
+			</File>
+			<File
+				RelativePath=".\CeXDib.h"
+				>
+			</File>
+			<File
+				RelativePath=".\HyperLink.cpp"
+				>
+			</File>
+			<File
+				RelativePath=".\HyperLink.h"
+				>
+			</File>
+			<File
+				RelativePath=".\ShadeButtonST.cpp"
+				>
+			</File>
+			<File
+				RelativePath=".\ShadeButtonST.h"
+				>
+			</File>
+			<File
+				RelativePath=".\WinXPButtonST.cpp"
+				>
+			</File>
+			<File
+				RelativePath=".\WinXPButtonST.h"
+				>
+			</File>
+		</Filter>
 		<File
 			RelativePath=".\ReadMe.txt"
 			>

+ 2 - 0
Source/OGCAssistTool/OGCAssistTool/OGCAssistToolDlg.cpp

@@ -123,6 +123,8 @@ BOOL COGCAssistToolDlg::OnInitDialog()
 
 	SetTimer(0, 300, NULL);
 
+	GLOBAL::g_IOCP.Start();
+
 	return TRUE;  // 除非将焦点设置到控件,否则返回 TRUE
 }
 

+ 278 - 48
Source/OGCAssistTool/OGCAssistTool/PageDebug.cpp

@@ -16,8 +16,12 @@ extern HWND g_hWnd_Tester;
 extern HWND g_hWnd_FWVersion;
 extern HWND g_hWnd_Channel;
 extern BOOL StartOGCTool();
+DWORD CPageDebug::m_dwGoProcThreadId=0;
 // CDlgDebug 对话框
 
+#define COLOR_RED RGB(255,0,0)
+#define COLOR_GREED RGB(0,255,0)
+
 CPageDebug *CPageDebug::m_pDlg = NULL;
 IMPLEMENT_DYNAMIC(CPageDebug, CDialogEx)
 
@@ -35,6 +39,8 @@ void CPageDebug::DoDataExchange(CDataExchange* pDX)
 {
 	CDialogEx::DoDataExchange(pDX);
 	DDX_Control(pDX, LIST_DEBUG_DATA, m_ctrlList);
+	DDX_Control(pDX, BTN_CONNECT, m_btnConnect);
+	DDX_Control(pDX, COMBO_ETYPE, m_cbDeltaEType);
 }
 
 
@@ -47,6 +53,7 @@ BEGIN_MESSAGE_MAP(CPageDebug, CDialogEx)
 	ON_WM_TIMER()
 	ON_BN_CLICKED(CHECK_LOCK, &CPageDebug::OnBnClickedLock)
 	ON_BN_CLICKED(BTN_LOAD_DATA, &CPageDebug::OnBnClickedLoadData)
+	ON_CBN_SELCHANGE(COMBO_ETYPE, &CPageDebug::OnCbnSelchangeEtype)
 END_MESSAGE_MAP()
 
 
@@ -86,7 +93,13 @@ BOOL CPageDebug::OnInitDialog()
 		((CComboBox*)GetDlgItem(COMBO_ETYPE))->SetCurSel(GLOBAL::g_config.nDeltaEType);
 	}
 
-	GLOBAL::g_IOCP.SetCallBack(ConnectProc, NULL, GoProc, NULL);
+	m_btnConnect.SetFaceColor(COLOR_RED);
+	GLOBAL::g_IOCP.SetCallBack(NULL, NULL, NULL, ReceiveProc);
+	SetDlgItemText(EDIT_LINE, GLOBAL::g_config.szLine);
+
+	HANDLE hThread = CreateThread(NULL, 0, ThreadGoProc, this, 0, &m_dwGoProcThreadId);
+	if ( hThread )
+		CloseHandle(hThread);
 
 	return TRUE;  // return TRUE unless you set the focus to a control
 	// 异常: OCX 属性页应返回 FALSE
@@ -163,73 +176,252 @@ BOOL CPageDebug::ConnectProc(DATAHEADER *pHeader, MSG_INFO *pMsg)
 	if ( m_pDlg == NULL )
 		return FALSE;
 
+	static DATAHEADER header;
+	header=*pHeader;
+	static MSG_INFO msg;
+	msg=*pMsg;
+	PostThreadMessage(m_dwGoProcThreadId, WM_CONNECT_PRO, (WPARAM)&header, (LPARAM)&msg);
+
+	/*
 	if ( pHeader->byMsgType == C2S_CONNECT )
 		m_pDlg->SetDlgItemText(BTN_CONNECT, pMsg->byResult ? _T("断开连接") : _T("连接设备"));
 	else if ( pHeader->byMsgType == C2S_DISCONNECT )
 		m_pDlg->SetDlgItemText(BTN_CONNECT, pMsg->byResult ? _T("连接设备") : _T("断开连接"));
+	*/
 }
 
-BOOL CPageDebug::GoProc(DATAHEADER *pHeader, MSG_INFO *pMsg)
+BOOL CPageDebug::ReceiveProc(DATAHEADER *pHeader, MSG_INFO *pMsg)
 {
 	if ( !pHeader || !pMsg )
 		return FALSE;
 
-	// 获取时间;
-	DWORD dwElapsed = _tstol((TCHAR*)pMsg->byData);
-	// 获取Config.dat第七行;
-	TCHAR szConfigPath[MAX_PATH] = {0};
-	_stprintf_s(szConfigPath, _T("%s\\Config.dat"), GLOBAL::g_config.szOGCToolPath);
-	if ( PathFileExists(szConfigPath) )
+	DATAHEADER header=*pHeader;
+	MSG_INFO msg_info=*pMsg;
+
+	switch( header.byMsgType )
 	{
-		CFile file;
-		CFileException excep;
-		if ( file.Open(szConfigPath, CFile::modeRead, &excep) )
+	case C2S_HIJACK:
 		{
-			DWORD dwRead = 0;
-			DWORD dwCount = 0;
-			string strData;
-			char szRead[MAX_PATH] = {0};
-			DWORD dwLen = file.GetLength();
-			while ( dwCount < dwLen )
-			{
-				dwRead = file.Read(szRead, MAX_PATH);
-				strData.append(szRead, dwRead);
-				dwCount += dwRead;
-			}
+			static MSG_INFO msg;
+			static DATAHEADER header;			
+			msg=*pMsg;
+			header=*pHeader;
+			dprintf(_T("接收到客户端消息:劫持"));
+			PostThreadMessage(m_dwGoProcThreadId, C2S_HIJACK, (WPARAM)&header, (LPARAM)&msg);
+		}
+		break;
+	case C2S_RESUME:
+		{
+			static MSG_INFO msg;
+			static DATAHEADER header;			
+			msg=*pMsg;
+			header=*pHeader;
+			dprintf(_T("接收到客户端消息:恢复"));
+			PostThreadMessage(m_dwGoProcThreadId, C2S_RESUME, (WPARAM)&header, (LPARAM)&msg);
+		}
+		break;
+	case C2S_CONNECT:
+		{
+			static MSG_INFO msg;
+			static DATAHEADER header;			
+			msg=*pMsg;
+			header=*pHeader;
+			dprintf(_T("接收到客户端消息:连接"));
+			PostThreadMessage(m_dwGoProcThreadId, C2S_CONNECT, (WPARAM)&header, (LPARAM)&msg);
+		}
+		break;
+	case C2S_DISCONNECT:
+		{
+			static MSG_INFO msg;
+			static DATAHEADER header;			
+			msg=*pMsg;
+			header=*pHeader;
+			dprintf(_T("接收到客户端消息:断开"));
+			PostThreadMessage(m_dwGoProcThreadId, C2S_DISCONNECT, (WPARAM)&header, (LPARAM)&msg);
+		}
+		break;
+	case C2S_CHECKFW:
+		{
+			static MSG_INFO msg;
+			static DATAHEADER header;			
+			msg=*pMsg;
+			header=*pHeader;
+			dprintf(_T("接收到客户端消息:CheckFW"));
+			PostThreadMessage(m_dwGoProcThreadId, C2S_CHECKFW, (WPARAM)&header, (LPARAM)&msg);
+		}
+		break;
+	case C2S_EXCEPTION:
+		{
+			static MSG_INFO msg;
+			static DATAHEADER header;			
+			msg=*pMsg;
+			header=*pHeader;
+			dprintf(_T("接收到客户端消息:异常"));
+			PostThreadMessage(m_dwGoProcThreadId, C2S_EXCEPTION, (WPARAM)&header, (LPARAM)&msg);
+		}
+		break;
+	case C2S_GO:
+		{
+			static MSG_INFO msg;
+			static DATAHEADER header;			
+			msg=*pMsg;
+			header=*pHeader;
+			dprintf(_T("接收到客户端消息:Go"));
+			PostThreadMessage(m_dwGoProcThreadId, C2S_GO, (WPARAM)&header, (LPARAM)&msg);			
+		}
+		break;
+	case C2S_COMMUNICATION_ERROR:
+		{
+			static MSG_INFO msg;
+			static DATAHEADER header;			
+			msg=*pMsg;
+			header=*pHeader;
+			dprintf(_T("接收到客户端消息:通信错误"));
+			PostThreadMessage(m_dwGoProcThreadId, C2S_COMMUNICATION_ERROR, (WPARAM)&header, (LPARAM)&msg);
+		}
+		break;
+	default:
+		break;
+	}
 
-			file.Close();
+	return FALSE;
+}
 
-			// 获取第七行;
-			int nPos=0;
-			int nIndex = 0;
-			while ( (nPos=strData.find('\r\n')) != std::string::npos )
+DWORD CPageDebug::ThreadGoProc(LPVOID lpParam)
+{
+	MSG msg;
+	CPageDebug* pDlg = (CPageDebug*)lpParam;
+	while (::GetMessage(&msg, NULL, 0, 0))
+	{
+		switch (msg.message)
+		{
+		case C2S_HIJACK:
 			{
-				if ( nIndex++ == 6 )
+				DATAHEADER &header = *(DATAHEADER*)msg.wParam;
+				MSG_INFO &msg_info = *(MSG_INFO*)msg.lParam;
+
+				if ( msg_info.byResult )
 				{
-					strData = strData.substr(0, nPos);
-					break;
+					GLOBAL::g_procWndInfo.bHijackStatus = TRUE;
+					((CButton*)m_pDlg->GetDlgItem(CHECK_HIJACK))->SetCheck(TRUE);
 				}
-				strData = strData.substr(nPos+2);				
 			}
-
-			// 输出的文件cvs路径;
-			CString strSN;
-			m_pDlg->GetDlgItemText(EDIT_SN, strSN);
-			TCHAR szOutDataPath[MAX_PATH] = {0};
-			_stprintf_s(szOutDataPath, _T("%s\\Output_%s_%s\\%s\\sRGB_32Patterns_.csv"), GLOBAL::g_config.szOGCToolPath, CharEncoding::ASCII2UNICODE(strData.c_str()), CTime::GetCurrentTime().Format("%Y%m%d").GetString(), strSN.GetString());
-			if ( PathFileExists(szOutDataPath) )
+			break;
+		case C2S_RESUME:
 			{
-				// 文件存在,按行读取;
-				std::string strFileData = GLOBAL::GetFileData(szOutDataPath);
-				if ( strFileData.size() )
+				DATAHEADER &header = *(DATAHEADER*)msg.wParam;
+				MSG_INFO &msg_info = *(MSG_INFO*)msg.lParam;
+				if ( msg_info.byResult )
 				{
-
+					GLOBAL::g_procWndInfo.bHijackStatus = FALSE;
+					((CButton*)m_pDlg->GetDlgItem(CHECK_HIJACK))->SetCheck(FALSE);
 				}
 			}
+			break;
+		case C2S_CONNECT:
+			{
+				DATAHEADER &header = *(DATAHEADER*)msg.wParam;
+				MSG_INFO &msg_info = *(MSG_INFO*)msg.lParam;
+				GLOBAL::g_procWndInfo.bConnectStatus = msg_info.byResult;
+				m_pDlg->SetDlgItemText(BTN_CONNECT, msg_info.byResult ? _T("断开连接") : _T("连接设备"));
+				m_pDlg->m_btnConnect.SetFaceColor(msg_info.byResult ? COLOR_GREED : COLOR_RED);
+			}
+			break;
+		case C2S_DISCONNECT:
+			{
+				DATAHEADER &header = *(DATAHEADER*)msg.wParam;
+				MSG_INFO &msg_info = *(MSG_INFO*)msg.lParam;
+				GLOBAL::g_procWndInfo.bConnectStatus = !msg_info.byResult;
+				m_pDlg->SetDlgItemText(BTN_CONNECT, msg_info.byResult ? _T("连接设备") : _T("断开连接"));
+				m_pDlg->m_btnConnect.SetFaceColor(msg_info.byResult ? COLOR_RED : COLOR_GREED);
+			}
+			break;
+		case C2S_GO:
+			{
+				DATAHEADER &header = *(DATAHEADER*)msg.wParam;
+				MSG_INFO &msg_info = *(MSG_INFO*)msg.lParam;
+				// 获取时间;
+				DWORD dwElapsed = _tstol((TCHAR*)msg_info.byData);
+				// 获取Config.dat第七行;
+				TCHAR szConfigPath[MAX_PATH] = {0};
+				_stprintf_s(szConfigPath, _T("%s\\Config.dat"), GLOBAL::g_config.szOGCToolPath);
+				if ( PathFileExists(szConfigPath) )
+				{
+					CFile file;
+					CFileException excep;
+					if ( file.Open(szConfigPath, CFile::modeRead, &excep) )
+					{
+						DWORD dwRead = 0;
+						DWORD dwCount = 0;
+						string strData;
+						char szRead[MAX_PATH] = {0};
+						DWORD dwLen = file.GetLength();
+						while ( dwCount < dwLen )
+						{
+							dwRead = file.Read(szRead, MAX_PATH);
+							strData.append(szRead, dwRead);
+							dwCount += dwRead;
+						}
+
+						file.Close();
+
+						// 获取第七行;
+						int nPos=0;
+						int nIndex = 0;
+						while ( (nPos=strData.find('\r\n')) != std::string::npos )
+						{
+							if ( nIndex++ == 6 )
+							{
+								strData = strData.substr(0, nPos);
+								break;
+							}
+							strData = strData.substr(nPos+2);				
+						}
+
+						// 输出的文件cvs路径;
+						CString strSN;
+						m_pDlg->GetDlgItemText(EDIT_SN, strSN);
+						TCHAR szOutDataPath[MAX_PATH] = {0};
+						_stprintf_s(szOutDataPath, _T("%s\\Output_%s_%s\\%s\\sRGB_32Patterns_.csv"), GLOBAL::g_config.szOGCToolPath, CharEncoding::ASCII2UNICODE(strData.c_str()), CTime::GetCurrentTime().Format("%Y%m%d").GetString(), strSN.GetString());
+						if ( PathFileExists(szOutDataPath) )
+						{
+							// 文件存在,按行读取;
+							std::string strFileData = GLOBAL::GetFileData(szOutDataPath);
+							if ( strFileData.size() )
+							{
+								std::vector<std::string> vtList;
+								GLOBAL::GetStringList(strFileData, "\r\n", vtList);
+								if ( vtList.size() )
+								{
+									DOUBLE dAVGValue = 0.0;
+									std::vector<GLOBAL::RGB_PAT> vtRGB;
+									GLOBAL::CheckOutData(vtList, vtRGB);
+									if ( vtRGB.size() )
+									{
+										BOOL bRet = GLOBAL::IsDebugPass(vtRGB, GLOBAL::g_config.nDeltaEType, GLOBAL::g_config.dDeltaEValue, dAVGValue);
+										if ( bRet )
+										{
+
+										}
+										else
+										{
+
+										}
+									}
+								}
+							}
+						}
+					}
+				}
+
+				m_pDlg->GetDlgItem(BTN_TEST)->EnableWindow(TRUE);
+			}
+			break;
+		default:
+			break;
 		}
 	}
-
-	return FALSE;
+	return 0;
 }
 
 void CPageDebug::OnBnClickedShowWnd()
@@ -280,7 +472,36 @@ void CPageDebug::OnBnClickedTest()
 	if ( GLOBAL::g_procWndInfo.bHijackStatus && GLOBAL::g_procWndInfo.bConnectStatus )
 	{
 		CString strSN;
+		CString strOrderID;
+		CString strDeltaEValue;
 		GetDlgItemText(EDIT_SN, strSN);
+		GetDlgItemText(EDIT_BATCH_NUMBER, strOrderID);
+		GetDlgItemText(EDIT_EVALUE, strDeltaEValue);
+
+		if ( strOrderID.IsEmpty() )
+		{
+			MessageBox(_T("错误:订单号不能空,请输入订单号!"), _T("错误!"), MB_ICONERROR);
+			return;
+		}
+
+		if ( ((CComboBox*)GetDlgItem(COMBO_ETYPE))->GetCurSel() == CB_ERR )
+		{
+			MessageBox(_T("错误:未选择指定的DeltaE类型!"), _T("错误!"), MB_ICONERROR);
+			return;
+		}
+
+		if ( strDeltaEValue.IsEmpty() )
+		{
+			MessageBox(_T("错误:DeltaE标准值不能空,请输入DeltaE标准值!"), _T("错误!"), MB_ICONERROR);
+			return;
+		}
+
+		if ( GLOBAL::IsDigitString(strDeltaEValue) == -1 )
+		{
+			MessageBox(_T("错误:DeltaE标准值非数字,请输入数字!"), _T("错误!"), MB_ICONERROR);
+			return;
+		}
+
 		if ( strSN.IsEmpty() )
 		{
 			MessageBox(_T("错误:SN不能空,请输入SN!"), _T("错误!"), MB_ICONERROR);
@@ -314,12 +535,12 @@ void CPageDebug::OnBnClickedTest()
 		if ( hWnd )
 		{
 			::PostMessage(hWnd, WM_LBUTTONDOWN, 0, 0);
-			Sleep(20);
+			Sleep(50);
 			::PostMessage(hWnd, WM_LBUTTONUP, 0, 0);
 		}
 
 		GetDlgItem(BTN_TEST)->EnableWindow(FALSE);
-		SetTimer(1, 500, NULL);
+		//SetTimer(1, 500, NULL);
 	}
 	else
 	{
@@ -366,7 +587,7 @@ void CPageDebug::OnBnClickedConnect()
 					if ( hWnd )
 					{
 						::PostMessage(hWnd, WM_LBUTTONDOWN, 0, 0);
-						Sleep(20);
+						Sleep(50);
 						::PostMessage(hWnd, WM_LBUTTONUP, 0, 0);
 					}
 
@@ -377,6 +598,7 @@ void CPageDebug::OnBnClickedConnect()
 				{
 					MessageBox(_T("设备已连接成功~"), _T("提示!"), MB_OK);
 					SetDlgItemText(BTN_CONNECT, _T("断开设备"));
+					m_btnConnect.SetFaceColor(COLOR_GREED);
 				}
 			}
 			break;
@@ -390,7 +612,7 @@ void CPageDebug::OnBnClickedConnect()
 		if ( hWnd )
 		{
 			::PostMessage(hWnd, WM_LBUTTONDOWN, 0, 0);
-			Sleep(20);
+			Sleep(50);
 			::PostMessage(hWnd, WM_LBUTTONUP, 0, 0);
 		}
 
@@ -474,3 +696,11 @@ void CPageDebug::OnBnClickedLoadData()
 {
 	// TODO: 在此添加控件通知处理程序代码
 }
+
+void CPageDebug::OnCbnSelchangeEtype()
+{
+	// TODO: 在此添加控件通知处理程序代码
+	INT nCurSel = m_cbDeltaEType.GetCurSel();
+	if ( nCurSel != CB_ERR )
+		GLOBAL::g_config.nDeltaEType = nCurSel;
+}

+ 10 - 1
Source/OGCAssistTool/OGCAssistTool/PageDebug.h

@@ -1,6 +1,10 @@
 #pragma once
 #include "afxcmn.h"
+#include "afxwin.h"
 
+// ÏûÏ¢;
+#define WM_CONNECT_PRO			(WM_USER + 1001)
+#define WM_GO_PROC				(WM_USER + 1002)
 
 // CDlgDebug ¶Ô»°¿ò
 extern HWND MyFindWindow(LPCTSTR lpClassName);
@@ -38,7 +42,7 @@ public:
 	}
 	static CPageDebug *m_pDlg;
 	static BOOL CALLBACK ConnectProc(DATAHEADER *pHeader, MSG_INFO *pMsg);
-	static BOOL CALLBACK GoProc(DATAHEADER *pHeader, MSG_INFO *pMsg);
+	static BOOL CALLBACK ReceiveProc(DATAHEADER *pHeader, MSG_INFO *pMsg);
 	afx_msg void OnBnClickedShowWnd();
 	afx_msg void OnBnClickedHijack();
 	afx_msg void OnBnClickedTest();
@@ -50,4 +54,9 @@ protected:
 public:
 	afx_msg void OnBnClickedLock();
 	afx_msg void OnBnClickedLoadData();
+	CMFCButton m_btnConnect;
+	static DWORD m_dwGoProcThreadId;
+	static DWORD WINAPI ThreadGoProc(LPVOID lpParam);
+	afx_msg void OnCbnSelchangeEtype();
+	CComboBox m_cbDeltaEType;
 };

+ 2 - 73
Source/OGCAssistTool/OGCAssistTool/PipeService.cpp

@@ -475,79 +475,8 @@ void CIOCPPipe::RecvProcess(PER_PIPE_CONTEXT* pPipeContext, PER_IO_CONTEXT* pIoC
 			msg_info.byData
 			);
 
-		switch( header.byMsgType )
-		{
-		case C2S_HIJACK:
-			{
-				dprintf(_T("接收到客户端消息:劫持"));
-				GLOBAL::g_procWndInfo.bHijackStatus = msg_info.byResult;
-			}
-			break;
-		case C2S_RESUME:
-			{
-				dprintf(_T("接收到客户端消息:恢复"));
-				GLOBAL::g_procWndInfo.bHijackStatus = !msg_info.byResult;
-			}
-			break;
-		case C2S_CONNECT:
-			{
-				dprintf(_T("接收到客户端消息:连接"));
-				GLOBAL::g_procWndInfo.bConnectStatus = msg_info.byResult;
-				// 发送第一个请求:回调处理;
-				if ( lpOnConnectCallback )
-				{
-					lpOnConnectCallback(&header, &msg_info);
-				}
-			}
-			break;
-		case C2S_DISCONNECT:
-			{
-				dprintf(_T("接收到客户端消息:断开"));
-				GLOBAL::g_procWndInfo.bConnectStatus = !msg_info.byResult;
-				// 发送第一个请求:回调处理;
-				if ( lpOnConnectCallback )
-				{
-					lpOnConnectCallback(&header, &msg_info);
-				}
-			}
-			break;
-		case C2S_CHECKFW:
-			{
-				dprintf(_T("接收到客户端消息:CheckFW"));
-			}
-			break;
-		case C2S_EXCEPTION:
-			{
-				dprintf(_T("接收到客户端消息:异常"));
-			}
-			break;
-		case C2S_GO:
-			{
-				dprintf(_T("接收到客户端消息:Go"));
-				if ( msg_info.byResult )
-				{
-					// 执行成功;
-				}
-				else
-				{
-					// 执行失败;
-				}
-
-				// 发送第一个请求:回调处理;
-				if ( lpOnGoCallback )
-				{
-					lpOnGoCallback(&header, &msg_info);
-				}
-			}
-			break;
-		case C2S_COMMUNICATION_ERROR:
-			{
-				dprintf(_T("接收到客户端消息:通信错误"));
-			}
-			break;
-		default:
-			break;
-		}
+		if ( lpOnReciveCallback )
+			lpOnReciveCallback(&header, &msg_info);
 
 		DWORD lpNumberOfBytesWritten = 0;
 		TCHAR szMsg[MAX_PATH] = {0};

+ 1 - 1
Source/OGCAssistTool/OGCAssistTool/PipeService.h

@@ -151,7 +151,7 @@ typedef BOOL(CALLBACK *OnConnectCallback)(DATAHEADER *pHeader, MSG_INFO* pMsg);
 // 回调客户端断开时;
 typedef BOOL(CALLBACK* OnDisconnectCallback)(PER_IO_CONTEXT* pIoContext);
 // 回调客户端消息到来时;
-typedef BOOL(CALLBACK *OnReciveCallback)(PER_PIPE_CONTEXT *pPipeContext, PER_IO_CONTEXT *pIoContext);
+typedef BOOL(CALLBACK *OnReciveCallback)(DATAHEADER *pHeader, MSG_INFO* pMsg);
 
 // 工作者线程的线程参数
 class CIOCPPipe;

+ 25 - 0
Source/OGCAssistTool/OGCAssistTool/Protocol.h

@@ -58,6 +58,19 @@ typedef struct _MSG_INFO_
 		memset(byData, 0, DATA_LEN);
 		memset(szClientName, 0, sizeof(TCHAR)*NAME_LEN);
 	}
+
+	_MSG_INFO_ &operator=(const _MSG_INFO_ &that)
+	{
+		if ( this == &that )
+			return *this;
+
+		dwClientId = that.dwClientId;
+		byResult = that.byResult;
+		memcpy(szClientName, that.szClientName, NAME_LEN);
+		memcpy(byData, that.byData, DATA_LEN);
+
+		return *this;
+	}
 }MSG_INFO,*LPMSG_INFO;
 
 typedef struct _HEADER_
@@ -74,6 +87,18 @@ typedef struct _HEADER_
 		dwPackageLen = sizeof(_HEADER_) + sizeof(MSG_INFO);
 		byMsgType = 0;
 	}
+
+	_HEADER_ &operator=(const _HEADER_ &that)
+	{
+		if ( this == &that )
+			return *this;
+	
+		byProtocol = that.byProtocol;
+		dwPackageLen = that.dwPackageLen;
+		byMsgType = that.byMsgType;
+
+		return *this;
+	}
 }DATAHEADER, *LPDATAHEADER;
 
 // ÇëÇó°ü

+ 251 - 0
Source/OGCAssistTool/OGCAssistTool/ShadeButtonST.cpp

@@ -0,0 +1,251 @@
+#include "stdafx.h"
+#include "ShadeButtonST.h"
+
+#ifdef _DEBUG
+#undef THIS_FILE
+static char THIS_FILE[]=__FILE__;
+#define new DEBUG_NEW
+#endif
+
+CShadeButtonST::CShadeButtonST()
+{
+}
+
+CShadeButtonST::~CShadeButtonST()
+{
+}
+
+void CShadeButtonST::SetShade(UINT shadeID, BYTE granularity, BYTE highlight, BYTE coloring, COLORREF color)
+{
+	long	sXSize,sYSize,bytes,j,i,k,h;
+	BYTE	*iDst ,*posDst;
+	
+	RECT rect;
+	GetWindowRect(&rect);
+	sYSize=rect.bottom-rect.top;
+	sXSize=rect.right-rect.left ;
+
+	m_dh.Create(max(1,sXSize /*-2*m_FocusRectMargin-1*/ ),1,8);	//create the horizontal focus bitmap
+	m_dv.Create(1,max(1,sYSize /*-2*m_FocusRectMargin*/),8);	//create the vertical focus bitmap
+
+	m_dNormal.Create(sXSize,sYSize,8);					//create the default bitmap
+
+	COLORREF hicr=GetSysColor(COLOR_BTNHIGHLIGHT);		//get the button base colors
+	COLORREF midcr=GetSysColor(COLOR_BTNFACE);
+	COLORREF locr=GetSysColor(COLOR_BTNSHADOW);
+	long r,g,b;											//build the shaded palette
+	for(i=0;i<129;i++){
+		r=((128-i)*GetRValue(locr)+i*GetRValue(midcr))/128;
+		g=((128-i)*GetGValue(locr)+i*GetGValue(midcr))/128;
+		b=((128-i)*GetBValue(locr)+i*GetBValue(midcr))/128;
+		m_dNormal.SetPaletteIndex((BYTE)i,(BYTE)r,(BYTE)g,(BYTE)b);
+		m_dh.SetPaletteIndex((BYTE)i,(BYTE)r,(BYTE)g,(BYTE)b);
+		m_dv.SetPaletteIndex((BYTE)i,(BYTE)r,(BYTE)g,(BYTE)b);
+	}
+	for(i=1;i<129;i++){
+		r=((128-i)*GetRValue(midcr)+i*GetRValue(hicr))/128;
+		g=((128-i)*GetGValue(midcr)+i*GetGValue(hicr))/128;
+		b=((128-i)*GetBValue(midcr)+i*GetBValue(hicr))/128;
+		m_dNormal.SetPaletteIndex((BYTE)(i+127),(BYTE)r,(BYTE)g,(BYTE)b);
+		m_dh.SetPaletteIndex((BYTE)(i+127),(BYTE)r,(BYTE)g,(BYTE)b);
+		m_dv.SetPaletteIndex((BYTE)(i+127),(BYTE)r,(BYTE)g,(BYTE)b);
+	}
+
+	m_dNormal.BlendPalette(color,coloring);	//color the palette
+
+	iDst=m_dh.GetBits();		//build the horiz. dotted focus bitmap
+	j=(long)m_dh.GetWidth();
+	for(i=0;i<j;i++){
+//		iDst[i]=64+127*(i%2);	//soft
+		iDst[i]=255*(i%2);		//hard
+	}
+
+	iDst=m_dv.GetBits();		//build the vert. dotted focus bitmap
+	j=(long)m_dv.GetHeight();
+	for(i=0;i<j;i++){
+//		*iDst=64+127*(i%2);		//soft
+		*iDst=255*(i%2);		//hard
+		iDst+=4;
+	}
+
+	bytes = m_dNormal.GetLineWidth();
+	iDst = m_dNormal.GetBits();
+	posDst =iDst;
+	long a,x,y,d,xs,idxmax,idxmin;
+
+	int grainx2=RAND_MAX/(max(1,2*granularity));
+	idxmax=255-granularity;
+	idxmin=granularity;
+
+	switch(shadeID){
+//----------------------------------------------------
+	case 8:	//SHS_METAL
+		m_dNormal.Clear();
+		// create the strokes
+		k=40;	//stroke granularity
+		for(a=0;a<200;a++){
+			x=rand()/(RAND_MAX/sXSize); //stroke postion
+			y=rand()/(RAND_MAX/sYSize);	//stroke position
+			xs=rand()/(RAND_MAX/min(sXSize,sYSize))/2; //stroke lenght
+			d=rand()/(RAND_MAX/k);	//stroke color
+			for(i=0;i<xs;i++){
+				if (((x-i)>0)&&((y+i)<sYSize))
+					m_dNormal.SetPixelIndex(x-i,y+i,(BYTE)d);
+				if (((x+i)<sXSize)&&((y-i)>0))
+					m_dNormal.SetPixelIndex(sXSize-x+i,y-i,(BYTE)d);
+			}
+		}
+		//blend strokes with SHS_DIAGONAL
+		posDst =iDst;
+		a=(idxmax-idxmin-k)/2;
+		for(i = 0; i < sYSize; i++) {
+			for(j = 0; j < sXSize; j++) {
+				d=posDst[j]+((a*i)/sYSize+(a*(sXSize-j))/sXSize);
+				posDst[j]=(BYTE)d;
+				posDst[j]+=rand()/grainx2;
+			}
+			posDst+=bytes;
+		}
+
+		break;
+//----------------------------------------------------
+	case 7:	// SHS_HARDBUMP
+		//set horizontal bump
+		for(i = 0; i < sYSize; i++) {
+			k=(255*i/sYSize)-127;
+			k=(k*(k*k)/128)/128;
+			k=(k*(128-granularity*2))/128+128;
+			for(j = 0; j < sXSize; j++) {
+				posDst[j]=(BYTE)k;
+				posDst[j]+=rand()/grainx2-granularity;
+			}
+			posDst+=bytes;
+		}
+		//set vertical bump
+		d=min(16,sXSize/6);	//max edge=16
+		a=sYSize*sYSize/4;
+		posDst =iDst;
+		for(i = 0; i < sYSize; i++) {
+			y=i-sYSize/2;
+			for(j = 0; j < sXSize; j++) {
+				x=j-sXSize/2;
+				xs=sXSize/2-d+(y*y*d)/a;
+				if (x>xs) posDst[j]=idxmin+(BYTE)(((sXSize-j)*128)/d);
+				if ((x+xs)<0) posDst[j]=idxmax-(BYTE)((j*128)/d);
+				posDst[j]+=rand()/grainx2-granularity;
+			}
+			posDst+=bytes;
+		}
+		break;
+//----------------------------------------------------
+	case 6: //SHS_SOFTBUMP
+		for(i = 0; i < sYSize; i++) {
+			h=(255*i/sYSize)-127;
+			for(j = 0; j < sXSize; j++) {
+				k=(255*(sXSize-j)/sXSize)-127;
+				k=(h*(h*h)/128)/128+(k*(k*k)/128)/128;
+				k=k*(128-granularity)/128+128;
+				if (k<idxmin) k=idxmin;
+				if (k>idxmax) k=idxmax;
+				posDst[j]=(BYTE)k;
+				posDst[j]+=rand()/grainx2-granularity;
+			}
+			posDst+=bytes;
+		}
+		break;
+//----------------------------------------------------
+	case 5: // SHS_VBUMP
+		for(j = 0; j < sXSize; j++) {
+			k=(255*(sXSize-j)/sXSize)-127;
+			k=(k*(k*k)/128)/128;
+			k=(k*(128-granularity))/128+128;
+			for(i = 0; i < sYSize; i++) {
+				posDst[j+i*bytes]=(BYTE)k;
+				posDst[j+i*bytes]+=rand()/grainx2-granularity;
+			}
+		}
+		break;
+//----------------------------------------------------
+	case 4: //SHS_HBUMP
+		for(i = 0; i < sYSize; i++) {
+			k=(255*i/sYSize)-127;
+			k=(k*(k*k)/128)/128;
+			k=(k*(128-granularity))/128+128;
+			for(j = 0; j < sXSize; j++) {
+				posDst[j]=(BYTE)k;
+				posDst[j]+=rand()/grainx2-granularity;
+			}
+			posDst+=bytes;
+		}
+		break;
+//----------------------------------------------------
+	case 1:	//SHS_DIAGSHADE
+		a=(idxmax-idxmin)/2;
+		for(i = 0; i < sYSize; i++) {
+			for(j = 0; j < sXSize; j++) {
+				posDst[j]=(BYTE)(idxmin+a*i/sYSize+a*(sXSize-j)/sXSize);
+				posDst[j]+=rand()/grainx2-granularity;
+			}
+			posDst+=bytes;
+		}
+		break;
+//----------------------------------------------------
+	case 2:	//SHS_HSHADE
+		a=idxmax-idxmin;
+		for(i = 0; i < sYSize; i++) {
+			k=a*i/sYSize+idxmin;
+			for(j = 0; j < sXSize; j++) {
+				posDst[j]=(BYTE)k;
+				posDst[j]+=rand()/grainx2-granularity;
+			}
+			posDst+=bytes;
+		}
+		break;
+//----------------------------------------------------
+	case 3:	//SHS_VSHADE:
+		a=idxmax-idxmin;
+		for(j = 0; j < sXSize; j++) {
+			k=a*(sXSize-j)/sXSize+idxmin;
+			for(i = 0; i < sYSize; i++) {
+				posDst[j+i*bytes]=(BYTE)k;
+				posDst[j+i*bytes]+=rand()/grainx2-granularity;
+			}
+		}
+		break;
+//----------------------------------------------------
+	default:	//SHS_NOISE
+		for(i = 0; i < sYSize; i++) {
+			for(j = 0; j < sXSize; j++) {
+				posDst[j]=128+rand()/grainx2-granularity;
+			}
+			posDst+=bytes;
+		}
+	}
+//----------------------------------------------------
+	m_dDisabled.Clone(&m_dNormal);	//build the other bitmaps
+	m_dOver.Clone(&m_dNormal);
+	m_dOver.BlendPalette(hicr,highlight);
+	m_dDown.Clone(&m_dOver);
+} // End of SetShade
+
+DWORD CShadeButtonST::OnDrawBackground(CDC *pDC, CRect* pRect)
+{
+	if (m_bMouseOnButton)
+	{
+		if (m_bIsPressed)
+			m_dOver.Draw(pDC->GetSafeHdc(),1,1);
+		else
+			m_dOver.Draw(pDC->GetSafeHdc(),0,0);
+	}
+	else
+		m_dNormal.Draw(pDC->GetSafeHdc(),0,0);
+
+	return BTNST_OK;
+} // End of OnDrawBackground
+
+DWORD CShadeButtonST::OnDrawBorder(CDC* pDC, CRect* pRect)
+{
+	BASE_BTNST_CLASS::OnDrawBorder(pDC, pRect);
+
+	return BTNST_OK;
+} // End of OnDrawBorder

+ 77 - 0
Source/OGCAssistTool/OGCAssistTool/ShadeButtonST.h

@@ -0,0 +1,77 @@
+//
+//	Class:		CShadeButtonST
+//
+//	Compiler:	Visual C++
+//				eMbedded Visual C++
+//	Tested on:	Visual C++ 6.0
+//				Windows CE 3.0
+//
+//	Created:	14/June/2001
+//	Updated:	25/November/2002
+//
+//	Author:		Davide Calabro'		davide_calabro@yahoo.com
+//									http://www.softechsoftware.it
+//
+//	Disclaimer
+//	----------
+//	THIS SOFTWARE AND THE ACCOMPANYING FILES ARE DISTRIBUTED "AS IS" AND WITHOUT
+//	ANY WARRANTIES WHETHER EXPRESSED OR IMPLIED. NO REPONSIBILITIES FOR POSSIBLE
+//	DAMAGES OR EVEN FUNCTIONALITY CAN BE TAKEN. THE USER MUST ASSUME THE ENTIRE
+//	RISK OF USING THIS SOFTWARE.
+//
+//	Terms of use
+//	------------
+//	THIS SOFTWARE IS FREE FOR PERSONAL USE OR FREEWARE APPLICATIONS.
+//	IF YOU USE THIS SOFTWARE IN COMMERCIAL OR SHAREWARE APPLICATIONS YOU
+//	ARE GENTLY ASKED TO DONATE 5$ (FIVE U.S. DOLLARS) TO THE AUTHOR:
+//
+//		Davide Calabro'
+//		P.O. Box 65
+//		21019 Somma Lombardo (VA)
+//		Italy
+//
+#ifndef _SHADEBUTTONST_H_
+#define _SHADEBUTTONST_H_
+
+#ifdef _WIN32_WCE
+#define	BASE_BTNST_CLASS	CCeButtonST
+#define	INC_BTNST			"CeBtnST.h"
+#else
+#define	BASE_BTNST_CLASS	CButtonST
+#define	INC_BTNST			"BtnST.h"
+#endif
+
+#include INC_BTNST
+#include "CeXDib.h"
+
+#if _MSC_VER > 1000
+#pragma once
+#endif // _MSC_VER > 1000
+
+class CShadeButtonST : public BASE_BTNST_CLASS
+{
+public:
+	CShadeButtonST();
+	virtual ~CShadeButtonST();
+
+	enum	{	SHS_NOISE = 0,
+				SHS_DIAGSHADE,
+				SHS_HSHADE,
+				SHS_VSHADE,
+				SHS_HBUMP,
+				SHS_VBUMP,
+				SHS_SOFTBUMP,
+				SHS_HARDBUMP,
+				SHS_METAL	};
+
+	void SetShade(UINT shadeID=0,BYTE granularity=8,BYTE highlight=10,BYTE coloring=0,COLORREF color=0);
+
+private:
+	CCeXDib m_dNormal,m_dDown,m_dDisabled,m_dOver,m_dh,m_dv;
+
+protected:
+	virtual DWORD OnDrawBorder(CDC* pDC, CRect* pRect);
+	virtual DWORD OnDrawBackground(CDC* pDC, CRect* pRect);
+};
+
+#endif

+ 102 - 0
Source/OGCAssistTool/OGCAssistTool/WinXPButtonST.cpp

@@ -0,0 +1,102 @@
+#include "stdafx.h"
+#include "WinXPButtonST.h"
+
+#ifdef _DEBUG
+#undef THIS_FILE
+static char THIS_FILE[]=__FILE__;
+#define new DEBUG_NEW
+#endif
+
+CWinXPButtonST::CWinXPButtonST()
+{
+	// No rounded borders
+	m_bIsRounded = FALSE;
+}
+
+CWinXPButtonST::~CWinXPButtonST()
+{
+}
+
+// This function is called every time the button border needs to be painted.
+// This is a virtual function that can be rewritten in CButtonST-derived classes
+// to produce a whole range of buttons not available by default.
+//
+// Parameters:
+//		[IN]	pDC
+//				Pointer to a CDC object that indicates the device context.
+//		[IN]	pRect
+//				Pointer to a CRect object that indicates the bounds of the
+//				area to be painted.
+//
+// Return value:
+//		BTNST_OK
+//			Function executed successfully.
+//
+DWORD CWinXPButtonST::OnDrawBorder(CDC* pDC, CRect* pRect)
+{
+	return BTNST_OK;
+} // End of OnDrawBorder
+
+// This function is called every time the button background needs to be painted.
+// If the button is in transparent mode this function will NOT be called.
+// This is a virtual function that can be rewritten in CButtonST-derived classes
+// to produce a whole range of buttons not available by default.
+//
+// Parameters:
+//		[IN]	pDC
+//				Pointer to a CDC object that indicates the device context.
+//		[IN]	pRect
+//				Pointer to a CRect object that indicates the bounds of the
+//				area to be painted.
+//
+// Return value:
+//		BTNST_OK
+//			Function executed successfully.
+//
+DWORD CWinXPButtonST::OnDrawBackground(CDC* pDC, CRect* pRect)
+{
+	if (!m_bMouseOnButton && !m_bIsPressed)
+		return BASE_BUTTONST::OnDrawBackground(pDC, pRect);
+
+	// Create and select a solid brush for button background
+	CBrush brushBK(m_crColors[BTNST_COLOR_BK_IN]);
+	CBrush* pOldBrush = pDC->SelectObject(&brushBK);
+
+	// Create and select a thick black pen for button border
+	CPen penBorder;
+	penBorder.CreatePen(PS_SOLID, 1, RGB(0, 0, 0));
+	CPen* pOldPen = pDC->SelectObject(&penBorder);
+
+	if (m_bIsRounded)
+		pDC->RoundRect(pRect, CPoint(8, 8));
+	else
+		pDC->Rectangle(pRect);
+
+	// Put back the old objects
+	pDC->SelectObject(pOldBrush);
+	pDC->SelectObject(pOldPen);
+
+	return BTNST_OK;
+} // End of OnDrawBackground
+
+// This function enables or disables the rounded border for the button.
+//
+// Parameters:
+//		[IN]	bRounded
+//				If TRUE the button will have a round border.
+//		[IN]	bRepaint
+//				If TRUE the button will be repainted.
+//
+// Return value:
+//		BTNST_OK
+//			Function executed successfully.
+//
+DWORD CWinXPButtonST::SetRounded(BOOL bRounded, BOOL bRepaint)
+{
+	m_bIsRounded = bRounded;
+	if (bRepaint)	Invalidate();
+
+	return BTNST_OK;
+} // End of SetRounded
+
+#undef	BASE_BUTTONST

+ 63 - 0
Source/OGCAssistTool/OGCAssistTool/WinXPButtonST.h

@@ -0,0 +1,63 @@
+//
+//	Class:		CWinXPButtonST
+//
+//	Compiler:	Visual C++
+//				eMbedded Visual C++
+//	Tested on:	Visual C++ 6.0
+//				Windows CE 3.0
+//
+//	Created:	03/September/2001
+//	Updated:	25/November/2002
+//
+//	Author:		Davide Calabro'		davide_calabro@yahoo.com
+//
+//	Disclaimer
+//	----------
+//	THIS SOFTWARE AND THE ACCOMPANYING FILES ARE DISTRIBUTED "AS IS" AND WITHOUT
+//	ANY WARRANTIES WHETHER EXPRESSED OR IMPLIED. NO REPONSIBILITIES FOR POSSIBLE
+//	DAMAGES OR EVEN FUNCTIONALITY CAN BE TAKEN. THE USER MUST ASSUME THE ENTIRE
+//	RISK OF USING THIS SOFTWARE.
+//
+//	Terms of use
+//	------------
+//	THIS SOFTWARE IS FREE FOR PERSONAL USE OR FREEWARE APPLICATIONS.
+//	IF YOU USE THIS SOFTWARE IN COMMERCIAL OR SHAREWARE APPLICATIONS YOU
+//	ARE GENTLY ASKED TO DONATE 5$ (FIVE U.S. DOLLARS) TO THE AUTHOR:
+//
+//		Davide Calabro'
+//		P.O. Box 65
+//		21019 Somma Lombardo (VA)
+//		Italy
+//
+#ifndef _WINXPBUTTONST_H_
+#define _WINXPBUTTONST_H_
+
+#if _MSC_VER > 1000
+#pragma once
+#endif // _MSC_VER > 1000
+
+#ifdef UNDER_CE
+#include "CeBtnST.h"
+#define	BASE_BUTTONST	CCeButtonST
+#else
+#include "BtnST.h"
+#define	BASE_BUTTONST	CButtonST
+#endif
+
+class CWinXPButtonST : public BASE_BUTTONST
+{
+public:
+	CWinXPButtonST();
+	virtual ~CWinXPButtonST();
+
+	DWORD SetRounded(BOOL bRounded, BOOL bRepaint = TRUE);
+
+protected:
+	virtual DWORD OnDrawBackground(CDC* pDC, CRect* pRect);
+	virtual DWORD OnDrawBorder(CDC* pDC, CRect* pRect);
+
+private:
+	BOOL	m_bIsRounded;		// Borders must be rounded?
+};
+
+#endif