[MFC] 디렉토리 선택 가능한 대화상자(SHBrowseForFolder)


디렉토리만 선택해야하는 경우 아래와 같은 박스가 필요함. 아래 코드에서 약간은 수정하여 사용할 수 있습니다.
플래그 설정으로 디렉토리, 파일 선택을 할 수 있습니다. (파일도 가능함)


[Source Code]
        :
static int CALLBACK BrowseCallbakProc(HWND hWnd, UINT uMsg, LPARAM lParam, LPARAM pData)

{

switch(uMsg)

{

case BFFM_VALIDATEFAILED:

CString strText;

strText.Format("%s", reinterpret_cast<LPTSTR>(lParam));

AfxMessageBox(strText);

break;

}

return 0;

}

 

void CNet_ProgDlg::OnButton6() // 여기는 클레스, 함수 이름이 바꾸어야 합니다.

{

    // TODO: Add your control notification handler code here

   
    ITEMIDLIST *pildBrowse;

char pszPathname[MAX_PATH];

      

LPITEMIDLIST pidl = NULL;

BROWSEINFO bInfo;

ZeroMemory( &bInfo, sizeof(BROWSEINFO) );

      

SHPathToPidl( CSIDL_DESKTOP, &pidl ); // 루트 디렉토리 설정 부분.

bInfo.hwndOwner = GetSafeHwnd();

bInfo.pidlRoot = pidl;

bInfo.pszDisplayName = pszPathname;

bInfo.lpszTitle = "Please Select Directory....";

bInfo.lpfn = BrowseCallbakProc;              
    // 콜백함수가 필요없다면 NULL이나 지움. 위의 static int 함수 필요 없어짐

bInfo.ulFlags = BIF_RETURNONLYFSDIRS | BIF_EDITBOX | BIF_VALIDATE ;
    // 디렉토리만 설정가능하도록 하였습니다... 플래그 설정은 맨 아래 참조하세요, 또는 MSDN

 

pildBrowse = ::SHBrowseForFolder(&bInfo);

      

if( pildBrowse != NULL )

{

SHGetPathFromIDList(pildBrowse, pszPathname);

        m_strDownFolder = (LPCTSTR)pszPathname; // 선택한 폴더 또는 파일… 이 부분을 목적에 맞게 수정.

        UpdateData(FALSE);                              

}

 

}

 

HRESULT CNet_ProgDlg::SHPathToPidl( LPCTSTR szPath, LPITEMIDLIST* ppidl )  // 여기는 클레스 이름 바꾸어야 함.

{

LPSHELLFOLDER pShellFolder = NULL;

OLECHAR wszPath[MAX_PATH] = {0};

ULONG nCharsParsed = 0;

      

HRESULT hr = SHGetDesktopFolder( &pShellFolder );

      

if( FAILED(hr) ) return FALSE;

      

MultiByteToWideChar( CP_ACP, MB_PRECOMPOSED, szPath, -1, wszPath, MAX_PATH );

hr = pShellFolder->ParseDisplayName( NULL, NULL, wszPath, &nCharsParsed, ppidl, NULL );

pShellFolder->Release();

      

return hr;

}

        : 

 

 

/*

// Browsing for directory.

#define BIF_RETURNONLYFSDIRS 0x0001 // For finding a folder to start document searching

#define BIF_DONTGOBELOWDOMAIN 0x0002 // For starting the Find Computer

#define BIF_STATUSTEXT 0x0004

#define BIF_RETURNFSANCESTORS 0x0008

#define BIF_EDITBOX 0x0010

#define BIF_VALIDATE 0x0020 // insist on valid result (or CANCEL)

 

#define BIF_BROWSEFORCOMPUTER 0x1000 // Browsing for Computers.

#define BIF_BROWSEFORPRINTER 0x2000 // Browsing for Printers

#define BIF_BROWSEINCLUDEFILES 0x4000 // Browsing for Everything

*/

-bInfo.ulFlags 플래그

 

BIF_BROWSEFORCOMPUTER : 네트워크의 컴퓨터만 선택가능

BIF_BROWSEFORPRINTER : 프린터만 선택가능

BIF_BROWSEINCLUDEFILES : 파일도 표시

BIF_DONTGOBELOWDOMAIN : 네트워크의 컴퓨터를 표시하지 않는다

BIF_EDITBOX : 에디트 박스를 표시한다

BIF_RETURNFSANCESTORS : 네트워크의 컴퓨터만 선택가능

BIF_RETURNONLYFSDIRS : 폴더만 선택가능

BIF_STATUSTEXT : 스테이터스 텍스트를 표시한다

BIF_VALIDATE : 부정 입력시에, BFFM_VALIDATEFAILED 이벤트

 

 

//Must be static funtion.
static int CALLBACK BrowseForFolder_CallbackProc(HWND m_hWnd, UINT uMsg, LPARAM lParam, LPARAM lpData)
{
 if(uMsg == BFFM_INITIALIZED)
  SendMessage(m_hWnd, BFFM_SETSELECTION, (WPARAM)TRUE, (LPARAM)lpData);

 return 0;
}

위 함수는 꼭 static 함수여야 한다. 그리고 아래에서 함수포인터를 넣어준다.
아래 코드는 폴더 선택 다이얼로그를 띄워야 하는 곳에 넣어주면 되겠지.

 BROWSEINFO bi;
 ZeroMemory(&bi, sizeof(BROWSEINFO));
 bi.hwndOwner =  this->GetSafeHwnd();
 bi.pidlRoot = NULL;
 bi.pszDisplayName = NULL;
 bi.lpszTitle = NULL;
 bi.ulFlags = BIF_RETURNONLYFSDIRS;
 bi.lpfn = BrowseForFolder_CallbackProc;
 bi.lParam = (LPARAM)(LPCTSTR)m_strContentsDownloadFolder; //초기값 설정.

 LPITEMIDLIST pidl = SHBrowseForFolder(&bi);
 TCHAR szPath[MAX_PATH] = {0,};  

 if( pidl )
 {
  SHGetPathFromIDList( pidl, szPath );
  m_strContentsDownloadFolder = szPath;
  GetDlgItem( IDC_DOWNLOAD_ADDRESS )->SetWindowText( m_strContentsDownloadFolder );
 }

위와 같이 하면 폴더를 선택할 수 있는 다이얼로그가 뜬다.

 

 

보통 많은 프로그램들을 보면 버튼 눌렀을때 폴더 선택할수 있게 다이얼로그를 띄워준다.

이것을 어케 하는지 알아본다.

간단하다.

 

   ITEMIDLIST *pidlBrowse;
   char pszPathname[1000];
   BROWSEINFO BrInfo;
   BrInfo.hwndOwner = GetSafeHwnd();
   BrInfo.pidlRoot = NULL;

  
   memset(&BrInfo, 0, sizeof(BrInfo));
   BrInfo.pszDisplayName = pszPathname;
   BrInfo.lpszTitle = "경로 선택";
   BrInfo.ulFlags = BIF_RETURNONLYFSDIRS;

   pidlBrowse = ::SHBrowseForFolder(&BrInfo);

   if( pidlBrowse != NULL)
   {
       ::SHGetPathFromIDList(pidlBrowse, pszPathname);
       m_strFileDownDir = pszPathname;  // 폴더 경로
   }

 

반환되는 폴더 경로는 pszPathname 에 저장된다.

 

대부분의 개발자들은 버그를 없애기 위해 많은 시간과 노력을 들인다. 그럼에도 막상 소프트웨어를 출시하고 나면 미처 발견하지 못한 버그로 낭패를 당하기 십상이다. 시간과 비용의 재투자는 말할 것도 없다. 이 같은 이유에서 개발자라면 누구나 자신이 작성한 프로그램의 버그를 찾아주는 툴이 있었으면 하는 바람을 가진다.

Sparrow는 C/C++ 프로그램의 소스를 분석하고 치명적인 오류를 찾아주는 툴이다. 테스트 케이스 실행을 통해 오류를 찾는 기존 테스팅 방법과 달리 프로그램 실행 없이 소스 코드만 분석하여 자동으로 프로그램의 오류를 찾아준다. 시간과 비용을 줄이는 완전히 다른 형태인 것이다.

■ 소스 코드에서 오류 검색
Sparrow는 C/C++에서 흔히 발생하는 메모리 관련 오류를 찾아낸다. 메모리 관련 오류로는 버퍼 오버런(buffer overruns), 메모리 누수(memory leaks), 메모리 해제 후 사용(memory uses after free) 등이다. 이번 리뷰는 프로그램 소스를 쉽게 구할 수 있는 공개 소프트웨어 분석으로 진행했다. 테스트 환경은 펜티엄4 3.2GHz와 4GB 메모리가 설치된 PC와 리눅스 운영체제를 사용하였다.

사용 방법은 간단하다. Makefile이 있는 디렉토리에서 간단한 명령어를 입력하면 분석을 시작하고, 결과까지 알려준다. 먼저 smake라는 명령어를 실행해 소스 트리의 구조를 파악하고 실행 파일이나 라이브러리를 만드는데 필요한 파일을 정리한다.

C/C++ 환경의 메모리 오류 검색 smke 이후 생성된 분석 단위

그리고 분석하고 싶은 실행 파일이나 라이브러리를 선택하여 분석을 하면 된다. 분석 결과는 HTML 페이지로 만들어지므로 웹 브라우저에서 확인이 가능하다. 우선 tar를 분석하는 데 걸리는 시간을 측정하였더니 100초 정도가 소요되었다. tar의 소스 크기가 28,000라인 정도 되니까 분석 속도는 매우 빠른 편이다.

Sparrow는 tar에서 총 26개의 메모리 누수와 버퍼 오버런이 발생할 수 있다고 분석했다. 대부분의 소스 코드 분석기 툴이 그렇듯이, 여기서 알려주는 오류는 진짜 오류가 아닐 수 있다. 따라서 오류의 진위여부를 확인할 필요가 있다.

■ 스코어 기능, 분석 결과 진위 여부 확인
Sparrow는 분석 결과로 알려준 오류가 진짜 오류인지 거짓 오류인지를 사용자가 쉽게 판단 할 수 있도록 두 가지 기능을 제공한다. 하나는 분석기에서 나온 오류의 형태를 보고 통계적인 방법을 사용해 오류의 여부를 점수로 매기는 스코어 기능이다. 사용자는 오류에서 스코어가 높은 순서대로 하나씩 확인하여 걸러내면 된다.

이는 Sparrow만의 독특한 기능이라고 하겠다. 다른 한 가지는 프로그램이 실행되고 어떤 과정에서 오류가 발생하는 지를 확인할 수 있도록 오류의 근원에서 발생 시점까지 흐름을 추적해준다. 해제 후 사용 오류와 메모리 누수 오류의 경우에는 함수 호출과 리턴 등의 프로그램 실행 흐름의 큰 변화가 일어나는 지점에 한해 정보를 제공한다.

tar 분석 결과 중 일부 버퍼 오버런 경고 화면

버퍼 오버런의 경우는 실행 흐름의 정보가 매우 자세하다. 예를 들어, 버퍼 buf가 buf[x]라는 식을 통해 접근이 되었다면, buf와 x의 값에 영향을 주는 명령어만 링크로 연결하여 보여준다. 이러한 연결 고리를 Sparrow에서는 reason chain이라고 한다. 사용자는 오류 확인을 위해 꼭 필요한 명령문만 확인하면 된다는 얘기다.

실제로 tar 분석으로 나온 버퍼 오버런이 진짜인지 reason chain으로 쉽게 확인할 수 있었다. 부가적으로는 매크로, 변수, 함수를 정의한 지점을 찾는 기본적인 기능과 정의된 함수가 어느 지점에서 호출되었는지 함수 포인터를 통해 호출한 곳까지 찾아 알려준다.

■ 프로그램 버그 해결 도우미
Sparrow는 단순히 오류가 발생한 위치만 알려주는 툴이 아니다. 그 오류가 발생한 실행 흐름 중에서 꼭 체크해야 하는 부분을 알려주므로 라인 하나하나를 일일이 살펴볼 필요가 없다. 작업 속도가 생명인 테스트 과정에서 더없이 중요한 사항이다. 참고로 큰 규모의 프로그램 분석 성능은
www.spa-arrow.com에서 확인할 수 있다.

메모리 누수 경고 화면 메모리 누수가 발생한 지점 화면

최근 들어 소프트웨어 오류에 대한 관심과 우려가 집중되고 있다. 프로그램 덩치가 거대하고 복잡해지면서 오류의 원인도 점점 찾기가 힘들어질뿐더러 숨겨진 오류가 언제 나타날지 모르기 때문이다. 더군다나 디지털화가 가속되면서 곳곳에 쓰이는 소프트웨어의 오류는 일상생활과 밀접하게 연관될 수밖에 없다. 그래서 버그 해결의 중요성은 누차 강조해도 모자람이 없다.

Sparrow는 사용자가 분석 결과를 쉽게 확인할 수 있게끔 편의성 높은 UI와 기능을 제공한다. 누구나 사용할 수 있음을 의미한다. 오랜 기간 동안 사용되고 검증된 공개 프로그램을 분석한 탓에 리뷰 과정에선 버퍼 오버런 오류가 거의 없었다. 반면 메모리 누수 오류는 꽤 많이 발견되었다. 프로그램 버그로 인한 고민을 한다면 Sparrow가 그 대안이 될 수 있겠다.

 
전민식 월간 마이크로소프트웨어 필자 msjin@gmail.com | 2007-05-07 13:01


더 보기 http://www.ebuzz.co.kr/content/buzz_view.html?ps_ccid=21988#ixzz0sg5q9E5I

유니코드 .. 멀티바이트 이놈들 -ㅅ-..

꼭 필요하긴하지만 ..막상쓰면 뷁쒧뗅뙓 같은 녀석들이다 -_ㅠ..

 

친절하게도

MultiByteToWideChar()

WideCharToMultiByte()

라는 함수를 제공해주지만..

 

굉장히 사용이 복잡하다는 문제점을 안고 있다.....

(크기설정 이나 옵션설정도 필요하다 -_-)

 

그래서 찾다 발견한 ...

 

#include <atlconv.h>
 USES_CONVERSION; // W2A , A2W를 사용하기 위한 디파인..

W2A() // 유니코드->멀티

A2W() // 멀티 -> 유니코드

 

 

사용하기전에

 USES_CONVERSION;

해줘야하는 점이 좀 복잡하긴하지만..

뭐 그래도 훨씬 간단한 것이다!!!!!!

 

 char szMult[] = "멀티녀석들!!";
 wchar_t szWide[] = L"유니코드닷";


 USES_CONVERSION;
 strcpy(szMult, W2A(szWide)); // 유니코드 -> 멀티바이트 복사
 _tcscpy(szWide, A2W(szMult)); // 멀티바이트 -> 유니코드 복사

 

뭐 그래도 훨씬 간단한 것이다!!!!!!

'C/C++언어 > 유니코드' 카테고리의 다른 글

CSting의 유니코드를 파일로 저장 & 로드 할때  (1) 2007.11.18
유니코드 정보 모음  (0) 2007.11.18
유니코드의 사용법  (0) 2007.09.06

출처 : http://blog.naver.com/gml81/40037809685

MapWindowPoints : CWnd의 좌표계로부터 다른 윈도우의 좌표계로 지정된 점들을 매핑시 킨다.
ClientToSreen : 클라이언트 좌표계를 화면 좌표계로 변환한다.
ScreenToClient : 화면 좌표계를 클라이언트 좌표계로 변환한다. 
-----------------------------------------------------------------------------

OnPrepareDC()에서

    dc.SetMapMode(MM_ISOTROPIC);

    dc.SetWindowExt(1000,1000);

    dc.SetViewportExt(2000,2000);

      CClientDC dc (this);
     OnPrepareDC (&dc);
     dc.DPtoLP (&point);
point가 마우스 좌표라면 논리 좌표로 변환해 주는 코드입니다.

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

jpg 이미지가 255*255 픽셀 크기인데요...
출력을하면은 255*255 크기가 아니고 적게 출력이 되는데.
무슨 이유입니까??

좌표계가 MM_TEXT로 설정되어 있어서 그럴겁니다

 MM_TEXT 좌표계는 하나의 픽셀이 기준이 됩니다
질문하셨다 시피 jpg 이미지가 255*255 크기라면   
좀 픽셀이 큰 모니터에서는 이미지가 더 크게 나오겠죠?

출력을 할때도 마찬가지로
프린터 장치의 dpi라고 하죠 1인치 사각형안에 얼마나 많은 점들을 찍을수 있느냐 하는 건데
(보통 300dpi 뭐 이런 얘기 많이 들어보셨을 겁니다)
이 프린터의 dpi에 따라 이미지 사진이 더 크게나올수도 있고 작게나올수도 있는겁니다

왜냐하면 기준이 픽셀이기 때문이죠 

그럼 화면과 출력물의 크기가 같아지기 위해서는 어떻게 해야하느냐 하면
MM_LOMETRIC같은 좌표계를 쓰시는 겁니다

MM_LOMETRIC은 자표계 기준이 0.1미리 입니다
따라서 MM_LOMETRIC좌표계 기준으로 1000*1000의 그림은
화면에서나 출력에서나 10cm * 10cm로 동일하게 출력되는 것이죠

쉽게 말씀드리면

 SetMapMode() 함수를 이용해서 좌표계를 바꿔주라는 이야기 입니다 ^^
SetMapMode(hPrinterDC, MM_LOMETRIC); // 이런식으로요

물론 출력하실때 좌표계가 바뀌었으니 출력될 좌표는 신경쓰셔야 겠죠 ^^
참고로 MM_LOMETRIC은 MM_TEXT와는 달리

y축이 아래로 가면 - 값 입니다

덧붙이자면

BOOL DPtoLP() // 디바이스 좌표를 로직좌표계로 바꿔주는 함수와 그 반대 함수들이 존재하니 참고 하시구요

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

 DPtoLP는 함수 이름 대로 디바이스 좌표를 논리적 좌표로 변경해주는 함수입니다...
 디바이스 좌표는 화면의 한 Pixel, 프린터의 한 Dot를 뜻합니다.
논리적 좌표는 논리적으로 단위를 정한 좌표입니다.(예로 10cm단위로 1, 2, 3...)
 일반적으로 GetDC()를 하게 되면 리턴되는 DC는 MM_TEXT 모드가 됩니다.
MM_TEXT는 디바이스 좌표와 논리 좌표가 1:1 대응(화면의 한 점이 1이 됩니다.)됩니다.
결국 DPtoLP를 해도 값의 변화가 없겠죠...

하지만 map mode를 MM_HIMETRIC으로 변경했다고 가정하면 논리적 좌표 1은
0.01mm를 나타내기 때문에 화면의 한 pixel은 화면 DPI에 따라 1이 아닌 다른 논리적 값이 됩니다...

[출처] [MFC] 좌표계|작성자 영희

출처 : http://tong.nate.com/gayanim/27925620

GetWindowRect
윈도우의 현재 위치와 크기를 구해준다. (left, top)은 윈도우의 현재 좌상단 위치를 나타내는데 이 좌표는 전체 화면을 기준으로 한 좌표이다. (right, bottom)은 윈도우의 우하단 위치를 나타내며 역시 전체 화면을 기준으로 한 좌표이다. 윈도우의 현재 크기(폭과 높이)를 구하고 싶으면 right-left, bottom-top을 계산하면 된다.

GetClientRect
윈도우의 작업영역 크기를 계산해 준다. 크기만 계산해 주기 때문에 좌상단(left, top)값은 항상 0,0이며 우하단 좌표(right, bottom)가 곧 윈도우의 크기를 나타낸다. 작업영역이란 윈도우의 타이틀바, 스크롤 바, 경계선, 메뉴 등을 제외한 영역이며 윈도우가 그리기를 하는 대상 영역이다

 

ScreenToClient
화면의 원점을 기준으로 하는 좌표 lpPoint를 hWnd의 작업 영역을 기준으로 하는 좌표로 변환한다. hWnd윈도우의 작업 영역 원점의 화면 좌표가 cx, cy일 때 lpPoint는 lpPoint.x - cx, lpPoint - cy로 변환된다. GetCursorPos, MoveWindow, GetWindowRect 등과 같이 화면 좌표를 리턴하는 함수로부터 작업 영역의 좌표로 변환하고자 할 때 이 함수를 사용한다.

+ Recent posts