• Left(int nCount)
    • 왼쪽기준으로 문자열 추출
  • Mid(int nFirst) const
  • Mid(int nFirst, int nCount)
    • nFirst 추출을 시작할 문자열 위치
    • nCount 추출할 문자의 갯수
  • Right(int nCount) const
    • nCount 오른쪽 기준 추출할 문자의 수

 

 

대소문자 변경

CString strFileNameParse = _T("abcd");

strFileNameParse.MakeUpper();//ABCD
strFileNameParse.MakeLower();//abcd

 

 

오류해결 1)

  • stdafx.h에서 afxdao.h부분을 주석처리해준다.
//#ifndef _AFX_NO_DAO_SUPPORT
//#include <afxdao.h> //MFC DAO database classes
//#endif // !_AFX_NO_DAO_SUPPORT

오류해결 2)

  • 재정의된 부분의 이름을 모두 변경한다.
    • ADOCONNECT.h에서 msado15.dll import에서 no_namespace rename("redefinition명","adoredefinition") rename.........
# import "C:\Program Files (x86)\Common Files\System\ADO\msado15dll" no_namespace rename("EOF", "adoEOF") rename("DataTypeEnum", "adoDataTypeEnum") rename("FieldAttributeEnum", "adoFieldAttributeEnum") rename("ParameterDirectionEnum", "adoParameterDirectionEnum")  rename("RecordStatusEnum", "adoRecordStatusEnum") rename("EditModeEnum", "adoEditModeEnum") rename("LockTypeEnum", "adoLockTypeEnum") 
  • mdb 관련 정보 읽는 로직
void CTXTTEST00Dlg::OnBnClickedButton3()
{
	 
	//CADOConnect file;

	//file.OpenMDB(L"D:\\검수\\20201105mdb대소문자변경");
	CDaoDatabase* database = NULL;
	CDaoTableDef* tableDef = NULL;

	TCHAR mdb[256] = _T("D:\\검수\\20201105mdb대소문자변경\\Camera.mdb");

	TRY
	{
		//db 오픈
		database = new CDaoDatabase;
	database->Open(mdb);
	

	{
		//테이블 개수 확인
		int tableCnt = database->GetTableDefCount();

		CString strTableCnt;
		strTableCnt.Format(_T("테이블 개수 : %d"), tableCnt);
		//AfxMessageBox(strTableCnt);


		//전체 테이블 목록보기
		CString tableNames;
		for (int i = 0; i < tableCnt; i++)
		{
			//테이블 정보 가져오기
			CDaoTableDefInfo tableDefInfo;
			database->GetTableDefInfo(i, tableDefInfo, AFX_DAO_ALL_INFO);	//첫번째 테이블
			//CDaoQueryDefInfo quryinfo;
			//database->GetQueryDefInfo(i, quryinfo, AFX_DAO_PRIMARY_INFO);
			if (tableDefInfo.m_lAttributes & dbSystemObject)	//시스템 테이블인 경우
				tableNames += _T("시스템 테이블 : ");
			else
				tableNames += _T("사용자 테이블 : ");

			tableNames += tableDefInfo.m_strName;	//테이블 이름
			tableNames += _T("\n");
		}
		AfxMessageBox(tableNames);
	}
	



	//테이블 정보 보기
	{
		tableDef = new CDaoTableDef(database);
		tableDef->Open(_T("file1"));	//album이라는 테이블

		CString info = _T("");

		//테이블 이름
		info += tableDef->GetName();
		info += _T("\n");

		//테이블 생성일
		COleDateTime oleCTime = tableDef->GetDateCreated();
		CString createTime;
		createTime.Format(_T("생성일: %04d-%02d-%02d\n"), oleCTime.GetYear(), oleCTime.GetMonth(), oleCTime.GetDay());
		info += createTime;

		//테이블 마지막 수정일
		COleDateTime oleUTime = tableDef->GetDateLastUpdated();
		CString lastUpdatedTime;
		lastUpdatedTime.Format(_T("수정일: %04d-%02d-%02d\n"), oleUTime.GetYear(), oleUTime.GetMonth(), oleUTime.GetDay());
		info += lastUpdatedTime;

		//테이블 레코드 수
		CString recordCnt;
		recordCnt.Format(_T("레코드수: %ld\n"), tableDef->GetRecordCount());
		info += recordCnt;

		//테이블 필드 출력
		info += _T("필드정보\n");
		CDaoFieldInfo fieldInfo;
		int fieldCnt = tableDef->GetFieldCount();
		for (int i = 0; i < fieldCnt; i++)
		{
			tableDef->GetFieldInfo(i, fieldInfo, AFX_DAO_ALL_INFO);
			info += _T("\t");
			info += fieldInfo.m_strName;		//필드 이름
			info += _T(" : ");
			short nType = fieldInfo.m_nType;	//필드 타입
			switch (nType)
			{
			case dbBoolean: info += _T("BOOLEAN");	break;
			case dbByte: info += _T("BYTE");		break;
			case dbInteger: info += _T("INTEGER");	break;
			case dbLong: info += _T("LONG");		break;
			case dbSingle: info += _T("SINGLE");		break;
			case dbCurrency: info += _T("CURRENCY");	break;
			case dbDate: info += _T("DATE");		break;
			case dbDouble: info += _T("DOUBLE");		break;
			case dbText: info += _T("TEXT");		break;
			case dbLongBinary: info += _T("LONGBINARY");	break;
			case dbMemo: info += _T("MEMO");		break;
			}
			info += _T("\n");
		}

		//인덱스 필드 찾기
		info += _T("인덱스 필드\n");
		CDaoIndexInfo indexInfo;
		int indexCnt = tableDef->GetIndexCount();
		for (int i = 0; i < indexCnt; i++)
		{
			tableDef->GetIndexInfo(i, indexInfo);
			for (int j = 0; j < indexInfo.m_nFields; j++)
			{
				CString indexField = indexInfo.m_pFieldInfos[j].m_strName;
				info += _T("\t");
				info += indexField;
				info += _T("\n");
			}
		}

		AfxMessageBox(info);
	}


	//쿼리 실행
	{
		CDaoRecordset rs(database);
		rs.Open(AFX_DAO_USE_DEFAULT_TYPE, _T("select count(*) as cnt from file1"));	//쿼리 실행

		COleVariant var;
		rs.GetFieldValue(_T("cnt"), var);	//쿼리 값 획득
		rs.Close();

		CString value = convertString(var);
		AfxMessageBox(value);
	}

	//바인딩 쿼리 실행 : select
	{
		//바인딩 형식의 쿼리 저장
		CDaoQueryDef qd(database);
		/* qd.Create()의 첫번째 인수의 문자로 쿼리가 저장되며 qd.Append()로 저장이 완료됨.
		(영구저장되는 위치가 레지스트리 같긴한데 잘 모르겠습니다.)
		한번쓰는 임시 쿼리인 경우 NULL을 준후 qd.Append()를 안해주면 됩니다.*/
		qd.Create(NULL, _T("PARAMETERS [binding 1] INT; select * from file1 where 1 = [binding 1]"));
		//qd.Append();	//영구적인 쿼리 저장

		//바인딩
		COleVariant binding1((short)1);
		qd.SetParamValue(_T("[binding 1]"), binding1);

		//쿼리 실행
		CDaoRecordset rs(database);
		rs.Open(&qd);

		CString rst;
		int tempcntz = 0;
		while (!rs.IsEOF())
		{
			tempcntz++;
			if (tempcntz > 20000)
			{
				string zztemp = "123";
			}
			int cnt = rs.GetFieldCount();
			COleVariant var;
			for (int i = 0; i < cnt; i++)
			{
				rs.GetFieldValue(i, var);
				rst += convertString(var);
				rst += _T(", ");
			}
			rst += _T("\n");
			rs.MoveNext();	//scroll
		
		}
		AfxMessageBox(rst);

		qd.Close();
		//qd.m_pDAOQueryDef->Close();
	}
	}
		CATCH(CException, e) //예외처리 : 정확히는 CDaoException이지만 어짜피 CException 상속 클래스임.
	{
		TCHAR szCause[256];
		e->GetErrorMessage(szCause, 256);
		AfxMessageBox(szCause, MB_ICONERROR);
	}
	END_CATCH

		if (tableDef != NULL)
		{
			if (tableDef->IsOpen()) tableDef->Close();
			delete tableDef;
			tableDef = NULL;
		}
	if (database != NULL)
	{
		if (database->IsOpen()) database->Close();
		delete database;
		database = NULL;
	}


}

 

  • 중간에 mdb에서 가져온 COlecVariant를 CString으로 바꿔주는 함수
//COleVariant를 CString으로 변환해줄 함수
CString convertString(COleVariant& var)
{
	CString value;
	switch (var.vt)	//COleVariant를 CString으로 변경
	{
	case VT_EMPTY:
	case VT_NULL: value = _T("NULL");										break;
	case VT_I2: value.Format(_T("%hd"), V_I2(&var));						break;
	case VT_I4: value.Format(_T("%d"), V_I4(&var));						break;
	case VT_R4: value.Format(_T("%e"), (double)V_R4(&var));				break;
	case VT_R8: value.Format(_T("%e"), V_R8(&var));						break;
	case VT_CY: value = COleCurrency(var).Format();						break;
	case VT_DATE: value = COleDateTime(var).Format(_T("%m %d %y"));			break;
	case VT_BSTR: value = V_BSTRT(&var);									break;
	case VT_DISPATCH: value = _T("VT_DISPATCH");								break;
	case VT_ERROR: value = _T("VT_ERROR");									break;
	case VT_BOOL: V_BOOL(&var) ? value = _T("TRUE") : value = _T("FALSE");		break;
	case VT_VARIANT: value = _T("VT_VARIANT");									break;
	case VT_UNKNOWN: value = _T("VT_UNKNOWN");									break;
	case VT_I1: value = _T("VT_I1");										break;
	case VT_UI1: value.Format(_T("0x%02hX"), (unsigned short)V_UI1(&var));	break;
	case VT_UI2: value = _T("VT_UI2");										break;
	case VT_UI4: value = _T("VT_UI4");										break;
	case VT_I8: value = _T("VT_I8");										break;
	case VT_UI8: value = _T("VT_UI8");										break;
	case VT_INT: value = _T("VT_INT");										break;
	case VT_UINT: value = _T("VT_UINT");									break;
	case VT_VOID: value = _T("VT_VOID");									break;
	case VT_HRESULT: value = _T("VT_HRESULT");									break;
	case VT_PTR: value = _T("VT_PTR");										break;
	case VT_SAFEARRAY: value = _T("VT_SAFEARRAY");								break;
	case VT_CARRAY: value = _T("VT_CARRAY");									break;
	case VT_USERDEFINED: value = _T("VT_USERDEFINED");								break;
	case VT_LPSTR: value = _T("VT_LPSTR");									break;
	case VT_LPWSTR: value = _T("VT_LPWSTR");									break;
	case VT_FILETIME: value = _T("VT_FILETIME");								break;
	case VT_BLOB: value = _T("VT_BLOB");									break;
	case VT_STREAM: value = _T("VT_STREAM");									break;
	case VT_STORAGE: value = _T("VT_STORAGE");									break;
	case VT_STREAMED_OBJECT: value = _T("VT_STREAMED_OBJECT");							break;
	case VT_STORED_OBJECT: value = _T("VT_STORED_OBJECT");							break;
	case VT_BLOB_OBJECT: value = _T("VT_BLOB_OBJECT");								break;
	case VT_CF: value = _T("VT_CF");										break;
	case VT_CLSID: value = _T("VT_CLSID");									break;
	}
	WORD vt = var.vt;
	if (vt & VT_ARRAY)
	{
		vt = vt & ~VT_ARRAY;
		value = _T("Array of ");
	}
	if (vt & VT_BYREF)
	{
		vt = vt & ~VT_BYREF;
		value += _T("Pointer to ");
	}
	if (vt != var.vt)
	{
		switch (vt)
		{
		case VT_EMPTY: value += _T("VT_EMPTY");				break;
		case VT_NULL: value += _T("VT_NULL");				break;
		case VT_I2: value += _T("VT_I2");					break;
		case VT_I4: value += _T("VT_I4");					break;
		case VT_R4: value += _T("VT_R4");					break;
		case VT_R8: value += _T("VT_R8");					break;
		case VT_CY: value += _T("VT_CY");					break;
		case VT_DATE: value += _T("VT_DATE");				break;
		case VT_BSTR: value += _T("VT_BSTR");				break;
		case VT_DISPATCH: value += _T("VT_DISPATCH");			break;
		case VT_ERROR: value += _T("VT_ERROR");				break;
		case VT_BOOL: value += _T("VT_BOOL");				break;
		case VT_VARIANT: value += _T("VT_VARIANT");			break;
		case VT_UNKNOWN: value += _T("VT_UNKNOWN");			break;
		case VT_I1: value += _T("VT_I1");					break;
		case VT_UI1: value += _T("VT_UI1");				break;
		case VT_UI2: value += _T("VT_UI2");				break;
		case VT_UI4: value += _T("VT_UI4");				break;
		case VT_I8: value += _T("VT_I8");					break;
		case VT_UI8: value += _T("VT_UI8");				break;
		case VT_INT: value += _T("VT_INT");				break;
		case VT_UINT: value += _T("VT_UINT");				break;
		case VT_VOID: value += _T("VT_VOID");				break;
		case VT_HRESULT: value += _T("VT_HRESULT");			break;
		case VT_PTR: value += _T("VT_PTR");				break;
		case VT_SAFEARRAY: value += _T("VT_SAFEARRAY");			break;
		case VT_CARRAY: value += _T("VT_CARRAY");				break;
		case VT_USERDEFINED: value += _T("VT_USERDEFINED");		break;
		case VT_LPSTR: value += _T("VT_LPSTR");				break;
		case VT_LPWSTR: value += _T("VT_LPWSTR");				break;
		case VT_FILETIME: value += _T("VT_FILETIME");			break;
		case VT_BLOB: value += _T("VT_BLOB");				break;
		case VT_STREAM: value += _T("VT_STREAM");				break;
		case VT_STORAGE: value += _T("VT_STORAGE");			break;
		case VT_STREAMED_OBJECT: value += _T("VT_STREAMED_OBJECT");	break;
		case VT_STORED_OBJECT: value += _T("VT_STORED_OBJECT");		break;
		case VT_BLOB_OBJECT: value += _T("VT_BLOB_OBJECT");		break;
		case VT_CF: value += _T("VT_CF");					break;
		case VT_CLSID: value += _T("VT_CLSID");				break;
		}
	}
	return value;
}

MFC 기반의 MS SQL을 ADO OLE DB와 연결 중

#import "C:\PROGRAM FILES\COMMON FILES\SYSTEM\ADO\MSADO15.DLL" \
no_namespace rename("EOF", "EndOfFile")
[오류]
Cannot open
 include file: 'c:\project\debug\MSADO15.tlh'

 

해당 dll을 import가 안되는 오류 발생 

[해결방법]

  1. C/C++ -> 일반 -> 다중 프로세스 컴파일 YES(/MP)로 수정

2. C/C++ ->코드 일반화 -> 최소 리빌딩 (NO/GM-) 수정

3.#import "C:\PROGRAM FILES\COMMON FILES\SYSTEM\ADO\MSADO15.DLL" \
no_namespace rename("EOF", "EndOfFile") 를 atdafx.h의 전처리 맨 마지막에 설정한다. 

이유 : 너무 먼저 선언해버리면 window.h 와 같은 전처리기와 충돌발생

 

 

해당 dll 을 import 하면 _ConnectionPtr, _RecordsetPtr, _CommandPtr 3개의 타입을 사용 가능.

 

 

Visual Studio는 Compile시 multi-processor compilation을 지원한다.
processor는 각각 파일 하나씩을 담당하여 compile을 진행한다.
따라서 core가 많을수록 compile속도는 증가한다.

multi-processor compilation 옵션을 켰을 때
compile속도가 50초에서 6초로 줄어 들었다.

Project 의Property Pages에서
Configuration Properties
    -> C/C++
        ->General
            맨 밑의 Multi-processor Compilation을 YES로 변경

만약 Minimal Rebuild가 켜져 있을 경우 /MP가 무시되므로 아래와 같이 변경해준다.
Configuration Properties
    -> C/C++
        ->Code Generation
            Enable Minimal Rebuild를 No로 변경

 

 

 

 

List 초기 값 셋팅

CRect rt;
	m_DbfFileListCtrl.GetWindowRect(&rt);
	m_DbfFileListCtrl.SetExtendedStyle(LVS_EX_GRIDLINES | LVS_EX_FULLROWSELECT);
	m_DbfFileListCtrl.InsertColumn(0, TEXT("순번"), LVCFMT_LEFT, rt.Width() *0.05);
	m_DbfFileListCtrl.InsertColumn(1, TEXT("파일이름"), LVCFMT_CENTER, rt.Width() *0.3);
	m_DbfFileListCtrl.InsertColumn(2, TEXT("파일갯수"), LVCFMT_CENTER, rt.Width() *0.3);
	m_DbfFileListCtrl.InsertColumn(3, TEXT("완료여부"), LVCFMT_CENTER, rt.Width() *0.3);

List 값 셋팅

	while (!ListQue.empty())
	{
		
		Listnum = m_DbfFileListCtrl.GetItemCount();
		
		CString strr;
		strr.Format(_T("%d"), Listnum);
		CString tempStrList;
		tempStrList.Format(_T("%d"), ListQue.front().second);
		
		m_DbfFileListCtrl.InsertItem(Listnum, strr); //숫자,dbf파일이름
		m_DbfFileListCtrl.SetItem(Listnum, 1, LVIF_TEXT, ListQue.front().first, NULL, NULL, NULL, NULL);
		//int -> CString
	 
		tempStrList.Format(_T("%d"), ListQue.front().second);
		m_DbfFileListCtrl.SetItem(Listnum, 2, LVIF_TEXT, tempStrList, NULL, NULL, NULL, NULL);


		ListQue.pop();
	}

ListControl 초기화 및 형식지정

m_ctrlLIST1.DeleteAllItems();


LVS_EX_FULLROWSELECT // 아이템을 선택할 때 줄 한줄 전체 반전효과 준다.
LVS_EX_GRIDLINES //각 아이템에 경계선을 그려준다.
LVS_EX_CHECKBOXES //각 아이템을 Check box를 표시해준다.
LVS_EX_HEADERDRAGDROP //컴럼 헤더를 드래그 함으로써 컬럼의 순서를  바꾼다.
listen.SetExtenedStyle(LVS_EX_GRIDLINES | LVS_EX_FULLROWSELECT)

1. ANCII(American Standard Code for Information Interchange,아스키)

  • ASCII는 최초의 문자열 인코딩.
  • 7bit로 구성 영어를 위한 문자, 숫자, 특수문자, 기호 등 128개 문자를 표현
  • 영어만을 위해 만들어졌고, 일본어, 중국어 등 다른 언어는 표현 불가
  • 이후 다른 언어를 지원해야 할 필요가 생겨 ANSI가 생겨남.

2. ANSI(American National Standard Institue, 안시)

  • ANSI는 8bit로 구성되어 있으며 256개의 문자를 표현 가능.
  • ANSI는 ASCII의 확장판으로 이해하면 된다.
  • ASCII에서 1bit를 더 사용한 것
  • ANSI의 앞 7bit는 ASCII와 동일, 뒤에 1bit를 이용하여 다른 언어의 문자를 표현
  • 단, 새롭게 추가 된 128개 문자로는 모든 언어 표현 불가.
    • 그래서 CodePage를 부여 각 언어별로 Code값을 주고, Code마다 다른 문자열 표를 의미 하도록 약속
      • ANSI = ANCII(7bit) + CodePage(1bit)

3. EUC-KR(Exteded Unix Code-Korea)

  • EUC-KR 은 한글 지원을 위해 유닉스 계열에서 나온 완성형 코드 조합.
  • 완성형 코드란, 완성 된 문자 하나하나마다 코드 번호를 부여한 것
  • 조합형 코드란, 한글의 자음과 모음 각각에 코드 번호를 부여한 후, 초성, 중성, 종성을 조합하여 하나의 문자를 나타내는 방식.
  • EUC-KR은 ANSI를 한국에서 확장한 것으로 외국에서는 지원불가.

4. CP949(Code Page 949)

  • CP949는 한글 지원을 위해 windows 계열에서 나온 확정 완성형 코드 조합이다.
  • EUC-KR은 2byte의 완성형 코드로 2bytes 내에서는 표현할 수 이쓴 완성된 문자의 수가 한계가 있었다.
  • EUC-KR 개선하여 확장하여 만든 코드이며 949는 한국을 의미한다. 932=일본, 936=중국

5. UTF-8(Universal Coded Character Set + Transformation Format -8-bit)

  • UTF-8은 유니코드를 위한 가변 길이 문자 인코딩(멀티바이트) 방식 중 하나로, ANSI의 단점을 보완하기 위해 만들어졌다.
  • ANSI는 다국어를 지원하기 위해 CodePage 정보를 미리 알고 있어야한다.
  • 멀티바이트 개념을 사용하여 하나의 Character Set에 거의 모든 문자를 넣었다.
  • ANSI는 고정바이트(1byte) 형태로 최대 256자 까지만 표현이 가능하나 UTF-8은 멀티바이트(1~4bytes)로 최대 1,112,064까지 표현가능
  • 첫 128자는 ASCII 코드 값으로 ANSI와 UTF-8이 동일. 그래서 영어로 사용할 경우 1bytes만 사용한다.
  • 2bytes를 사용하며, 중동지역 언어 또는 많은 유럽언어가 여기에 속한다. 한국,중국,일본 등 동아시아권 언어는 3byte 이상을 사용한다. 
  • UTF-8은 매우 일반적인 인코딩 방식이지만, 3bytes 이상의 문자를 사용할 경우에는 비효율적!
  • UTF-8 유니코드는 아스키 코드와 영문 영역에서는 100% 호환 만약, UTF-8 유니코드 문서에 한글 등이 전혀 없고 영문과 숫자로 이루어져 있다면 그 카드는 아스키코드와 동일 전 세계의 모든 언어를 하나의 파일에 쓸 수 있다

6. UTF-16(Universal Coded Character Set + Transformation Format -16-bit)

  • UTF-16은 16bit 기반으로 저장하는 UTF-8의 변형
  • 한글의 경우 UTF-8로 저장할 경우 3bytes가 필요한데, UTF-16으로 저장하면 2bytes면 되어 용량의 이점이 있음
  • 그러나 경우에 따라서는 2bytes이상을 사용할 경우가 있음
  • 엔디안 처리를 고려함에 따라 복잡성 증대나 ANSI호환이 안되는 단점

7. UTF-32 (Universal Coded Character Set + Transformation Format -32-bit)

  • UTF-32 는 모든 문자를 4bytes로 인코딩한다. 문자 변환 알고리즘이나 가변길이 인코딩 방식에 대한 고민을 하고 싶지 않을 때 사용함 
  • 매우 비효율적인 메모리 사용하므로 자주사용하지 않는다.

* UTF-8, UTF-16 모두 유니코드를 지원하기 위한 인코딩 방식이다. 이들을 이해하기 위해서는 유니코드에 대한 이해가 필요하다. 일반적으로 UTF-8과 유니코드를 동일하게 생각하는데 약간 차이가 있다.

 

8. UNICODE 

  • UNICODE는 전 세계의 모든 문자를 컴퓨터에서 일관되게 표현할 수 있도록 고안된 코드 조합.
  • 주의해야 할 것이 '인코딩'이 아니라는 것. 유니코드는 전세계 거의 모든 문자를 2bytes 숫자로 1:1 매핑 시키는 '방식'을 말하고, 유니코드를 표현하는 여러가지 '인코딩' 방식들이 존재함.
  • 유니코드를 표현하는 여러가지 '인코딩' 방식들이 존재하는 것이다.UTF-8, UTF-16등이 그 인코딩 중 하나인 것
  • 유니코드_목록을 통해 매핑 테이블을 확인 가능 (유니코드_목록, 한글_목록)
    • 여기서 '가'를 찾아보면 유니코드 값이 'AC00'인 것을 알 수 있는데 16진수 AC00은 10진수로 44,032인데 8bit로 나누기에 너무 크다. 이 값을 8bit 단위로 쪼개어 저장하는 방법이 UTF-8이다.(쪼개는 방법 여기)
    • window 비스타 이상에서는 유니코드를 utf-16으로 인코딩한다.
    • 유니코드 값을 바로 사용하지 않고 UTF-8을 이용하여 사용하다보니 UTF-8=UNICODE 라 생각하기 쉬운데 그게 아니다. 

 

 

1) 모든 .cpp, .h 창을 끈다.

 

2) 모두 접는다.

3) 다시 확장한다.  끝.

+ Recent posts