Programming/MFC2009. 11. 8. 04:08
CString temp = "2,30,100,2"; // 자를 문자열 ( ", "의 갯수는 변할 수 있다.)
 CString strTok;   
 
 int sepCount = GetFindCharCount(temp, ',');   // " , " 의 갯수를 세어온다.
 
 CString* temp1 = new CString[sepCount+1]; // 구해온 갯수만큼 동적 배열을 할당(CString배열)
 
 int cnt=0;
 while(AfxExtractSubString(strTok, temp, cnt, ','))  // 문자를 잘라준다. (AfxExtractSubString = strTok)
  temp1[cnt++] = strTok;                                       // 해당 배열에 순차적으로 넣어준다.
 
 for(int i=0; i<sepCount+1; i++)
  cout << (LPCSTR)temp1[i] << endl;                  // 화면에 출력한다.

 delete[] temp1;


요렇게... 간단하게 예를 들자면,
CString str = "192.168.0.1";
CString strA, strB, strC, strD;
AfxExtractSubString(strA, str, 0, '.'); // strA == "192"
AfxExtractSubString(strB, str, 0, '.'); // strB == "168"
AfxExtractSubString(strC, str, 0, '.'); // strC == "0"
AfxExtractSubString(strD, str, 0, '.'); // strD == "1"



  =========================================================================================


안녕하세요...
 
CString의 멤버 함수에 보면 Find 함수와 GetAt 함수를 이용하시면 원하시는
기능을 구현하실 수 있습니다.
아래와 같이 예제를 작성해 보았습니다.
 
    CString data;
    char temp[20];
    char temp_data;
    int devide_count = 0, devide_index = 0;
    int str_length = 0;
 
    data = "abcd,123,efgh,456,ijk,";
    str_length = data.GetLength();
 
    for(int i = 0; i < str_length; i++){
        // 데이터에서 ',' 값을 찾아 위치 값을 얻는다.
        devide_index = data.Find(',', devide_index);

        // devide_index값이 -1이라면 데이터에 ','값이 존재하지 않는것이므로
        // 함수를 종료한다.
        if(devide_index == -1) return;

        // 찾았다면 devide_index 다음 인덱스부터 검색을 하기 위해 devide_index++하여준다.
        devide_index++;
        devide_count++;

        if(devide_count == 2){
            // devide_count 값이 2라면 내가 원하는 위치의 데이터를 찾은 것이므로
            // 데이터의 남은 길이만큼 for문을 돈다.
            for(i = 0; i < str_length - devide_index; i++){
                // 데이터를 얻어 temp_data 저장한다.
                temp_data = data.GetAt(devide_index+i);
                // temp_data값이 ','값이 temp_data를 temp[i]에 저장한다.
                if(temp_data != ',') temp[i] = temp_data;
                else {
                    temp[i] = 0;
                    MessageBox(temp);
                    return;
                }
            }  
        }
    }
Posted by skensita
Programming/MFC2009. 1. 31. 16:53

MFC

  1. m_vtFileName.clear();
    m_UserThumbnail.clear();
  2. // 파일 목록을 찾는다.
    CFileFind finder;
    CString strWildCard( m_strDirectory );
  3. strWildCard += "\\*.*";

  4. BOOL bWorking = finder.FindFile( strWildCard );
  5. while( bWorking )
    {
    bWorking = finder.FindNextFile();
  6.   if( finder.IsDots() || finder.IsDirectory() )
      continue;  
     else
     {
      CString filePath = finder.GetFileName();
      filePath.MakeLower();   //대문자 -> 소문자
  7.    //if( IsImageGDIPLUSValid( m_strDirectory + "\\" + filePath ) )  
      if( filePath.Find(".jpg") > 0)
       m_vtFileName.push_back( filePath );  
     }

    finder.Close();
  8.  

API

  1.  m_strThumbnailDir = dir;
    if( m_strThumbnailDir == "" )
    {
     //AfxMessageBox(_T("not define strpath!"));
     m_vtImageName->clear();
     return false;
    }
  2.  CString strExt;
    CString strName;
    CString strPattern;
  3.  BOOL bRC = TRUE;
  4.  HANDLE     hFind = NULL;
    WIN32_FIND_DATA   FindFileData;
    std::vector<CString> VectorImageNames;
  5.  if( m_strThumbnailDir[ m_strThumbnailDir.GetLength() - 1 ] == TCHAR('\\') )
     strPattern.Format( _T("%s*.*"), m_strThumbnailDir );
    else
     strPattern.Format( _T("%s\\*.*"), m_strThumbnailDir );
  6.  hFind = FindFirstFile(strPattern,&FindFileData);
    if(hFind == INVALID_HANDLE_VALUE)
    {
     LPVOID  msg;
     ::FormatMessage( FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM,
          NULL,
          GetLastError(),
          MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
          (LPTSTR)&msg,
          0,
          NULL);
     MessageBox((LPTSTR)msg, _T("fileload error"), MB_OK|MB_ICONSTOP);
     ::LocalFree(msg);
     return FALSE;
    }
    // filter off the system files and directories
    if (!(FindFileData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)  &&
     !(FindFileData.dwFileAttributes & FILE_ATTRIBUTE_SYSTEM)     &&
     !(FindFileData.dwFileAttributes & FILE_ATTRIBUTE_HIDDEN)     &&
     !(FindFileData.dwFileAttributes & FILE_ATTRIBUTE_TEMPORARY))
    {   
     // test file extension
     strName = FindFileData.cFileName;
     strExt = strName.Right(3);
  7.   if( FindType( strExt ) ){
  8.    // save the image file name
      VectorImageNames.push_back( strName );
     }
    }
  9.  // loop through to add all of them to our vector
    while (bRC)
    {
     bRC = ::FindNextFile(hFind, &FindFileData);
     if (bRC)
     {
      // filter off the system files and directories
      if (!(FindFileData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)  &&
       !(FindFileData.dwFileAttributes & FILE_ATTRIBUTE_SYSTEM)     &&
       !(FindFileData.dwFileAttributes & FILE_ATTRIBUTE_HIDDEN)     &&
       !(FindFileData.dwFileAttributes & FILE_ATTRIBUTE_TEMPORARY))
      {
       // test file extension
       strName = FindFileData.cFileName;
       strExt = strName.Right(3);
  10.     if(FindType(strExt)){
        // save the image file name
        VectorImageNames.push_back(strName);
       }
      }
     }
     else
     {
      DWORD err = ::GetLastError();
      if (err !=  ERROR_NO_MORE_FILES)
      {
       LPVOID msg;
       ::FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM,
        NULL, err,
        MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
        (LPTSTR)&msg, 0, NULL);
       MessageBox((LPTSTR)msg, _T("fileload error"), MB_OK|MB_ICONSTOP);
       ::LocalFree(msg);
       ::FindClose(hFind);
       return FALSE;
      }
     }
    } // end of while loop
  11.  // close the search handle
    ::FindClose(hFind);
  12.  // update the names, if any
    if ( !VectorImageNames.empty() )
    {
     // reset the image name vector
     m_vtImageName->clear();
     *m_vtImageName = VectorImageNames;
     return TRUE;
    }
    else
    {
     m_vtImageName->clear();
     return TRUE;
    }
  13.  return FALSE; 
Posted by skensita
Programming/MFC2009. 1. 31. 15:13



Visual Studio 6에서 만들어진 다이알로그 베이스 MFC 프로그램.



Visual Studio 2008에서 만들어진 다이알로그 베이스 MFC 프로그램.


보는것처럼 버튼의 모양이 다른것을 확인할 수 있다. 이외에 여러 컨트롤들이 다른 모양으로 표시 될 것입다.

Visual Studio 6에서 만들어진 프로그램에 저런 컨터트롤을 사용하기 위해서는 아래의 방법을 거치면

같은 모양의 컨트롤을 볼 수 있습니다.

----------------------------------------------------------------------------------------------

해당 첨부된 파일이름을 적당히 바꾸시고, 에디터로 열으셔서

이름 같은거 바꿔주시면 일단 시작입니다.

그리고, 해당 프로젝트의 적당한 경로, res 같은 곳으로 복사해주세요.

1. 해당 프로젝트를 엽니다.

2. 리소스 편집창으로 이동합니다.

3. 우측 마우스 메뉴의 인서트를 선택합니다.

4. 해당 다이알로그의 Import 버튼을 클릭합니다.

5. 파일 열기 창의 하단부 Open As을 오토에서 커스텀으로 변경합니다.

6. 복사한 메니페스트 파일을 선택합니다.

7. 리소스타입을 24라고 숫자로 입력합니다. 

8. 해당 리소스 편집창에 24 타입으로 대충 IDR_241 과 같은 형태로 추가되었을 것입니다.
    해당 리소스의 프로퍼티를 열으셔서 위의 아이디를 숫자 1로 바꿔줍니다.

9. 빌드를 다시 수행합니다.

10. XP에 테마가 있는 상태라면 원하시는 모양으로 바뀐 다얄로그를 보실 수 있을겁니다.



메니페스트라의내용은 강좌란이나 인터넷에서 검색해 보면 깔끔한 자료를 찾으실 수 있을겁니다.

Posted by skensita
Programming/MFC2009. 1. 12. 13:32

1. Introduction

MFC를 사용해서 트레이 기반으로 동작하는 다이알로그 베이스드의 프로그램을 개발해 본 사람이라면 누구나 한번쯤은 이런 생각을 해 보았을것이다. 이놈의 모달 왜 시작하기만 하면 나타나지? ShowWindow API를 사용해서 SW_HIDE를 몇 군데 넣어보아도 뾰족한 수가 없었을 것이다. 최대한 노력을 해 보았자, 화면에 나타났다 금새 사라지는게 전부다.

그럼 왜 이런 현상이 나타날까? 그건 MFC 내부적으로 DoModal안에서 다이알로그를 Show하게 만들기 때문이다. 그렇다면 방법은 없을까? 불행하게도 일반적인 ShowWindow를 사용한 방법은 없다. 이 문서에서는 문제를 해결하는 다른 방법을 제시하고 있다. 그럼 2장에서 좀 더 자세히 살펴보기로 하자.

2. HOWTO

이미 1장에서 ShowWindow를 통한 답이 없다고 밝혔다. 그렇다면 도대체 무엇을 사용해야 깔끔하게 다이알로그를 제어할 수 있을까? 그 답은 바로 WM_WINDOWPOSCHAINGING에 있다. 보기에도 상당히 긴 이름을 가진 메시지이다. 아마도 윈도우 위치가 변경될때 발생할 것 같은 느낌을 주지 않는가? 그렇게 생각했다면 정답이다.

MSDN에 따르면 WM_WINDOWPOSCHANGING 메시지는 윈도우의 사이즈, 포지션, 또는 Z-order 순서가 변경되는 경우 윈도우에 통보된다고 한다. 그렇다면 윈도우의 거의 모든 외부 변화에 이 메시지가 발생한다고 보면된다. 이 메시지에 대해서 좀 더 살펴보면 다음과 같다.

WM_WINDOWPOSCHANGING

    WPARAM wParam : 사용하지 않음;
    LPARAM lParam : WINDOWPOS 구조체 포인터

typedef struct {
    HWND hwnd;
    HWND hwndInsertAfter;
    int x;
    int y;
    int cx;
    int cy;
    UINT flags;
} WINDOWPOS;

위는 해당 메시지의 wParam과 lParam및 lParam에 사용되는 구조체의 설명을 나타낸 것이다. 오늘 우리의 문제를 해결하는데 가장 중요한 것은 이 WINDOWPOS 구조체다. 그 중에서도 flags라고 할 수 있다.

flags는 윈도우 포지션과 관련된 다양한 값들을 가질 수 있다고 한다. 일반적으로 아래와 같은 값들의 조합으로 구성된다.

  • SWP_DRAWFRAME - 프레임을 그린다.
  • SWP_FRAMECHANGED
  • SWP_HIDEWINDOW - 윈도우를 숨긴다.
  • SWP_NOACTIVATE - 윈도우를 활성화 시키지 않는다.
  • SWP_NOCOPYBITS - 클라이언트 영역과 관련된 모든 정보를 무시한다.
  • SWP_NOMOVE - 현재 위치를 유지한다. (x,y 파라미터를 무시한다.)
  • SWP_NOOWNERZORDER - 소유주 윈도우의 Z-order를 변경하지 않는다.
  • SWP_NOREDRAW - 윈도우를 새로 그리지 않는다. 어떠한 페인팅 관련 메시지도 포스트 되지 않는다.
  • SWP_NOREPOSITION - SW_NOOWNERZORDER 플래그와 같음
  • SWP_NOSENDCHANGING - 윈도우가 WM_WINDOWPOSCHANGING 메시지를 받는 것을 막는다.
  • SWP_NOSIZE - 사이즈를 변경하지 않는다. (cx, cy 파라미터를 무시한다.)
  • SWP_NOZORDER - Z-order를 변경하지 않는다.
  • SWP_SHOWWINDOW - 윈도우를 출력한다.
z-order
윈도우는 일반적으로 2차원 평면 모니터에 출력된다. 그래서 x,y축이 기본적으로 존재한다. 거기에 더해서 윈도우 시스템에서는 z-order라는 개념이 있다. 이것은 수학과 마찬가지로 x,y축 외에 z축을 기준으로 한 순서가 된다. 윈도우로 따지면 특정 윈도우 뒤에 무슨 윈도우가 있는지를 기술하는 것을 z-order라고 생각하면 된다.

여기서 특히나 중요한 것은 SWP_SHOWWINDOW다. 화면에 윈도우가 출력되려고 하면 분명 WM_WINDOWPOSCHANGING 메시지가 포스팅 될 것이다. 당연히 넘어온 WINDOWPOS 구조체의 flags 필드값에는 SWP_SHOWWINDOW가 설정되어 있을 것이다. 그렇다면 값을 살짝 제거해 버리면 어떻게 될까? 아마도 MFC의 다이알로그 베이스드 프로그램이라면 아래와 같은 코드가 될 것이다.

void CHidDlgDlg::OnWindowPosChanging(WINDOWPOS FAR* lpwndpos) 
{
    CDialog::OnWindowPosChanging(lpwndpos);
    
    // TODO: Add your message handler code here
    lpwndpos->flags &= ~SWP_SHOWWINDOW;
}

위와 같이 해두고 프로그램을 실행하면, 다이알로그가 화면에 출력되지 않을 것이다. 프로세스 목록에서 해당 프로그램을 종료시키자. 이것이 우리가 적용할 모달 다이알로그를 간단하게 숨기는 방법이다. 이것들을 합쳐서 좀 더 우아하게 사용하는 방법을 다음 장에서 살펴보도록 하자.

참고
기본적으로 다이알로그를 클래스 위저드로 열게 되면, 메시지 상자에 WM_WINDOWPOSCHANGING 메시지가 없다. 클래스 위저드의 마지막 탭에 위치한 클래스 인포로 가셔서 메시지 필터를 윈도우로 변경한후에 보면 WM_WINDOWPOSCHANGING 메시지가 추가되어 있는 것을 확인할 수 있다.

3. Codes

2장에서 살펴본 내용의 의하면 결국 우리는 기존의 ShowWindow행동을 무시하고 독자적인 행동을 해야 한다는 것을 알 수 있다. 쉽게 생각할 수 있는 방법으로 간단하게 멤버변수등을 하나 만들고 그 값에 따라서 WM_WINDOWPOSCHANGING 핸들러에서 SWP_SHOWWINDOW 플래그를 설정또는 제거해 주면 쉽게 될 것 이다. 하지만 이렇게 인터페이스를 분리시킬때에는 꼭 기존의 행동이랑 유사하게 내지는 기존의 행동을 통해서 변경시켜 주는 것이 좋다. 그렇게 해야 추후에 보더라도 헷갈리지 않기 때문이다.

이러한 작업을 가장 완벽하게 할 수 있는 곳은 아마도 ShowWindow일 것이다. CWnd의 ShowWindow를 재정의해서 사용하는 것이다. 하지만 이 경우 ShowWindow가 CWnd에 virtual함수로 선언되어져 있지 않기때문에 다이알로그를 CWnd포인터로 사용하는 경우에는 동작하지 않을 수 있다. 그렇게 되면 오류는 나지 않지만 결과가 이상하게 되므로 다른 사람이 쓰게 될 때 오해를 줄 수 있다. 따라서 ShowWindow를 오버라이드 하지 않고, 그와 비슷한 이름의 ShowWindowEx를 만들어 그놈을 사용하기로 하자. 아래는 간단하게 작성해본 샘플 코드다.

void CHidDlgDlg::OnWindowPosChanging(WINDOWPOS FAR* lpwndpos) 
{
    CDialog::OnWindowPosChanging(lpwndpos);
    
    // TODO: Add your message handler code here
    if(m_bShowFlag)
        lpwndpos->flags |= SWP_SHOWWINDOW;
    else
        lpwndpos->flags &= ~SWP_SHOWWINDOW;

}

BOOL CHidDlgDlg::ShowWindowEx(int nCmdShow)
{
    m_bShowFlag = (nCmdShow == SW_SHOW);
    return (GetSafeHwnd()) ? ShowWindow(nCmdShow) : TRUE;
}

m_bShowFlag는 BOOL형으로 선언된 멤버 변수다. 이제 다이알로그의 ShowWindowEx 함수를 DoModal전에 사용하면, DoModal이 실행되더라도 다이알로그가 화면에 표시되지 않을 것이다.

주의해서 보아야 할 점 중에 하나는 ShowWindowEx의 마지막 호출은 ShowWindow로 이루어진다는 점이다. 하지만 DoModal 이전에 다이알로그는 생성되지 않으므로 그 경우에 ShowWindow를 호출하면 오류가 난다. 왜냐하면 아직 만들어진 윈도우 핸들이 없기 때문이다. 따라서 이 경우는 ShowWindow를 호출하지 않고 그냥 리턴해야 한다는 점을 기억해야 한다.


Posted by skensita
Programming/MFC2008. 11. 14. 10:45
배포전에 Dependency를 이용 꼭 필요한 파일의 목록을 확인한다.(8버젼 부터는 안먹히기도 하나 그래도 꼭 확인한다)
VC에 있는 Dependency툴은 단일파일로 실행되고 한번만 실행해주면
윈도우 탐색기 컨텍스트 메뉴에 자동으로 View Dependencies를 추가해준다.

VC 6 이하(~ VS 6)
 MSVCRT, MFC42 등의 MFC버젼과 관련된 DLL과 추가로 사용한 DLL을 같이 배포한다.
 98이후부터는 운영체제에 포함되어 있다.
참고로 http://activex.microsoft.com/controls/vc/mfc42.cab로 관련 DLL을 다운받을 수 있으며
ActivX 배포시 inf파일에 추가해서 자동으로 설치되게 만들 수도 있다.

VC 7(VS 2003)
MSVCR71, MFC71
이 DLL은 최신 운영체제라고 해서 더는 기본 내장을 해 주지않기 때문에 응용 프로그램이 알아서 자기 디렉터리나 윈도우 시스템 디렉터리에다 구비해야 한다.

VC 8이후(VS 2005~)
side by side asembly라는 기술이 도입되어 windows 디렉토리에 밑에 WinSxS(Windows Side-by-Side) 폴더에 추가 작업을 해야한다.
Dependency를 사용해서 관련 DLL을 같이 배포해도 제대로 실행된다는 보장을 할 수 없다.
관련 DLL들은 C:\Program Files\Microsoft Visual Studio 8\VC\redist\x86\Microsoft.VC80.CRT(이하 2005기준)에서 얻을수 있으며
MFC를 안쓰고 release버전만 배포한다면 Microsoft.VC80.CRT.manifest, msvcp80.dll, msvcr80.dll만 배포해도 된다.
(msvcm80.dll은 매니지드C++용 crt라 native를 쓰는 경우는 배포하지 않아도 된다.)

배포방법으로는
1. 재배포 패키지를 이용한다. 링크에서 다운받아 설치해도 되며 다른 배포방법도 설명하고 있다.

설치 디렉토리에서 얻기
C:\Program Files\Microsoft Visual Studio 8\SDK\v2.0\BootStrapper\Packages\vcredist_x86

Microsoft Visual C++ 2005 SP1 재배포 가능 패키지(x86)
http://www.microsoft.com/downloads/details.aspx?familyid=200B2FD9-AE1A-4A14-984D-389C36F85647&displaylang=ko

Microsoft Visual C++ 2008 재배포 가능 패키지(x86)
http://www.microsoft.com/downloads/details.aspx?FamilyID=9b2da534-3e03-4391-8a4d-074b9f2bc1bf&DisplayLang=ko

2. 정적 라이브러리를 사용한다(포함) -> CRT(/MT), MFC, ATL 등
실행파일이 커지긴 하나 제일 간단하다. MFC 라이브러리를 사용시는 MFC라이브러리를 정적으로 포함하면 CRT도 자동으로 /MT로 변경된다. 고로 어디서든 기존보다 더 간단하다. 귀찮아서 ActiveX를 이렇게 배포한적있음 ㅡ.ㅡ;

용량은 기본 MFC 다이얼로그 프로젝트가 아무것도 추가안하고 52k정도에서 308k 정도로 커진다.


3. 인스톨쉴드(Install Shield), 설치 프로젝트를 이용한다.

4. .Net Framework를 설치한다.
managed 로 컴파일했다면 .Net Framework는 필수이다.

-> 추가! MFC,ATL을 사용안한 프로젝트에 한해서만 먹힙니다. 프레임웍만 깔면 WinSxS에 VC80.CRT관련만 설치되네요.

    VC90도 똑같습니다. 재배포 패키지를 설치하셔야 MFC,ATL관련이 깔립니다.

위 방법 외에도 몇가지가 더 있으며 재배포 패키지 링크에 연결된 설명들과 아래 링크들을 참조하기 바란다.
http://www.codeproject.com/cpp/vcredists_x86.asp(codeproject에 소개된 방법)
http://www.serious-code.net/moin.cgi/RedistributingVisualCppRunTimeLibrary

/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

재배포 패키지를 이용한 OCX(ActiveX) 배포 (2005 ~)
Cab 파일들어갈 파일 내용은 다음과 같다.
자신이 만든 ocx파일
inf 파일
재배포패키지

INF파일의 내용은 다음과 같다.

[Setup Hooks]
hook1=hook1

[hook1]
run=%EXTRACT_DIR%\vcredist_x86.exe

[version]
signature="$CHICAGO$
AdvancedINF=2.0

[Add.Code]
mytest.ocx=mytest.ocx
vcredist_x86.exe=vcredist_x86.exe

[vcredist_x86.exe]
file-win32-x86=thiscab
DestDir=11
RegisterServer=no

[mytest.ocx]
file-win32-x86=thiscab
DestDir=11
FileVersion=1,0,0,3
clsid={1DF754CB-D85F-490B-9011-BDCB0BFDC430} <= 이건 아시져?
RegisterServer=yes

inf파일의 [Add.Code]는 나열된 순서의 반대로 설치가 되는 점을 유의하며 위와같이 하면
vc2005 재배포 패키지가 실행된후 맨 마지막으로 ocx가 설치된다.


출처 - DEVPIA slipy1님이 쓰신글

Posted by skensita
Programming/MFC2008. 9. 8. 15:22

Visual C++ 완벽가이드 PPT
Posted by skensita
Programming/MFC2008. 9. 6. 16:31

Connection 객체

 
Connection 객체는 ODBC 데이타 소스와 연결할 때 사용한다.

 
프로퍼티 설명
Attributes 객체에 대한 하나이상의 특성을 나타낸다.
CommandTimeout 명령이 실행되는 최대 시간을 지정한다. 만약 시간이 경과되면 오류를 발행한다.
ConnectionString 데이타 소스와 연결할 때 사용하는 연결정보를 저장한다.
ConnectionTimeout 데이타 소스와 연결할 때 최대 대기 시간을 지정한다.
DefaultDatabase Connection 객체에 대한 기본 데이타베이스를 지정한다.
IsolationLevel Connection 객체에 대한 격리 레벨을 지정한다.
Mode Connection 객체에서 데이타의 변경에 대한 권한을 지정한다.
Provider Connection 객체의 Provider 이름을 나타낸다.
Version ADO의 버젼을 나타낸다.

메소드 설명
BeginTrans 새로운 트랜젝션을 시작한다.
CommitTrans 현재 트랜젝션에서 일어난 변경사항을 저장하고 트랙젝션을 닫는다.
그리고 새로운 트랜젝션을 다시 시작한다.
RollbackTrans 현재 트랜젝션에서 일어난 변경사항을 취소하고 트랙젝션을 닫는다.
그리고 새로운 트랜젝션을 다시 시작한다.
여기서 트랜젝션은 데이타베이스에 가하는 일련의 작업 집합을 말한다.
Open 데이타 소스에 연결한다.
Close 데이타 소스로의 연결을 종료한다.
Execute 지정된 쿼리, SQL 문장 또는 Stored Procedure를 실행한다.
 

 Error 객체

 
ADO의 명령수행중에 발생한 오류에 대한 정보를 담고 있다.

 
프로퍼티 설명
Number 오류 번호
Description 오류에 대한 설명
Source 오류를 발생시킨 객체의 이름을 나타낸다.
HelpFile 오류와 관련된 도움말 파일의 이름을 나타낸다.
HelpContext 오류와 관련된 도움말의 컨텍스트 ID를 나타낸다.
SQLStatus SQL 상태를 나타내는 길이가 5인 문자열을 리턴한다.
NativeError 데이타베이스에서 정의한 오류 번호를 리턴한다.
 

 Command 객체

 
Command 객체는 데이타 소스로 부터 실행할 명령을 정의한다.

 
프로퍼티 설명
ActiveConnection 데이타 소스에 연결된 Connection객체로 Command 객체는 이 연결객체를 통해서 명령을 실행한다.
CommandText 실행할 SQL 문장이나 테이블 이름, 또는 스토어드 프로시져
CommandTimeout 명령이 실행되는데 걸리는 최대 대기 시간을 나타낸다.
CommandType Command 객체의 종류를 지정한다.
Prepared 명령을 실행하기 전에 준비된 문장을 생성할 것인지를 지정한다.

메소드 설명
CreateParameter 새로운 파라메터 객체를 생성한다.
Execute CommandText에서 지정한 쿼리, SQL 문장, 또는 스토어드 프로시듀어를 실행한다.
 

 Parameter 객체

 
파라메터 객체는 파라메터를 가지는 쿼리나 스토어드 프로시듀어를 담고있는 커멘드 객체와 함께 사용된다.

 
프로퍼티 설명
Attributes 파라메터의 속성을 나타내며, adParamSigned, adParamNullable, adParamLong과 같은 값들을 혼합하여 지정할 수 있다.
Direction 파라메터가 입력 파라메터인지 출력 파라메터인지 등을 지정한다.
Name 파라메터 객체의 이름을 나타낸다.
NumericScale 숫자형 파라메터에서 소수점 뒷자리수를 결정한다.
Precision 숫자형 파라메터에서 최대 자리수를 결정한다.
Size 파라메터 값의 바이트 수 또는 문자열 수를 지정한다.
Type 파라메터 값의 데이터 형을 지정한다.
Value 파라메터의 값을 나타낸다.

메소드 설명
AppendChunk 긴 문자열이나 바이너리 타입의 파라메터 객체에 데이터를 추가한다.
 

 Recordset 객체

 
프로퍼티 설명
AbsolutePage 레코드의 절대 페이지를 나타낸다.
만약 여기에 새로운 값을 지정하면, 현재 레코드의 위치가 해당 페이지의 첫 레코드로 이동한다.
페이지란 순차적으로 일정 개수만큼 레코드들을 묶어놓은 단위이다.
페이지는 기본 값으로 10개의 레코드를 가진다.
AbsolutePosition 현재 레코드의 절대 위치를 나타낸다.
첫 레코드의 AbsolutePosition은 1이다.
ActiveConnection 현재 레코드셋이 연결된 Connection 객체를 나타낸다.
BOF, EOF BOF는 현재 레코드가 첫 레코드의 이전에 있는지를 나타낸다.
EOF는 현재 레코드가 마지막 레코드의 다음에 있는지를 나타낸다.
Bookmark 레코드셋에서 현재 레코드의 위치를 저장하고 언제라도 그 위치로 이동할 수 있다.
CacheSize 로컬 메모리에 저장할 레코드의 개수를 지정한다.
CacheSize의 기본값은 ForwardOnly 커서를 가진 레코드 셋의 경우 1이고, 그 외의 경우에는 모두 10의 값을 갖는다.
CursorType 레코드 셋에서 사용할 커서의 유형을 정한다.
커서란 레코드 셋에서 현재 레코드를 가리키는 포인터를 말하고, 커서의 유형은 아래와 같은 유형이 있으며 각각 다른 특성을 가진다.
커서 유형 지원 기능
AdOpenForwardOnly None
AdOpenKeyset adBookmark, adHoldRecords, adMovePrevious, adResync
AdOpenDynamic adMovePrevious
AdOpenStatic adBookmark, adHoldRecords, adMovePrevious, adResync
EditMode 현재 레코드의 편집 상태를 나타낸다.
Filter 레코드셋 객체 안에서 선택적으로 레코드들을 화면에 표시할 때 사용한다.
LockType 레코드를 편집하는 동안 설정할 락 유형을 결정한다.
MaxRecords 쿼리 실행후에 리턴될 최대 레코드 수를 지정한다.
PageCount 레코드셋이 포함하고 있는 페이지 수를 지정한다.
PageSize 페이지당 레코드 수를 결정한다.
RecordCount 레코드셋 객체의 총 레코드 수를 리턴한다.
Source 레코드셋 안의 데이터가 어디로부터 왔는지를 나타낸다.
Status 순차적 업데이트또는 기타 작업에 대한 현재 레코드의 상태를 나타낸다.

메소드 설명
AddNew 레코드셋에 새로운 레코드를 생성한다.
CancelBatch 진행중인 순차 업데이트를 취소한다.
CancelUpdate AddNew나 Edit로 변경한 레코드의 업데이트를 취소한다.
Clone 존재하는 레코드셋의 복사하여 새로운 레코드셋을 생성한다.
Close 열려진 레코드셋을 닫는다.
Delete 레코드셋에서 현재 레코드를 삭제한다.
GetRows 레코드셋에서 여러 개의 레코드를 읽어서 배열에 저장한다.
Move 레코드셋에서 현재 레코드를 이동시킨다.
MoveFirst 현재 레코드를 첫 레코드로 이동시킨다.
MoveLast 현재 레코드를 마지막 레코드로 이동시킨다.
MoveNext 현재 레코드를 다음 레코드로 이동시킨다.
MovePrevious 현재 레코드를 이전 레코드로 이동시킨다.
NextRecordset 현재 레코드셋을 종료하고 다음 레코드셋을 리턴한다.
Open 쿼리나 SQL의 실행한 결과를 가져온다.
Requery 쿼리를 다시 실행하여 레코드셋을 최신 정보로 고친다.
Resync 데이터베이스로부터 현재 레코드셋의 데이터를 최신 정보로 갱신한다.
Supports 레코드셋이 특정 기능을 지원하는지를 결정한다.
Update 현재 레코드의 변경사항을 레코드셋 객체에 저장한다.
UpdateBatch 진행중인 모든 순차 업데이트 작업을 디스크로 저장한다.
 

 Field 객체

 
필드 객체는 레코드셋 객체의 각 필드를 표현하는 객체이다.
레코드셋은 필드 객체들의 모임인 Fields 컬렉션을 가진다.
필드 객체는 레코드셋에 저장되어 있는 실질적인 값들에 접근할 수 있는 방법을 제공한다.
필드 객체에 대한 문법은 아래와 같이 다양한다.

Recordset.Fields.Item(0)
Recordset.Fields.Item("Name")
Recordset.Fields(0)
Recordset.Fields("Name")
Recordset(0)
Recordset("Name")
Recordset![Name]

 
프로퍼티 설명
ActualSize 필드 값의 실제 길이를 나타낸다.
Attributes 필드 객체의 속성을 나타낸다.
DefinedSize 필드 객체의 정의된 길이를 나타낸다.
Name 필드의 이름을 나타낸다.
NumericScale 숫자형 필드의 소수점 이하 자리수를 나타낸다.
OriginalValue 필드의 값이 변하기 전에 원래의 값을 나타낸다.
Precision 숫자형 필드의 최대 자리수를 나타낸다.
Type 필드 객체의 데이터 타입을 나타낸다.
UnderlyingValue 데이터베이스 내의 현재 필드의 값을 나타낸다.
Value 필드의 값을 나타낸다.

메소드 설명
AppendChunk 데이터를 긴 문자열이나 바이너리 타입의 필드 객체에 추가한다.
GetChunk 긴 문자열이나 바이너리 타입의 필드 객체에서 전부 또는 일부 내용을 리턴한다.
 

 Property 객체

 
프로퍼티 설명
Attributes 프로퍼티 객체의 속성을 나타낸다.
Name 프로퍼티의 이름을 나타낸다.
Type 프로퍼티의 데이터 타입을 나타낸다.
Value 프로퍼티의 값을 나타낸다.
Posted by skensita
Programming/MFC2008. 9. 6. 16:30

ADO를 이용한 삽입, 삭제, 업뎃



void CTestADODlg::OnButton3()
{
 // DAO (Access2000) 이후 버젼 리딩가능
 AfxGetModuleState()->m_dwVersion = 0x0601;
 
 // COM이나 OLE를 라이브러리를 초기화한다.
 AfxOleInit();
 
 
 // ADO에 Connection 객체 사용
 _ConnectionPtr pConn;  
 HRESULT hr;
 BOOL IsConnectionOpen = FALSE;
 
 // DB를 열기 위한 예의상 구문으로 인식하고 넘어가자.
 
 CoInitialize(NULL);
 hr = pConn.CreateInstance(__uuidof(Connection));
 //pConn->CursorLocation =adUseClient;
 
 // 데이터베이스 접속
 if(SUCCEEDED(hr))
 {
  // Provider: 여기서는 mdb를 사용하므로, Microsoft.Jet.OLEDB.4.0를 선택한다.
  // Data위치: c:\\TestDb.mdb
  _bstr_t strMode("Provider=Microsoft.Jet.OLEDB.4.0;Data Source= d:\\dbTest.mdb;");
  try
  {
   hr = pConn->Open(strMode,_bstr_t(L""),_bstr_t(L""), -1);
  }
  catch(_com_error& e)
  {
   AfxMessageBox(e.Description());
   AfxMessageBox(e.ErrorMessage());  
  }
 }
 if(SUCCEEDED(hr))
 {
  AfxMessageBox("데이터베이스 연결됨");
  IsConnectionOpen = TRUE;
 }
 
 // 데이터베이스에 연결이 되었다면,
 if(IsConnectionOpen)
 {
  _RecordsetPtr pRs;
  hr = pRs.CreateInstance(__uuidof(Recordset));
  _bstr_t strQuery("Select * from tblTest");
     
  // INSERT 구문
  try
  {
   // 테이블명(tbltest)에서 필드ID에 200, Checker에 300을 삽입한다.
   _bstr_t bstrQuery("INSERT INTO tbltest(ID,Checker) values('200','300')");
   
   // 0L에서 0은 int형 0L은 long형을 의미한다.
   // long형이 int 보다 더 큰수 저장가능

   _variant_t valValue(0L);


   // 새로운 트랜젝션을 시작한다.
   pConn->BeginTrans();
   pRs = pConn->Execute((_bstr_t)bstrQuery, &valValue, adOptionUnspecified);


   // 현재 트랜젝션에서 일어난 변경을 저장하고 트랜젝션을 닫고
   // 새로운 트랜젝션을 시작한다.
   pConn->CommitTrans();
 
  }
  catch(_com_error& e)
  {
   AfxMessageBox(e.Description());
   AfxMessageBox(e.ErrorMessage());  
  }
 
 
  // UPDATE 구문
  try
  {
   // 필드명 ID의 값이 2인 모든 곳의 필드명 ID, Checker의 필드값을 변경
   _bstr_t bstrQuery2("UPDATE tbltest SET ID = 2000 , Checker = 300 WHERE ID = 2 ");
   _variant_t valValue2(0L);
   pConn->BeginTrans();
   pConn->Execute((_bstr_t)bstrQuery2, &valValue2, adOptionUnspecified);
   pConn->CommitTrans();
 
  }
  catch(_com_error& e)
  {
   AfxMessageBox(e.Description());
   AfxMessageBox(e.ErrorMessage());  
  }
 

  // DELETE 구문
  try
  {
   // ID가 200인 tbltest 테이블 내의 Record를 삭제.
   _bstr_t bstrQuery3("DELETE FROM tbltest WHERE ID = 200 ");
   _variant_t valValue3(0L);


  pConn->BeginTrans();
   pConn->Execute((_bstr_t)bstrQuery3, &valValue3, adOptionUnspecified);
   pConn->CommitTrans();
 
  }
  catch(_com_error& e)
  {
   AfxMessageBox(e.Description());
   AfxMessageBox(e.ErrorMessage());  
  }
 }
}

Posted by skensita
Programming/MFC2008. 9. 6. 16:30

MS Access로 mdb를 만들었다고 가정하고 시작해본다.

ADO를 사용하기 위해서는 가령 작업하고 있는 파일(TestADODlg.cpp/TestADODlg.h),

라면 다음과 같은 선언을 상단에 우선적으로 해야한다.



(Step1) - 헤더파일

#if !defined(AFX_TESTADODLG_H__4B76919F_E8B6_4E36_92B4_4F549B5272FC__INCLUDED_)
#define AFX_TESTADODLG_H__4B76919F_E8B6_4E36_92B4_4F549B5272FC__INCLUDED_

#if _MSC_VER > 1000
#pragma once
#endif // _MSC_VER > 1000

#import "C:\Program Files\Common Files\System\ADO\msado15.dll" rename("EOF", "EndOfFile")
using namespace ADODB;
// #import "C:\Program Files\Common Files\System\ADO\msado15.dll"no_namespace

// rename("EOF", "EndOfFile")


 

(Step2)

void CTestADODlg::OnTestADO()
{
 
 // DAO (Access2000) 이후 버젼 리딩가능
 AfxGetModuleState()->m_dwVersion = 0x0601;
 
 // COM이나 OLE를 라이브러리를 초기화한다.
 AfxOleInit();
 
 
 // ADO에 Connection 객체 사용
 _ConnectionPtr pConn;  
 HRESULT hr;
 BOOL IsConnectionOpen = FALSE;
 
 // DB를 열기 위한 예의상 구문으로 인식하고 넘어가자. 
 CoInitialize(NULL);
 hr = pConn.CreateInstance(__uuidof(Connection));
 pConn->CursorLocation = adUseClient;
 
 // 데이터베이스 접속
 if(SUCCEEDED(hr))
 {
  // Provider: 여기서는 mdb를 사용하므로, Microsoft.Jet.OLEDB.4.0를 선택한다.
  // Data위치: D:\\tDbTest.mdb
  _bstr_t strMode("Provider=Microsoft.Jet.OLEDB.4.0;Data Source= d:\\dbTest.mdb;");
  try
  {
   hr = pConn->Open(strMode,_bstr_t(L""),_bstr_t(L""), -1);
  }
  catch(_com_error& e)
  {
   AfxMessageBox(e.Description());
   AfxMessageBox(e.ErrorMessage());  
  }
 }
 if(SUCCEEDED(hr))
 {
  AfxMessageBox("데이터베이스 연결됨");
  IsConnectionOpen = TRUE;
 }
 
 // 데이터베이스에 연결이 되었다면,  레코드의 내용을 확인하자.
 if(IsConnectionOpen)
 {
  _RecordsetPtr pRs;
  hr = pRs.CreateInstance(__uuidof(Recordset));
  _bstr_t strQuery("Select * from tblTest");
 
 
  // 레코드셋 설정
  hr = pRs->Open(strQuery, pConn.GetInterfacePtr(),
   adOpenForwardOnly,adLockReadOnly,adCmdText);  
  // 아래와 같은 방식으로 접속해도 된다
  // pRs = pConn->Execute((_bstr_t)strQuery, NULL, adOptionUnspecified);
   
  _variant_t vtColumn;
  _variant_t vtNull;
 
  // _varint_t 형의 Type을 변경한다.
  vtNull.ChangeType(VT_NULL);
 
  TCHAR strDisp[MAX_PATH+1];
  short i;
 
  // Record수를 읽는다.
  long nRecord = pRs->RecordCount;
 
  // Field수를 구한다. 주의해야할 것은 long형이라는 것이다.
  long nRow = pRs->Fields->Count;

  // 다음은 Field수를 구하는 다른 방법이다.
  long nRow2 = pRs->GetFields()->Count;
 
 
  // 필드명 표시
  for(i = 0; i<nRow ; i++)
  {
   // 필드명 취득
   vtColumn = pRs->Fields->GetItem(i)->Name;  
   vtColumn.ChangeType(VT_BSTR);


   // 문자열 복사하는 방법
   lstrcpyn(strDisp,(_bstr_t)vtColumn,MAX_PATH);  
  }

  // 필드값 표시  
  while(!pRs->EndOfFile)
  {
   for(i=0;i<nRow;i++)
   {
    // 필드값을 읽어온다
    vtColumn = pRs->GetCollect(i);

    // 또한 필드값을 읽어오는 다른 방법이다.
    // vtColumn = pRs->Fields->GetItem(i)->Value;

    // 조금더 다르게 하여 특정 필드의 필드값을 읽어온다.
    // vtColumn = pRs->Fields->GetItem("Checker")->Value;

    // 데이터가 NULL이면 ""을 대입
    if(vtColumn == vtNull)
    {
     vtColumn = _variant_t("");    
    }
    else
    {
     vtColumn.ChangeType(VT_BSTR);    
    }
    lstrcpyn(strDisp,(_bstr_t)vtColumn,MAX_PATH);
   
   }
   pRs->MoveNext();
  }
  hr = pRs->Close();
 }

pConn->Close();
}

Posted by skensita
Programming/MFC2008. 9. 5. 01:19

BOOL CEasyInterfaceApp::InitInstance()
{
 HANDLE hMutex = CreateMutex(NULL, TRUE, "EasyInterFace");
 
 if(GetLastError() == ERROR_ALREADY_EXISTS)
 {
  ReleaseMutex(hMutex);
 
  CWnd *pWndPrev, *pWndChild;
 
  if(pWndPrev = CWnd::FindWindow(NULL, "EasyInterFace"))
  {
   pWndChild = pWndPrev->GetLastActivePopup();
   
   if(pWndPrev->IsIconic())
    pWndPrev->ShowWindow(SW_RESTORE);
   
   pWndChild->SetForegroundWindow();
  }
 
  return FALSE;
 }
 ReleaseMutex(hMutex);
}
Posted by skensita