MFC 중 CDatabase 를 이용하여 Excel 파일을 컨트롤 할 수 있는 기능이 있다.

 


 

CDatabase  database;

CString  sDriver = _T("MICROSOFT EXCEL DRIVER (*.XLS)");
CString  sExcelFile = "xls 파일 전체 경로";

CString  sSql;
CString  strError;

 

 

 

sSql.Format(_T("DRIVER={%s};DSN='';FIRSTROWHASNAMES=1;READONLY=FALSE;CREATE_DB=\"%s\";DBQ=%s"), sDriver, sExcelFile, sExcelFile);
if(database.OpenEx(sSql, CDatabase::noOdbcDialog))
{
 
 sSql.Format(_T("SELECT * FROM [%s$A1:IV65536]"), "Address");

 


 

 

위와 같은 방법으로 xls 파일을 읽어 엑셀 데이터를 사용 할 수 있는데 2017년 10월 중순쯤부터 갑자기 오류가 나기 시작한다.

 

-5016

FIRSTROWHASNAMES\

잘못된 연결 문자열 특성입니다

 

 

뭐 위와 같은 내용의 에러 메시지가 보이게 된다.

 

 

구글링을 해보니 msexcl40.dll 파일이 업데이트 되면서부터 발생한 문제로 보인다.

 

문제가 발생하는 msexcl40.dll 의 버전은 4.0.9801.1 버전이고 크기는 345,088 byte 이다.

 

가장 좋은 방법은 KB4041681 업데이트를 제거 하는 방법이 있다.

 

하지만 최근 Windows 10 RS3 로 업데이트 하였다면 KB4041681 업데이트가 보이지 않는다.

 

이럴때는 msexcl40.dll 파일을 문제가 발생하지 않는 4.0.9801.0 버전으로 변경을 해주어야 하는데

 

이 파일은 특별한 권한이 있지 않는 이상 덮어쓰기가 되지 않는다.

 

msexcl40.dll 4.0.9801.0 버전 파일을 구하여 접근 가능한 경로에 파일을 복사 해둔다.

 

그리고 나서 레지스트티 편집기 (regedit.exe) 를 실행한다.

 

\HKEY_LOCAL_MACHINE\SOFTWARE\WOW6432Node\Microsoft\Jet\4.0\Engines\Excel

 

위 경로로 이동한 다음 Win32 라는 키의 값을 보면

 

C:\Windows\SysWOW64\msexcl40.dll

 

이렇게 되어 있는데 이 앞쪽 경로를 msexcl40.dll 4.0.9801.0 버전 파일이 있는 경로로 변경해준다.

 

예를 들어 D 드라이브의 Driver 라는 경로에 msexcl40.dll 이 존재 한다면

 

d:\driver\msexcl40.dll

 

위와 같이 변경해 주면 된다.




혹여 파일이 필요하신 분들은 아래 파일을 사용.


msexcl40.dll  - 4.0.9801.0


msexcl40.zip


파일에 의심이 되시는 분들은c:\windows 에서 msexcl40.dll 을 검색해보시면 


여러 파일들이 검색이 되는데 이 중 크기가 다른 파일 또는 날짜가 다른 파일이 검색이 된다면 해당 파일의 속성을 클릭하여 버전 확인 후 


4.0.9801.0 버전 파일을 복사하여 사용하면 된다.



 

https://support.microsoft.com/ko-kr/help/4042007/description-of-the-security-update-for-the-microsoft-jet-database-engi

 

 

https://social.technet.microsoft.com/Forums/en-US/55b1d633-b715-491e-917e-b7cb01ae0523/error-in-windows-update-kb4041681-unexpected-error-from-external-database-driver-1?forum=sqldataaccess

 

 





만약 프로그램의 소스를 수정 할수 있는 상황 이라면 다음과 같이 코드를 수정 하면 작동 한다.



 

CDatabase  database;

//CString  sDriver = _T("MICROSOFT EXCEL DRIVER (*.XLS)");

CString  sDriver = _T("Microsoft Excel Driver (*.xls, *.xlsx, *.xlsm, *.xlsb)");

CString  sExcelFile = "xls 파일 전체 경로";

CString  sSql;
CString  strError;

 

 

 

sSql.Format(_T("DRIVER={%s};DSN='';FIRSTROWHASNAMES=1;READONLY=FALSE;CREATE_DB=\"%s\";DBQ=%s"), sDriver, sExcelFile, sExcelFile);
if(database.OpenEx(sSql, CDatabase::noOdbcDialog))
{
 
 //sSql.Format(_T("SELECT * FROM [%s$A1:IV65536]"), "Address");

 sSql.Format(_T("SELECT * FROM [%s$]"), "Address");





http://www.codeproject.com/KB/miscctrl/#Charting+Controls

 

http://www.codeproject.com/Articles/317712/An-MFC-Chart-Control-with-Enhanced-User-Interface

 

http://www.codeproject.com/Articles/1546/Plot-Graphic-Library

 

http://www.codeproject.com/Articles/3214/D-Graph-ActiveX-Control




USES_CONVERSION 는 Wide Char 형태를 Ansi 형태로.. 혹은 그 반대로 바꾸는 것을 간편하게 해주는 매크로를 제공한다.


A2CW : (LPCSTR) ==> (LPCWSTR)
A2W : (LPCSTR) ==> (LPWSTR)
W2CA : (LPCWSTR) ==> (LPCSTR)
W2A : (LPCWSTR) ==> (LPSTR)


T2COLE : (LPCTSTR) ==> (LPCOLESTR)
T2OLE : (LPCTSTR) ==> (LPOLESTR)
OLE2CT : (LPCOLESTR) ==> (LPCTSTR)
OLE2T : (LPCOLESTR) ==> (LPCSTR)


<사용예>

	CString strTrackData;
	unsigned char* trackData;
	int size, decUnicode;

	// unsigned char* 형을 CString 변수에 저장
	strTrackData.Format(_T("%s"), m_hCommHistory->GetTrackData());
	size = strTrackData.GetLength();

	// unsigned char* 형을 WCHAR* 변수에 저장

	WCHAR* w_trackData = T2W((LPCSTR)m_hCommHistory->GetTrackData());
	for(int i = 0; i < size; i++) 
	{
		// 유니코드값을 얻어와서 한글 범위 체크
		decUnicode = static_cast(w_trackData[i]);
		if(decUnicode >= 44032 && decUnicode <= 55203) 
		{
			// 한글은 '?'로 대체
			w_trackData[i] = '?';
		}
	}

	// !! 간단한 매크로도 있다
	#define ishan(ch) (((ch) & 0xE0) > 0x90) 

// CString Char

char* StringToChar(CString str)

{

        char *szStr = NULL;

#if defined(UNICODE) || defined(_UNICODE)

        int nLen = str.GetLength() + 1;

        TCHAR *tszTemp = NULL;

        tszTemp = new TCHAR[nLen];

        memset(tszTemp, 0x00, nLen*sizeof(TCHAR));

        _tcscpy(tszTemp, str);

        // Get size (실제사용되는바이트사이즈)

        int nSize = WideCharToMultiByte(CP_ACP, 0, tszTemp, -1, NULL, NULL, NULL, NULL);

        szStr = new char[nSize];

        memset(szStr, 0x00, nSize);

        WideCharToMultiByte(CP_ACP, 0, tszTemp, -1, szStr, nSize, NULL, NULL);

        if(tszTemp)

        {

               delete [] tszTemp;

               tszTemp = NULL;

        }

#else

        int nLen = str.GetLength() + 1;

        szStr = new char[nLen];

        memset(szStr, 0x00, nLen);

        strcpy(szStr, str);

#endif

        return szStr;

}

 

// CString TCHAR

TCHAR* StringToTCHAR(CString str)

{

        TCHAR *tszStr = NULL;

        int nLen = str.GetLength() + 1;

        tszStr = new TCHAR[nLen];

        memset(tszStr, 0x00, nLen*sizeof(TCHAR));

        _tcscpy(tszStr, str);

 

        return tszStr;

}

 

// Char CString

CString CharToString(char *str)

{

        CString cStr;

#if defined(UNICODE) || defined(_UNICODE)

        int nLen = strlen(str) + 1;

        TCHAR *tszTemp = NULL;

        tszTemp = new TCHAR[nLen];

        memset(tszTemp, 0x00, nLen*sizeof(TCHAR));

        MultiByteToWideChar(CP_ACP, 0, str, -1, tszTemp, nLen*sizeof(TCHAR));

        cStr.Format(_T("%s"), tszTemp);

        if(tszTemp)

        {

               delete [] tszTemp;

               tszTemp = NULL;

        }

#else

        cStr.Format("%s", str);

#endif

        return cStr;

}

 

// Char TCHAR

TCHAR* CharToTCHAR(char *str)

{

        TCHAR *tszStr = NULL;

#if defined(UNICODE) || defined(_UNICODE)

        int nLen = strlen(str) + 1;

        tszStr = new TCHAR[nLen];

        memset(tszStr, 0x00, nLen*sizeof(TCHAR));

        MultiByteToWideChar(CP_ACP, 0, str, -1, tszStr, nLen*sizeof(TCHAR));

#else

        int nLen = strlen(str) + 1;

        tszStr = new TCHAR[nLen];

        memset(tszStr, 0x00, nLen*sizeof(TCHAR));

        _tcscpy(tszStr, str);

#endif

        return tszStr;

}

 

// TCHAR CString

CString TCHARToString(TCHAR *str)

{

        CString cStr;

        cStr.Format(_T("%s"), str);

        return cStr;

}

 

// TCHAR Char

char* TCHARToChar(TCHAR *str)

{

        char *szStr = NULL;

#if defined(UNICODE) || defined(_UNICODE)

        int nSize = WideCharToMultiByte(CP_ACP, 0, str, -1, NULL, NULL, NULL, NULL);

        szStr = new char[nSize];

        memset(szStr, 0x00, nSize);

        WideCharToMultiByte(CP_ACP, 0, str, -1, szStr, nSize, NULL, NULL);

#else

        int nLen = strlen(str) + 1;

        szStr = new char[nLen];

        memset(szStr, 0x00, nLen);

        strcpy(szStr, str);

#endif

        return szStr;

}


<출처> http://www.devpia.com/MAEUL/Contents/Detail.aspx?BoardID=51&MAEULNO=20&no=8562&page=1


MFC 프로그래밍을 하다 보면 컨트롤을 상속받아 새롭게 재정의 하는 경우가 많다.

예를 들어 CTreeCtrl 을 상속 받는 CTestTreeCtrl 을 만든다고 한다면

class CTestTreeCtrl : public CTreeCtrl
{

}

이런 구조가 만들어진다.

문제는 NM_CLICK, TVN_ENDLABELEDIT 이런 통지 메시지들을 재정의 할때 원하지 않는

결과가 나오는 경우가 있다.

즉, 해당 클래스에서만 NM_CLICK 이 발생을 하고 해당 컨트롤의 부모윈도우에게는 NM_CLICK 이 발생하지 않는 현상이 나타나는것이다.

CTestTreeCtrl Class 에 NM_CLICK 를 재정의 하는 메서드를 만든다면 다음과 같이 될것이다.


protected:
//{{AFX_MSG(CTestTreeCtrl ) 
afx_msg void OnClick(NMHDR* pNMHDR, LRESULT* pResult);
//}}AFX_MSG BEGIN_MESSAGE_MAP(CTestTreeCtrl , CTreeCtrl)

//{{AFX_MSG_MAP(CTestTreeCtrl ) 
ON_NOTIFY_REFLECT(NM_CLICK, OnClick)
//}}AFX_MSG_MAPEND_MESSAGE_MAP();

void CTestTreeCtrl ::OnClick(NMHDR* pNMHDR, LRESULT* pResult) {*pResult = 0;}

여기서 주의 깊게 봐야 하는 것이 바로

ON_NOTIFY_REFLECT(NM_CLICK, OnClick)

위 매크로다

MS 의 기술문서(KR600769) 에 보면 (http://support.microsoft.com/kb/600769/k)

ON_NOTIFY_REFLECT 는 부모 윈도우에 통지를 하지 않고 해당 클래스에서만

처리 하게끔 한다고 명시하고 있다.

부모 윈도우에까지 통지를 하고 싶다면 다음과 같이 변경 하면된다

ON_NOTIFY_REFLECT -> ON_NOTIFY_REFLECT_EX

afx_msg void OnClick(NMHDR* pNMHDR, LRESULT* pResult);
-> afx_msg BOOL OnClick(NMHDR* pNMHDR, LRESULT* pResult);

이렇게 반환 type 을 BOOL 로 변경하면 된다.

해당 메서드의

return 값이 FALSE 이면 부모에게 통지를 하고 TRUE 이면 부모에게 통지를 하지 않는다.
  1. shiningsoul 2012.10.09 09:09

    찾았던 내용이내요 덕분에 막혔던 부분이 잘 해결 되었내요
    감사합니다.


http://whoim.tistory.com/entry/INI-섹션정보-얻기-GetPrivateProfileSectionNames

처음에는 이분 블로그에서 해당 소스를 보고 사용하였었다..

며칠후에 해당 소스를 보다가.. 문자열이 \0 로 구분되는것에 착안

좀 더 최적화를 해보았다.

기존 코드
	char    szBuf[1024] = {0x00,};   
	char    szSect[512] = {0x00,};   
	DWORD	nCnt = ::GetPrivateProfileSectionNames(szBuf, 1024, strPath);   
	int     nPos = 0;  
	BOOL    bMakedSect = FALSE; // 하나의 섹션을 구성완료하면 TRUE하여 pos를 0으로 초기화
	for(int i=0; i < (int)nCnt; i++, nPos++)   
	{   
		if(szBuf[i] != '\0'){
			if(bMakedSect) nPos = 0;   
			memcpy(szSect + nPos, szBuf+i, 1);   
			bMakedSect = FALSE;   
			continue;   
		}   
		else{   
			szSect[i] = '\0';

			nTemp = m_cbApplication.AddString(szSect);
			
			if( strcmp(m_strSection, szSect) == 0)
			{
				nIdx = nTemp;
			}

			memset(szSect, 0x00, sizeof(szSect));
			bMakedSect = TRUE;   
		}

		nTemp = m_cbApplication.AddString(szSect);

		if( strcmp(m_strSection, szSect) == 0)
		{
			nIdx = nTemp;
		}		
	}






나름대로 최적화 코드

	char    szBuf[1024] = {0x00,};   
	char    szSect[512] = {0x00,};   
	DWORD	nCnt = ::GetPrivateProfileSectionNames(szBuf, 1024, strPath);   
	int     nPos = 0;   
	

	// 2010.08.13 Section 정보 최적화
	for(int i=0; i < (int)nCnt; nPos++)
	{
		strcpy(szSect , szBuf + i);
		i += strlen(szSect) + 1;

		nTemp = m_cbApplication.AddString(szSect);

		if( strcmp(m_strSection, szSect) == 0)
		{
			nIdx = nTemp;
		}
	}


  1. 장석태 2010.12.31 15:32

    오호 최적화 괜춘하네요 님 ㅋㅋ

  2. Seo 2013.05.15 13:29

    char *p = szBuf;
    while(nCnt > 0){
    nPos = strlen(szBuf) + 1;
    p += nPos;
    nCnt -= nPos;
    std::cout << "Session Name = " << p << std::endl
    }

    이게 더 빠르겠네요 ^^ 참고 하다가 한번 남겨 놓습니다.

  3. 2018.03.08 10:14

    비밀댓글입니다

    • BlogIcon Acidpop acidpop 2018.03.08 10:49 신고

      안녕하세요
      char 로 선언한 szSect 를

      TCHAR szSect 형태로 선언을 해주시고

      strcpy, strlen, strcmp 를

      _tcscpy, _tcslen, _tcscmp 로 변경 해서 사용하시면 됩니다.

      이런 복잡한 과정이 싫으시다면

      AddString을 AddStringA 로 변경해보세요.

      상세한 내용은 char, TCHAR 차이를 공부 하시면 좋을것 같습니다.

  4. NPC 2019.09.09 09:20

    나름데로(X) 나름대로(O)


CListCtrl 을 사용중 안에 내용을 저장 하기 위해 후딱 만들어 봤다...

아직 충분한 테스트가 안되어 있기에 버그가 있을수 있으니 사용에 주의 바람..



ListCtrlEx.h

class CListCtrlEx : public CListCtrl
{
// Construction
public:
	CListCtrlEx();

// Attributes
public:

// Operations
public:

// Overrides
	// ClassWizard generated virtual function overrides
	//{{AFX_VIRTUAL(CListCtrlEx)
	//}}AFX_VIRTUAL

// Implementation
public:
	typedef enum
	{
		TEXT_MODE,
		BINARY_MODE
	}FILE_MODE;
	BOOL LoadData(CString strFileName, FILE_MODE nMode = BINARY_MODE);
	BOOL SaveData(CString strFileName, FILE_MODE nMode = BINARY_MODE);
	virtual ~CListCtrlEx();

	// Generated message map functions
protected:
	//{{AFX_MSG(CListCtrlEx)
		// NOTE - the ClassWizard will add and remove member functions here.
	//}}AFX_MSG

	DECLARE_MESSAGE_MAP()

private:
	CString strFileKey;			// Data 의 유효성을 검사하기 위한 키 값
};





ListCtrlEx.cpp

CListCtrlEx::CListCtrlEx()
{
	// GUID Generator Tool 을 이용해 값을 만들었다

 	strFileKey = "12345678_90AB_CDEF_GHIJ_KLMNOPQRSTUX";
}

CListCtrlEx::~CListCtrlEx()
{
}


BEGIN_MESSAGE_MAP(CListCtrlEx, CListCtrl)
	//{{AFX_MSG_MAP(CListCtrlEx)
		// NOTE - the ClassWizard will add and remove mapping macros here.
	//}}AFX_MSG_MAP
END_MESSAGE_MAP()

/////////////////////////////////////////////////////////////////////////////
// CListCtrlEx message handlers



BOOL CListCtrlEx::SaveData(CString strFileName, FILE_MODE nMode)
{
	int nRow = 0, nCol = 0;
	CString strTemp = "";
	CFile file;

	TCHAR pszPathName[_MAX_PATH];
	
	::GetModuleFileName(::AfxGetInstanceHandle(), pszPathName, _MAX_PATH);

	PathRemoveFileSpec(pszPathName);

	CString strFullPath;

	strFullPath.Format("%s\\%s", pszPathName, strFileName);

	if(nMode == TEXT_MODE)
	{
		if(!file.Open(strFullPath, CFile::modeCreate | CFile::modeWrite))
		{
			return FALSE;
		}
		
	}
	else if(nMode == BINARY_MODE)
	{
		if(!file.Open(strFullPath, CFile::modeCreate |
				CFile::modeWrite | CFile::typeBinary))
		{
			return FALSE;
		}
	}

	CArchive	ar(&file, CArchive::store);

	ar << strFileKey;

	// Item 개수
	nRow = GetItemCount();
	// Column  개수
	nCol = GetColumns();
	
	ar << nRow;
	ar << nCol;

	for(int i=0; i < nRow; i++)
	{
		for(int j=0; j < nCol; j++)
		{
			strTemp = GetItemText(i, j);
			ar << strTemp;
		}
	}

	ar.Close();
	file.Close();

	return TRUE;
}

BOOL CListCtrlEx::LoadData(CString strFileName, FILE_MODE nMode)
{
	int nRow = 0, nCol = 0;
	int nIdx = 0;
	CString strTemp = "";
	CFile file;

	TCHAR pszPathName[_MAX_PATH];
	
	::GetModuleFileName(::AfxGetInstanceHandle(), pszPathName, _MAX_PATH);

	PathRemoveFileSpec(pszPathName);

	CString strFullPath;

	strFullPath.Format("%s\\%s", pszPathName, strFileName);
	
	if(nMode == TEXT_MODE)
	{
		if(!file.Open(strFullPath, CFile::modeRead))
		{
			return FALSE;
		}
		
	}
	else if(nMode == BINARY_MODE)
	{
		if(!file.Open(strFullPath, CFile::modeRead | CFile::typeBinary))
		{
			return FALSE;
		}
	}
	
	CArchive	ar(&file, CArchive::load);

	ar >> strTemp;

	if(strTemp != strFileKey)
	{
		ar.Close();
		file.Close();
		return FALSE;
	}
	
	ar >> nRow;
	ar >> nCol;

	if(nRow <= 0 || nCol <= 0)
	{
		ar.Close();
		file.Close();

		return FALSE;
	}

	if(nCol > GetColumns())
	{
		ar.Close();
		file.Close();

		return FALSE;
	}

	for(int i=0; i < nRow; i++)
	{
		ar >> strTemp;
		nIdx = InsertItem(i, strTemp);
		for(int j=1; j < nCol; j++)
		{
			ar >> strTemp;
			SetItemText(nIdx, j, strTemp);
		}
	}
	
	ar.Close();
	file.Close();

	return TRUE;
}




CImageList

CImageList create flags

설 명

ILC_COLOR

디폴트 색상이 적용되는데 포통 ILC_COLOR4가 적용된다

ILC_COLOR4

4비트(16색상)

ILC_COLOR8

8비트(256색상)

ILC_COLOR16

16비트

ILC_COLOR24

24비트

ILC_COLOR32

32비트

ILC_COLORDDB

장치 종속적인 비트맵

ILC_MASK

투명 이미지를 출력하기 위해 마스크를 사용한다

CImageList draw flags

설 명

ILD_BLEND25, ILD_FOCUS

시스템 하이라이트 색상을 25% 섞어서 출력한다. 마스크가 지정되어 있지 않으면 사용할 수 없다. 탐색기에서 파일을 드래그할 때 파일의 아이콘이 평상시보다 훨씬 더 밝아지는 것을 볼 수 있는데 이 방법으로 그린것이다

ILD_BLEND50, ILD_SELECTED, ILD_BLEND

시스템 하이라이트 색상을 50% 섞어서 출력한다

ILD_MASK

마스크를 출력한다

ILD_NORMAL

배경 색상으로 이미지를 출력한다. 배경색상이 CLR_NONE이면 이미지는 마스크를 사용하여 투명하게 그려진다

ILD_TRANSPARENT

마스크를 사용하여 투명한 이미지를 그린다. 마스크가 정의되어 있지 않으면 이 값은 사용할 수 없다

CImageList Operations

설 명

Add

이미지나 이미지들을 이미지 리스트에 추가한다

Attach

이미지 리스트 오브젝트를 이미지 리스트에 Attach시킨다

Detach

이미지 리스트 오브젝트를 이미지 리스트에서 Detach 시킨다

DeleteImageList

이미지 리스트를 지운다

Draw

드레그 & 드롭 중에도 이미지 리스트를 출력한다

Remove

이미지 리스트에서 이미지를 삭제한다

Read

파일에서 이미지 리스트를 읽어온다

Write

파일에 이미지 리스트를 쓴다

ImageList는 동일한 크기를 가진 이미지의 집합으로, 각각의 이미지를 배열항목처럼 취급하여 0 부터 시작하는 인덱스로 참조할수 있도록 만든것.

 

//ImageList를 생성만 하는 함수.

BOOL Create( int cx, int cy, UINT nFlags, int nInitial, int nGrow );

//1,2파라미터 : 이미지의 폭과 넓이

//3 파라미터 : 이미지 리스트의 타입 지정.주로 색상수를 나타냄. ILC_COLOR4일때 4비트(16색상)

//4 파라미터 : 초기에 포함할 이미지의 개수

//5 파라미터 : 새로운 이미지를 추가하기 위해 이미지리스트의 메모리를 재할당할때 얼마만큼의 여분의 메모리를 할당할것인가를 나타냄. 4 = 이미지 4개를 추가할 만큼 할당.

 

//ImageList를 생성함과 동시에 비트맵 이미지로 초기화까지 하는 함수.

BOOL Create( UINT nBitmapID, int cx, int nGrow, COLORREF crMask );

//1 파라미터 : 비트맵소스의 리소스 ID

//2 파라미터 : 이미지의 폭(y값 자동 지정)

//3 파라미터 : 새로운 이미지를 추가하기 위해 이미지리스트의 메모리를 재할당할때 얼마만큼의 여분의 메모리를 할당할것인가를 나타냄. 4 = 이미지 4개를 추가할 만큼 할당.

//4 파라미터 : 투명색으로 사용할 색상 지정.

 

 

예제)

CImageList m_il1, m_il2;

m_il1.Create(32, 32, ILC_COLOR4, 2, 1);

m_il2.Create(IDB_BITMAP1, 48, 1, RGB(255,255,255));

 

 

//이미지 추가

 

//Icon 추가

int Add( HICON hIcon );

//hIcon: 아이콘 리소스를 가리키는 핸들값, CWinApp::LoadIcon()의 리턴값을 사용하면 됨.

 

//Bitmap 추가

int Add( CBitmap* pbmImage, COLORREF crMask );

// 1 파라미터 : 비트맵 리소스를 담고 있는 CBitmap 객체의 주소

// 2 파라미터 : 투명색 지정.

 

예제)

//Icon추가

m_il1.Add(AfxGetApp()->LoadIcon(IDI_ICON1));

m_il1.Add(AfxGetApp()->LoadIcon(IDI_ICON2));

 

//Bitmap추가

CBitmap bitmap;

bitmap.LoadBitmap(IDB_BITMAP1);

m_il2.Add(&bitmap, RGB(255,255,255));

 

 

//화면 출력

CImageList::Draw(), CImageList::DrawIndirect(), CImageList::DrawEx()를 사용.

DrawEx는 MFC 7.0 이상에서만 가능.

 

BOOL Draw( CDC* pdc, int nImage, POINT pt, UINT nStyle );

//1 파라미터 : 출력할 대상을 나타내는 Device Context

//2 파라미터 : 출력할 이미지의 인덱스

//3 파라미터 : 출력 좌표

//4 파라미터 : 그리기 스타일을 지정하는 값으로

nStyle

Flag specifying the drawing style. It can be one or more of these values:

Value Meaning
ILD_BLEND25, ILD_FOCUS 시스템 하이라이트(Highlight) 색상을 25% 섞어서 출력.
ILD_BLEND50, ILD_SELECTED, ILD_BLEND 시스템 하이라이트(Highlight) 색상을 50% 섞어서 출력.
ILD_MASK 마스크를 출력한다.
ILD_NORMAL 이미지의 배경색을 이용하여 출력하며, 배경색이 CLR_NONE으로 설정된 경우 마스크를 이용하여 이미지를 투명하게 출력.
ILD_TRANSPARENT 마스크를 이용하여 이미지를 투명하게 출력한다.

 

예제)

Void CExImageListView::OnDraw (CDC* pDC)

{

 m_il.SetBkColor (CLR_NONE); //배경색 설정 (CLR_NONE은 투명색)

 m_il.Draw (pDC, 0, CPoint(100, 200), ILD_NORMAL); //투명 출력

 m_il.Draw (pDC, 0, CPoint(150, 200), ILD_BLEND25);

 m_il.Draw (pDC, 0, CPoint(200, 200), ILD_BLEND50); //투명 출력

 m_il.Draw (pDC, 0, CPoint(250, 200), ILD_MASK);

}

 //리스트 컨트롤과 이미지 리스트 연결

 

CListCtrl::SetImageList

CImageList* SetImageList( CImageList* pImageList, int nImageList );

Return Value

A pointer to the previous image list.

Parameters

pImageList

Pointer to the image list to assign.

nImageList

Type of image list. It can be one of these values:

  • LVSIL_NORMAL   Image list with large icons.

  • LVSIL_SMALL   Image list with small icons.

  • LVSIL_STATE   Image list with state images.

예제)

m_ObjectList.SetImageList(m_largeImage, LVSIL_NORMAL);

 

이미지 리스트의 사용
-------------------------------------------------------------------------------------
보통 컨트롤에서는 이미지 리스트를 자동으로 연결해주는 SetImageList 와 같은 함수가 있다.
이와는 별도로 리스트 내부에서 원하는 아이콘을 뽑아다 사용할 경우는 다음 메서드를 이용한다.

HICON ExtractIcon(int nImage);

주의. ExtrancIcon을 이용하여 리턴된 HICON 핸들은 이미지 리스트의 내부 핸들의 포인터를
리턴하는것이 아니라, 복사한 핸들을 리턴하기 때문에.. 다 사용하고 나면 CloseHandle()을
이용하여 꼭 해재하여 주어야한다.

이 함수를 루프나 혹은 드로잉 함수에서 그 때 그때, 불러서 사용한다면 길지 않은 시간이
흐른 후 시스템의 리소스가 부족합니다 라는 메시지와 다운 되는 컴퓨터를 보게 될것이다.

[출처] CImageList Class|작성자 러브러브

+ Recent posts