GSI

윈도우 찾아서 종료 시키기

인스톨 프로그램과 비슷한 경우를 보면 해당 실행파일을 업데이트 할 경우가 생기게 되는데 이때 실행 파일을 종료 하고 새로운 파일을 추가한 후에 다시 실행시켜야 하는 경우가 발생 한다.

그래서 화면에 떠 있는 응용 프로그램의 타이틀이나 클래스를 검색 해서 프로세스 아이디를 얻은 다음에 프로세스를 종료 시켜야 한다.

프로그램을 실행하고 Spy++로 보게 되면 아래와 같이 보이게 됩니다.

사용자 삽입 이미지




여기서 나오는 "TestRemoteClose" 와 "#32770" 두개를 접근해서 프로세스를 처리할 수 있습니다.

아래의 함수는 os에서 현재 돌아가고 있는 각종 윈도우를 순회 하면서 내가 원하는 윈도우를 찾아 주는 코드 입니다.

BOOL CALLBACK SearchWindowProc (HWND hWnd, LPARAM lParam)
{
 char szClassName[1024]={0,}, szTitle[1024]={0,};
 char *pTitle = "TestRemoteClose", *pTitle2 = "TestRemoteClose";
 char *pDest = NULL, *pDest2 = NULL;

 GetClassName (hWnd, szClassName, sizeof(szClassName));
 GetWindowText (hWnd, szTitle, sizeof(szTitle));

#ifdef _DEBUG
 char szBuf[2048];
 wsprintf (szBuf, "Title: [%s],\tClass: [%s]\n", szTitle, szClassName);
 OutputDebugString (szBuf);
#endif

 pDest = strstr (szTitle, pTitle);
 pDest2 = strstr (szTitle, pTitle2);

 // Title 의 값에서 pTitle, pTitle2의 값을 검사해서 NULL인지를 검사한다.
 // 즉, NULL 이 아니면 해당 윈도우라고 판단한다.
 if (pDest != NULL || pDest2 != NULL) {

  //if (!strcmp (szClassName, "IEFrame")) // 웹일 경우 IEFrame로 되어 있다.
  {

   if (bIsMsgBox == false) {
    bIsMsgBox = true;
    MessageBox (NULL, "정상적인 설치를 위하여 잠시 종료합니다.", "설치 정보", MB_ICONINFORMATION);
   }

   DWORD dwProcessId = 0;
   GetWindowThreadProcessId (hWnd, &dwProcessId);

   if (dwProcessId)
    UserTerminateProcessId (dwProcessId);
  }
 }

 return TRUE;
}

// 메인쪽에서 아래 함수를 호출하면서 순회 하게 된다.
EnumWindows (SearchWindowProc, NULL);

더 자세한 내용이나 수정해야될 부분이 있다면 코멘트 부탁 드립니다.

Posted by gsi
:

상태바를 추가 해서 툴을 적용할때 각종 정보들을 출력할 수 있습니다.

1. 리소스 기호를 추가 합니다.

사용자 삽입 이미지
2. String Table 에 추가 합니다.
사용자 삽입 이미지

3. 해당 내용을 추가 합니다.

static UINT indicators[] =
{
// ID_SEPARATOR,           // 상태 줄 표시기
 ID_INDICATOR_INFO0,      // 추가한 상태바
 ID_INDICATOR_INFO1,      // 추가한 상태바
 ID_INDICATOR_INFO2,      // 추가한 상태바
 ID_INDICATOR_INFO3,      // 추가한 상태바
 ID_INDICATOR_CAPS,
 ID_INDICATOR_NUM,
 ID_INDICATOR_SCRL,
};

4. 메인 프레임 사이즈 조정시 상태바의 크기도 조절 되도록 한다.

void CMainFrame::OnSize(UINT nType, int cx, int cy)
{
 CFrameWnd::OnSize(nType, cx, cy);

 if(m_wndStatusBar.m_hWnd != NULL)
 {
  int width = cy - 90;

  m_wndStatusBar.SetPaneInfo(0, ID_INDICATOR_INFO0, SBPS_NORMAL|SBPS_STRETCH, width/4);
  m_wndStatusBar.SetPaneInfo(1, ID_INDICATOR_INFO1, SBPS_NORMAL|SBPS_STRETCH, width/4);
  m_wndStatusBar.SetPaneInfo(2, ID_INDICATOR_INFO2, SBPS_NORMAL|SBPS_STRETCH, width/4);
  m_wndStatusBar.SetPaneInfo(3, ID_INDICATOR_INFO3, SBPS_NORMAL|SBPS_STRETCH, width/4);
  m_wndStatusBar.SetPaneInfo(4, ID_INDICATOR_INFO3, SBPS_NORMAL|SBPS_STRETCH, 30);
  m_wndStatusBar.SetPaneInfo(5, ID_INDICATOR_INFO3, SBPS_NORMAL|SBPS_STRETCH, 30);
  m_wndStatusBar.SetPaneInfo(6, ID_INDICATOR_INFO3, SBPS_NORMAL|SBPS_STRETCH, 30);
 }
}

5. 문자열을 바꿀때는 SetPaneText()를 사용한다.

m_wndStatusBar.SetPaneText(0, str0);  // 0은 인덱스, str0은 문자열

Posted by gsi
:

사용자 삽입 이미지

CDialog 베이스에 CStatic, CListBox를 사용해서 만들어 봤습니다.
마우스 휠을 사용하면 화면을 아래 위로 움직일 수 있습니다.
마우스로 타이틀을 더블클릭 하면 내용을 숨기고 보이게 할 수 있습니다.

[개선사항]
마우스로 휠을 사용할때 이동 폭을 지정해 주어야 할듯 하다.
타이틀 더블클릭으로 숨기기 모드가 되면 아래의 내용이 자동으로 올라 와야 한다.

관련 파일 :

Posted by gsi
:

CStatic를 상속해서 다른 컨트롤을 처리 할때 SS_NOTIFY 를 사용하면 마우스 이벤트를 받을 수 있다. 하지만 WM_MOUSEWHEEL 위쟈드에서 선택해서 함수 생성하면 신호가 들어오지 않는다. 하지만 PreTranslateMessage() 쪽에는 메시지가 들어 는거 같다.

BOOL CBarContainer::PreTranslateMessage(MSG* pMsg)
{
 if(pMsg->message == WM_MOUSEWHEEL)
 {
   // 처리하기
 }

 return CStatic::PreTranslateMessage(pMsg);
}

Posted by gsi
:

DC 내용 복사해서 다른 곳의 DC에 적용하기

내용 구현 :

Flicker Free Code 사용한 클래스 의 이름을 CMemDC 라고 하겠습니다.
해당 코드는 위에 있습니다.

우선 CMemDC로 선언한 변수에 현재 화면에 그려진 DC를 적용시켜 줍니다.
m_pTestFormDlg->m_pParentMemDC = new CMemDC(pDC, &rect);

해당 pDC와 화면 영역 값을 넘겨 주면서 생성해 줍니다.
원래 이 부분의 rect는 제가 집어 넣은 겁니다. 안해주면 내부에서 GetClipRect()로 값을
구해서 적용하게 되어 있습니다.

DC와 같이 적용된 CMemDC 쪽에 BitBlt를 사용해서 해당 DC의 내용을 그립니다.
m_pTestFormDlg->m_pParentMemDC->BitBlt(
   0, 0, rect.Width(), rect.Height(), pDC, 0, 0, SRCCOPY);

이제 이 DC를 다른 곳에서 BitBlt를 해서 사용하시면 됩니다.
pdc->BitBlt(0, 0, 850, 666, m_pParentMemDC, 0, 0, SRCCOPY);

이상. ^^

Posted by gsi
:

void CChildView::SaveBitmapToDirectFile(CDC* pDC, CRect BitmapSize, int BitCount, CString strFilePath)
{
 CBitmap bmp, *pOldBmp;
 CDC dcMem; 
 BITMAP                  bm;
 BITMAPINFOHEADER        bi;
 LPBITMAPINFOHEADER      lpbi;
 DWORD                   dwLen;
 HANDLE                  handle;
 HANDLE                  hDIB;  
 HPALETTE                hPal=NULL;

 /*----- CDC의 내용을 Bitmap으로 전송 ----*/
 dcMem.CreateCompatibleDC(pDC);
 bmp.CreateCompatibleBitmap(pDC ,BitmapSize.Width(),BitmapSize.Height());   
 pOldBmp = (CBitmap*) dcMem.SelectObject(&bmp);
 dcMem.BitBlt( 0,0, BitmapSize.Width(), BitmapSize.Height(), pDC, 0,0, SRCCOPY);
 dcMem.SelectObject(pOldBmp);

 if (strFilePath == "")          return;
 /*------------------------- 비트멥 헤더를 기록함 -------------------------*/
 if (hPal==NULL)
  hPal = (HPALETTE) GetStockObject(DEFAULT_PALETTE);
 GetObject(HBITMAP(bmp), sizeof(BITMAP), &bm);

 bi.biSize               = sizeof(BITMAPINFOHEADER);
 bi.biWidth              = bm.bmWidth;
 bi.biHeight             = bm.bmHeight;
 bi.biPlanes             = 1;
 bi.biBitCount           = 32;      
 bi.biCompression        = BI_RGB;
 bi.biSizeImage          = bm.bmWidth * bm.bmHeight * 3;
 bi.biXPelsPerMeter      = 0;
 bi.biYPelsPerMeter      = 0;
 bi.biClrUsed            = 0;
 bi.biClrImportant       = 0;

 int nColors = (1 << bi.biBitCount);
 if( nColors > 256 )
  nColors = 0;
 dwLen  = bi.biSize + nColors * sizeof(RGBQUAD);
 hPal = SelectPalette(pDC->GetSafeHdc(),hPal,FALSE);
 RealizePalette(pDC->GetSafeHdc());
 hDIB = GlobalAlloc(GMEM_FIXED,dwLen);
 lpbi = (LPBITMAPINFOHEADER)hDIB;
 *lpbi = bi;
 GetDIBits(pDC->GetSafeHdc(),
  HBITMAP(bmp),
  0,
  (DWORD)bi.biHeight,
  (LPBYTE)NULL,
  (LPBITMAPINFO)lpbi,
  (DWORD)DIB_RGB_COLORS);
 bi = *lpbi;
 if (bi.biSizeImage == 0)
 {
  bi.biSizeImage = ((((bi.biWidth * bi.biBitCount) + 31) & ~31) / 8)
   * bi.biHeight;
 }
 dwLen += bi.biSizeImage;
 if (handle = GlobalReAlloc(hDIB, dwLen, GMEM_MOVEABLE))
  hDIB = handle;

 lpbi = (LPBITMAPINFOHEADER)hDIB;
 GetDIBits(pDC->GetSafeHdc(),
  HBITMAP(bmp),
  0,                   
  (DWORD)bi.biHeight,     
  (LPBYTE)lpbi       
  + (bi.biSize + nColors * sizeof(RGBQUAD)),
  (LPBITMAPINFO)lpbi,  
  (DWORD)DIB_RGB_COLORS);

 BITMAPFILEHEADER      hdr;
 hdr.bfType        = ((WORD) ('M' << 8) | 'B');       
 hdr.bfSize        = GlobalSize (hDIB) + sizeof(hdr);  
 hdr.bfReserved1   = 0;                                
 hdr.bfReserved2   = 0;                                
 hdr.bfOffBits=(DWORD)(sizeof(hdr)+lpbi->biSize + nColors * sizeof(RGBQUAD));
 char* pBmpBuf;
 DWORD FileSize;
 FileSize=sizeof(hdr)+GlobalSize(hDIB);
 pBmpBuf = new char[FileSize];
 memcpy(pBmpBuf,&hdr,sizeof(hdr));
 memcpy(pBmpBuf+sizeof(hdr),lpbi,GlobalSize(hDIB));
 /*--------------------- 실제 파일에 기록함 --------------------------*/
 CFile file;
 file.Open(strFilePath, CFile::modeCreate | CFile::modeNoTruncate | CFile::modeWrite);
 file.Write(pBmpBuf,FileSize);
 file.Close();
 /*------------------------ 임시로 할당한 메모리를 해제.. -------------*/
 delete[] pBmpBuf;

 if(hDIB)
 {      
  GlobalFree(hDIB);
 }
 SelectPalette(pDC->GetSafeHdc(),hPal,FALSE);   
}

Posted by gsi
:

CScrollView를 사용해서 화면을 처리 하다 보면 셀 단위의 뷰를구현할때 즉, 화면이 일정 범위의 간격을 두고 움직이고자 할때 스크롤 바를 움직이면 한픽셀씩 움직이지 않고 한 단위씩 움직이도록 하고자 할때가 있다. 이때는 OnVScroll()를 오버라이드 한다.

void CColorPlayScrollView::OnVScroll(UINT nSBCode, UINT nPos, CScrollBar* pScrollBar)
{
 UINT newpos = 0;
 switch(nSBCode) {
  case SB_LINEUP:
  case SB_LINEDOWN:
  case SB_PAGEUP:
  case SB_PAGEDOWN:
  case SB_THUMBPOSITION:
  case SB_THUMBTRACK:
  case SB_TOP:
  case SB_BOTTOM:
  case SB_ENDSCROLL:
   {
    if(nPos%30 == 0) {
//     SetScrollPos(SB_VERT,nPos,TRUE);
     CScrollView::OnVScroll(nSBCode, nPos, pScrollBar);
    }
   }
   break;
 }

// SetScrollPos(SB_VERT,newpos,TRUE);

// CScrollView::OnVScroll(nSBCode, nPos, pScrollBar);
}

여기서 모든 메시지를 가져와서 해당 값이 되었을때만 호출하도록 처리 해봤습니다.
CScrollView::OnVScroll(nSBCode, nPos, pScrollBar);
이 함수를 호출하면 화면이 이동 되도록 해봤습니다. 결과는 아래와 같아요.^^

사용자 삽입 이미지

Posted by gsi
:

mfc 프로젝트 생성후에 dll을 추가해서 사용할때 실행 파일과 동일한 경로에 해당 데이터들이 있어야 한다.

속성 페이지에서 몇가지 만져 줘야 하는데요.

아래와 같습니다.

dll 프로젝트 생성시...
1. 일반 항목
   - 출력 디렉터리 = $(SolutionDir)lib
   - 중간 디렉터리 = $(SolutionDir)/Obj/$(ProjectName)/Debug

2. 링커 항목
   - 출력파일 = $(SolutionDir)lib\TestForm1.dll

3. 빌드 이벤트 > 빌드 후 이벤트 항목
   - 명령줄 = xcopy $(SolutionDir)\lib\TestForm1.dll $(SolutionDir)\bin\ /y
     ( dll 을 복사한다.)
Posted by gsi
:

기존 CScrollView를 사용하면서 mfc의 DC 드로잉 부분에서 부족했던 저로서는 번쩍 거리는 화면이 너무 안좋게 보였습니다.
하지만 지금 테스트해본 결과가 맞는 정답은 아니겠지만 많은 부분 개선되는 것을 확인했습니다.

스크롤 사이즈를 10240000 까지 늘려서 테스트를 진행했습니다.
sizeTotal.cx = sizeTotal.cy = 10240000;
SetScrollSizes(MM_TEXT, sizeTotal);

미리 선과제로 OnEraseBkgnd()는 return false로 변경을 하고 시작했습니다.

BOOL CScrollViewTestView::OnEraseBkgnd(CDC* pDC)
{
     return false;
}

하나더 해줘야 할게 CScrollView의 스크롤이 16bit로 되는 현상을 32bit로 전환처리. (이건 제 블로그나 기타 다른 곳에도 기술되어 있습니다.)

BOOL CScrollViewTestView::OnScroll(UINT nScrollCode, UINT nPos, BOOL bDoScroll)
{
 // When you drag the scroll box, the nPos value send from WM_HSCROLL/WM_VSCROLL is 16bit value.
 // Therefore retrieve the 32bit scroll box position value.
 if(SB_THUMBTRACK == LOBYTE(nScrollCode)) // WM_HSCROLL
 {
  SCROLLINFO info;
  if(GetScrollInfo(SB_HORZ, &info, SIF_TRACKPOS))
  {
   nPos = info.nTrackPos; // 32bit position value.
  }
 }
 else if(SB_THUMBTRACK == HIBYTE(nScrollCode)) // WM_VSCROLL
 {
  SCROLLINFO info;
  if(GetScrollInfo(SB_VERT, &info, SIF_TRACKPOS))
  {
   nPos = info.nTrackPos; // 32bit position value.
  }
 }

 return CScrollView::OnScroll(nScrollCode, nPos, bDoScroll);
}

이후에 OnDraw(CDC* pDC) 에서 테스트를 했습니다.

스크롤 내부의 총 사이즈를 사용해서 드로잉을 해봤습니다.

CSize size = GetTotalSize()
... 중략...
 for(int x = 0; x < size.cx; x += 10) {
  pDC->MoveTo(x, 0);
  pDC->LineTo(x, size.cy);
 }

 for(int y = 0; y < size.cy; y += 10) {
  pDC->MoveTo(0, y);
  pDC->LineTo(size.cx, y);
 }

이렇게 테스트를 하니까. tick를 찍어 봤을때 2250 이 나오네요. -.-;

그래서 우선  Flicker Free Drawing 를 사용해서 해봤습니다.

 CRect rcBounds = CRect(0, 0, size.cx, size.cy);
 CMemDC pDCEx(pDC);
 pDCEx->FillRect(rcBounds, CBrush::FromHandle((HBRUSH)GetStockObject(WHITE_BRUSH)));

 for(int x = 0; x < size.cx; x += 10) {
  pDCEx->MoveTo(x, 0);
  pDCEx->LineTo(x, size.cy);
 }

 for(int y = 0; y < size.cy; y += 10) {
  pDCEx->MoveTo(0, y);
  pDCEx->LineTo(size.cx, y);
 }

하지만 tick는 2500 으로 더 많게 되네요. 왜냐하면. 메모리 DC를 만들고 하다 보니 그런거 같아요.

그래서 스크롤은 안보이는 부분을 드로잉하지 않는 처리를 해야 하는거 같아서
아래와 같이 값을 구한다음에 처리를 해봤습니다.

 CSize size = GetTotalSize();  // 페이지의 총 사이즈(안보이는 부분까지 싹다)
 CRect clientRect;
 GetClientRect(&clientRect);    // 현재 화면에 보이는 클라이언트 정보

 CPoint scrollpos = GetScrollPosition();  // 스크롤 된 위치 좌측 상단
 CPoint devicescrollpos = GetDeviceScrollPosition();  // 디바이스별... 이건 위와 같네요(현재 상태에서는)

// 드로잉 간격을 10씩 했기 때문에 시작 지점을 보정해 줬습니다.
 CPoint startpos = CPoint(scrollpos.x%10, scrollpos.y%10);
 startpos.x = scrollpos.x - startpos.x;
 startpos.y = scrollpos.y - startpos.y;

// 시작지점과 클라이언트 영역을 사용해서 끝 점을 구했습니다.
 CPoint endpos = CPoint(scrollpos.x + clientRect.Width(), scrollpos.y + clientRect.Height());

드로잉은 아래와 같이 테스트...

 CRect rcBounds = CRect(0, 0, size.cx, size.cy);
 CMemDC pDCEx(pDC);
 pDCEx->FillRect(rcBounds, CBrush::FromHandle((HBRUSH)GetStockObject(WHITE_BRUSH)));

 for(int x = startpos.x; x < endpos.x; x += 10) {
  pDCEx->MoveTo(x, 0);
  pDCEx->LineTo(x, size.cy);
 }

 for(int y = startpos.y; y < endpos.y; y += 10) {
  pDCEx->MoveTo(0, y);
  pDCEx->LineTo(size.cx, y);
 }

이렇게 작업을 해서 안보이는 부분을 처리 했습니다.
처음 시작할때는 조금 딜레이가 있지만. 번쩍 거리는 현상의 거의 없어 지네요.
앞으로 복잡한 부분이 아닌 적당한 드로잉 방법에는 Flicker Free Drawing를 사용해야 겠습니다. ^^..


여기서 사용한 CMemDC는 아래 코드가 있습니다.




스크롤 테스트한 총 예제는 아래 코드..

Posted by gsi
:

웹 서비스 연동 방법 - <웹 서비스를 사용하다.!>

웹 서비스를 이용하면 응용 프로그램을 서버를 경유 하지 않고, 네트윅을 접근할 수 있다는 장점이 있습니다.
그래서 이번 프로젝트는 응용 프로그램 + 웹 서비스를 연동해서 어플리케이션을 제작할려고 합니다.
그 내용 중에서 웹 서비스 최초 연동 부분만 우선 살펴 보겠습니다.

웹 서비스를 제작하기 위해서 프로젝트를 생성합니다.
참고로 전 2008 beta2를 만지고 있어서 그쪽에서 했습니다.

사용자 삽입 이미지


ASP.NET Web Service 를 선택하고 File System, C#을 선택한 후에 프로젝트를 생성합니다.

테스트기 때문에 HelloWorld를 그대로 사용하겠습니다.

    [WebMethod]
    public string HelloWorld() {
        return "Hello World";
    }

이후에 서비스를 사용할 클라이언트를 만들어야 하는데요.
전 mfc로 싱글뷰를 사용했습니다.
내부에 MFC 확장 DLL을 사용해서 CDialog를 상속 받은 클래스를 하나 제작하고
그 쪽에서 웹 서비스를 연동해 봤습니다. (결과는 잘 되는군요.)

우선 웹 서비스를 참조 해야 하기 때문에 웹 서비스를 iis쪽에 등록 하시던지 간단하게
 테스트만 할 거라면 우선 디버그 상태로 뛰우게 되면 아래와 같은 임시 주소가 생기게 됩니다.
이거 보면서 참 편하다는 생각이 들었죠.

이 주소가 나왔으니 mfc 프로젝트에서 참조 추가를 해보겠습니다.
사용자 삽입 이미지
위와 같이 참조 라는 곳에서 "웹 참조 추가"를 선택 합니다.

사용자 삽입 이미지

이런 화면이 나오게 되는데요 여기서 URL 쪽에 아까 디버그로 실행한 웹 주소나 iis에 추가한
주소를 적어 주시고 "이동" 버튼을 누르면 해당 내용이 나오게 됩니다.
웹 참조 이름은 다르게 수정이 가능합니다.

"참조 추가" 버튼을 누르면 프로젝트에 포함이 됩니다.
사용자 삽입 이미지
이런 몇개의 파일이 자동으로 생성되게 됩니다.
이제 이것을 사용하기 위해서 우선 클래스 상태를 보기 위해서 "개체 브라우저"를 엽니다.
사용자 삽입 이미지
위와 같이 LoginSvr 이라는 네임 스페이스와 CLoginSvr 이라는게 보입니다.
CLoginSvr은 아래와 같이 typedef 되어 있네요.

typedef class LoginSvr::CLoginSvrT<> CLoginSvr
    LoginSvr의 멤버

이제 사용하는 방법만 남았네요.
아래와 같이 사용해서 처리 하시면 됩니다.

LoginSvr::CLoginSvr svr;
BSTR bstrStatus2;
svr.HelloWorld(&bstrStatus2);
m_szEdit = bstrStatus;
::SysFreeString( bstrStatus2 );
UpdateData(false);

여기서 보면 C#이나 asp.net 쪽의 프로그램과는 좀 불편한 감이 있네요.
HelloWorld()의 형태가 인자가 없고 리턴을 string 형태로 받게 되어 있지만
mfc 쪽에서 사용할때는 인자 형태의 포인터로 받게 되어 있으며 stringBSTR 형태로
 취환이 되어서 처리 되게 되어 있습니다.

아.. 이 내용은 대충 여기까지..
앞으로 작업 하면서 여러가지 문제점에 봉착할거 같은데요. 우선 세세하게 작업 내용들을 올리도록 할께요 ^^.
Posted by gsi
:

CDialog를 서브클래싱 해서 다른 컨트롤에 적용할려고 할때 보통 Create를 오버라이드 해서 사용하게 되는데 이때 보면 Create의 원형은 아래와 같습니다.

BOOL CGDialog::Create(LPCTSTR lpszTemplateName, CWnd* pParentWnd)
{
 return CDialog::Create(lpszTemplateName, pParentWnd);
}


하지만 여기서 보면 Dialog 니까. Dialog의 아이디를 넣으면 되겠지 하지만 이건 int 형을 LPCTSTR형으로 바꿀수 없다는 에러만 발생하게 됩니다. (솔직히 TemplateName라는게 어떤건지 잘 모르겠습니다.

하지만 우리가 알고 있는 Dialog의 아이디 값을 LPCTSTR형으로 바꾸어 주는 함수를 사용하면 됩니다.

보통 다른 컨트롤에서 생성하기 때문에 Create를 하나더 만듭니다.
왜냐하면 굳이 아이디 값을 노출하거나 더 적어줄 필요가 없으니 아래와 같이 함수를 만들면 될듯합니다.

BOOL CGDialog::Create(CWnd* pParentWnd)
{
 return Create(MAKEINTRESOURCE(IDD_GDIALOG), pParentWnd);
}


여기서 보는바와 같이 MAKEINTRESOURCE 라는 디파인 문을 사용하면 LPCTSTR형태로 변환해 주면 가능합니다.

위의 함수를 다른 컨트롤 쪽에서 아래와 같이 사용하면 해당 컨트롤에 추가해서 사용할 수 있습니다.

 m_Dialog.Create(this);
 m_Dialog.ShowWindow(SW_SHOW);
 m_Dialog.MoveWindow(CRect(200, 200, 400, 400));


[팁]
다이얼로그의 스타일이 3가지가 있는데요. Overlapped, PopUp, Child 형태가 있습니다.
Overlapped, PopUp 형태로 하게 되면 컨트롤에 추가 되지만 컨트롤 안에 종속되지는 않네요. 밖으로 이동이 가능하게 되는데요 꼭, 모달 다이얼로그와 비슷한 형태인듯 합니다.
그리고 Child 형태로 하게 되면 컨트롤 내부에서만 동작을 하게 되네요.

이때 타이틀바가 나오거나 안나오거나 상관 없이 동작하게 됩니다.

Posted by gsi
:

사용자 삽입 이미지

MFC 에서 싱글뷰로 해서 Doc 없애고, CChildView로만 생성했습니다.
내부에 Static, Button을 서브클래싱 해서 클래스를 각각 제작.

CChildView 내부에 멤버 변수로 선언
CGStatic m_Static;
CGButton m_Button;


OnCreate 함수를 오버라이드 하여 컨트롤을 생성합니다.
int CChildView::OnCreate(LPCREATESTRUCT lpCreateStruct)
{
 if (CWnd::OnCreate(lpCreateStruct) == -1)
  return -1;

 m_Static.Create("test", WS_CHILDWINDOW|SS_NOTIFY, CRect(10, 10, 100, 100), this, 1000);
 m_Static.ShowWindow(SW_SHOW);

 m_Button.Create("", WS_CHILDWINDOW, CRect(100, 100, 200, 200), this, 1001);
 m_Button.ShowWindow(SW_SHOW);

 return 0;
}


CStatic 컨트롤의 마우스 이벤트를 먹게 할려면 SS_NOTIFY를 추가해야 합니다.

CStatic, CButton의 마우스 이벤트 코드는 동일하기 때문에 CButton 의 내용만 서술합니다.
이전 위치를 기억 하기 위해서 변수를 하나 생성
CPoint  oldPos;

생성자 쪽에서 초기화를 해줍니다.
oldPos = CPoint(0, 0);

나머지 OnLButtonDown, OnLButtonUp, OnMouseMove 이벤트를 추가하고
아래와 같이 작성해 줍니다.
void CGButton::OnLButtonDown(UINT nFlags, CPoint point)
{
 SetCapture();
 
 // 최초 위치를 oldpos에 입력하고 시작한다.
 CPoint curpos;
 GetCursorPos(&curpos);
 GetParent()->ScreenToClient(&curpos);
 oldPos = curpos;

 CButton::OnLButtonDown(nFlags, point);
}

void CGButton::OnLButtonUp(UINT nFlags, CPoint point)
{
 ReleaseCapture();
 CButton::OnLButtonUp(nFlags, point);
}

void CGButton::OnMouseMove(UINT nFlags, CPoint point)
{
 if(GetCapture() == this) {

  // 현재 컨트롤이 포함되어 있는 부모 컨트롤에서의 위치값을 가져온다.
  CRect thisRect;
  GetWindowRect(&thisRect);
  GetParent()->ScreenToClient(&thisRect);

  // 현재 마우스 위치값을 컨트롤의 위치 값으로 변환한다.
  CPoint curpos;
  GetCursorPos(&curpos);
  GetParent()->ScreenToClient(&curpos);

  // 변경된 위치값을 사용해서 이동범위를 구한다.
  CPoint newpos = curpos - oldPos;

  // 이동할 위치와 크기값을 보정한다.
  thisRect.left += newpos.x;
  thisRect.top += newpos.y;
  thisRect.right = thisRect.left+100;
  thisRect.bottom = thisRect.top+100;
 
  // 윈도우를 이동시킨다.
  MoveWindow(&thisRect);

  // 계속 움직임을 위해서 현재 값을 저장한다.
  oldPos = curpos;

  Invalidate();
 }

 CButton::OnMouseMove(nFlags, point);
}

Posted by gsi
:

버튼을 CView에 추가..

 m_Button.Create("", WS_CHILDWINDOW, CRect(50, 100, 150, 200), this, 1001);
 m_Button.ShowWindow(SW_SHOW);


그리고 버튼 내부에 클릭 이벤트를 통해서 해당 위치에 버튼을 MoveWindow 시켜보자.

void CGButton::OnLButtonUp(UINT nFlags, CPoint point)
{
 CPoint curpos;
// 커서의 스크린 위치를 가져온다.
 GetCursorPos(&curpos);
// 부모 객체에서의 스크린 좌표를 클라이언트 좌표로 바꾼다.
 GetParent()->ScreenToClient(&curpos);
// 좌표값을 사용해서 윈도우의 크기를 지정한다.
 CRect rt(curpos.x, curpos.y, curpos.x+100, curpos.y+100);
// 자신 객체를 이동시킨다.
 MoveWindow(&rt);

 CButton::OnLButtonUp(nFlags, point);
}


이 코드가 완성되었으니. 클릭후 드래그로 컨트롤을 View에서 이동가능할듯 하다. ^^
(아마도 다 아는거겠지만. 요즘 mfc에 대해서 조금씩 방법적인 면이 늘어 나는거 같다.)

Posted by gsi
:

[MFC] 폴더 경로 얻기

C++ 2007. 12. 12. 14:23 |

사용자 삽입 이미지

 ITEMIDLIST      *pidlBrowse;
 char                  pszPathname[MAX_PATH];

 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)
 {
  // 패스를 얻어옴
  BOOL bSuccess = ::SHGetPathFromIDList(pidlBrowse, pszPathname);

  if ( bSuccess )
  {
   m_szSafedefaultPath = pszPathname;   //<-- 여기서 값을 입력
   UpdateData(FALSE);
  }
  else
  {
   MessageBox("잘못된 폴더명입니다.", "lol", MB_OKCANCEL|MB_ICONASTERISK );
  }
 }

Posted by gsi
:

// 프로젝트 생성
MFC Extension DLL 을 체크 하고 생성한다.

// DLL 내부에서 class 생성할때
class AFX_EXT_CLASS CTest : public CDialog
이런 형태로 앞에 AFX_EXT_CLASS 를 추가한다.

// 해당 프로젝트에서 사용할때.
*.h, *.lib를 추가한다.
*.dll을 실행파일과 같은 경로 또는 시스템 폴더에 추가한다.
나머지 사용시에는 일반 클래스와 같이 동작한다.

이건. mfc에서 확장해서 리소스 및 다이얼로그 등등.. 모든 자원을 dll로 뺀 다음에
사용이 가능한듯 보인다.
Posted by gsi
: