FTP는 파일전송규약입니다.

웹호스팅을 하거나 업로드 다운로드 등에 사용됩니다.


보통은 그냥 상용화된 프로그램을 쓰지만..

개발을 하다보면 좀 더 특성화된 프로그램이 필요로 합니다.

그럴 땐.. FTP을 까야죠. 


깊이 깊이 까다보면 아~~~

Socket으로 명령어를 보내고 결과를 읽고~

fopen으로 파일을 열고~  바이너리로 파일을 보내고~

여러가지 경험을 하게 됨과 동시에~

우리가 쓰는 알FTP, FileZiller 등에 위대함을 느끼지요 ㅎㅎ


출처는 위키백과 입니다.


명령어 RFC 설명
ABOR 현재의 파일 전송 중단.
ACCT 계정 정보.
ADAT RFC 2228 인증/보안 데이터
ALLO 파일을 받기 위해 충분한 디스크 공간 할당.
APPE 이어서 추가.
AUTH RFC 2228 인증/보안 구조
CCC RFC 2228 명령 채널 지우기
CDUP 부모 디렉터리로 변경.
CONF RFC 2228 기밀 보호 명령
CWD 작업 디렉터리 변경
DELE 파일 삭제
ENC RFC 2228 개인 정보 보호 채널
EPRT RFC 2428 서버 접속에 필요한 확장 주소 및 포트 지정.
EPSV RFC 2428 확장 수동 모드 들어가기.
FEAT RFC 2389 서버가 추가한 기능 목록 보기
LANG RFC 2640 언어 탐색
LIST 지정한 경우 파일이나 디렉터리 정보를 반환. 지정하지 않은 경우 현재 작업 디렉터리 정보 반환.
LPRT RFC 1639 서버 접속에 필요한 긴 주소 및 목록 지정.
LPSV RFC 1639 긴 수동 모드 들어가기
MDTM RFC 3659 지정한 파일의 마지막으로 수정한 시간 반환
MIC RFC 2228 무결성 보호 명령
MKD 디렉터리 만들기
MLSD RFC 3659 디렉터리의 이름이 지정되면 디렉터리의 내용을 보여줌
MLST RFC 3659 명령 줄에 입력한 데이터만 제공.
MODE 전송 모드 설정 (스트림, 블록, 압축)
NLST 지정한 디렉터리의 파일 이름 목록 반환.
NOOP 동작 안 함 (더미 패킷: 대개 회선이 살아있는지를 살피기 위해 쓰임)
OPTS RFC 2389 기능 옵션 선택.
PASS 암호.
PASV 수동 모드 들어가기.
PBSZ RFC 2228 보호 버퍼 크기
PORT 서버 접속에 필요한 주소 및 포트 지정.
PROT RFC 2228 데이터 채널 보호 수준.
PWD 작업 디렉터리 인쇄. 호스트 컴퓨터의 현재 디렉터리 반환.
QUIT 연결 끊기.
REIN 연결 다시 초기화.
REST 지정한 지점에서 전송 다시 시작.
RETR 파일 복사본 전송
RMD 디렉터리 제거
RNFR 이름 변경 원본 이름
RNTO 이름 변경 대상 이름
SITE 지정한 명령어를 원격 서버로 송신.
SIZE RFC 3659 파일 크기 반환
SMNT 파일 구조 마운트.
STAT 현재 상태 반환.
STOR 데이터 입력 및 서버 쪽 파일로 저장.
STOU 파일을 저만의 방식으로 저장.
STRU 전송 구조 설정.
SYST 시스템 유형 반환.
TYPE 전송 모드 설정 (ASCII/바이너리).
USER 인증 사용자 이름.


https://ko.wikipedia.org/wiki/FTP_%EB%AA%85%EB%A0%B9%EC%96%B4_%EB%AA%A9%EB%A1%9D

Posted by +깡통+

1>------ 빌드 시작: 프로젝트: HMFS, 구성: Release x64 ------
1>링크하고 있습니다...
1>HMFS.obj : error LNK2001: "public: __cdecl CWinAppEx::CWinAppEx(int)" (??0CWinAppEx@@QEAA@H@Z) 외부 기호를 확인할 수 없습니다.
1>HMFS.obj : error LNK2001: "public: virtual __cdecl CWinAppEx::~CWinAppEx(void)" (??1CWinAppEx@@UEAA@XZ) 외부 기호를 확인할 수 없습니다.
1>HMFS.obj : error LNK2001: "public: virtual struct CRuntimeClass * __cdecl CWinAppEx::GetRuntimeClass(void)const " (?GetRuntimeClass@CWinAppEx@@UEBAPEAUCRuntimeClass@@XZ) 외부 기호를 확인할 수 없습니다.
1>HMFS.obj : error LNK2001: "public: virtual int __cdecl CWinAppEx::ExitInstance(void)" (?ExitInstance@CWinAppEx@@UEAAHXZ) 외부 기호를 확인할 수 없습니다.
1>HMFS.obj : error LNK2001: "public: virtual int __cdecl CWinAppEx::LoadState(wchar_t const *,class CFrameImpl *)" (?LoadState@CWinAppEx@@UEAAHPEB_WPEAVCFrameImpl@@@Z) 외부 기호를 확인할 수 없습니다.
1>HMFS.obj : error LNK2001: "public: virtual int __cdecl CWinAppEx::CleanState(wchar_t const *)" (?CleanState@CWinAppEx@@UEAAHPEB_W@Z) 외부 기호를 확인할 수 없습니다.
1>HMFS.obj : error LNK2001: "public: virtual int __cdecl CWinAppEx::SaveState(wchar_t const *,class CFrameImpl *)" (?SaveState@CWinAppEx@@UEAAHPEB_WPEAVCFrameImpl@@@Z) 외부 기호를 확인할 수 없습니다.
1>HMFS.obj : error LNK2001: "public: virtual int __cdecl CWinAppEx::OnViewDoubleClick(class CWnd *,int)" (?OnViewDoubleClick@CWinAppEx@@UEAAHPEAVCWnd@@H@Z) 외부 기호를 확인할 수 없습니다.
1>HMFS.obj : error LNK2001: "public: virtual int __cdecl CWinAppEx::ShowPopupMenu(unsigned int,class CPoint const &,class CWnd *)" (?ShowPopupMenu@CWinAppEx@@UEAAHIAEBVCPoint@@PEAVCWnd@@@Z) 외부 기호를 확인할 수 없습니다.
1>HMFS.obj : error LNK2001: "public: virtual void __cdecl CWinAppEx::OnAppContextHelp(class CWnd *,unsigned long const * const)" (?OnAppContextHelp@CWinAppEx@@UEAAXPEAVCWnd@@QEBK@Z) 외부 기호를 확인할 수 없습니다.
1>HMFS.obj : error LNK2001: "protected: virtual void __cdecl CWinAppEx::OnClosingMainFrame(class CFrameImpl *)" (?OnClosingMainFrame@CWinAppEx@@MEAAXPEAVCFrameImpl@@@Z) 외부 기호를 확인할 수 없습니다.
1>HMFS.obj : error LNK2001: "protected: virtual int __cdecl CWinAppEx::LoadWindowPlacement(class CRect &,int &,int &)" (?LoadWindowPlacement@CWinAppEx@@MEAAHAEAVCRect@@AEAH1@Z) 외부 기호를 확인할 수 없습니다.
1>HMFS.obj : error LNK2001: "protected: virtual int __cdecl CWinAppEx::StoreWindowPlacement(class CRect const &,int,int)" (?StoreWindowPlacement@CWinAppEx@@MEAAHAEBVCRect@@HH@Z) 외부 기호를 확인할 수 없습니다.
1>HMFS.obj : error LNK2001: "protected: virtual int __cdecl CWinAppEx::ReloadWindowPlacement(class CFrameWnd *)" (?ReloadWindowPlacement@CWinAppEx@@MEAAHPEAVCFrameWnd@@@Z) 외부 기호를 확인할 수 없습니다.
1>D:\project\vc80\HMFS\x64\Release\HMFS.exe : fatal error LNK1120: 14개의 확인할 수 없는 외부 참조입니다.
1>빌드 로그가 "file://d:\project\vc80\HMFS\HMFS\x64\Release\BuildLog.htm"에 저장되었습니다.
1>HMFS - 오류: 15개, 경고: 0개
========== 빌드: 성공 0, 실패 1, 최신 0, 생략 0 ==========

 

이러한 오류가 났다.

분명히 지난번에 정상적으로 컴파일 한 소스임이 틀림 없는데...

 

기억을 되듬어보니 VS2008 를 패치 했었다. 

컴파일 플랫폼 선택에서 x64가 나타나지 않았기 때문이다.

다시 Win32 를 선택해주니 정상적인 컴파일이 되었다.

 

조금은 사소한것 같지만 소스 수정을 잘못한줄 알고 디버깅(되돌리기)을 얼마나 했던가 -_-;

결국 원본 자체가 컴파일 안되는걸 모르고 몇 시간 허비했다.

Posted by +깡통+

도구->옵션->디렉토리 에서 각각 컴파일에서 참조할 폴더를 지정하는 방법.


또는 StdAfx.h 파일에다가 참조할 헤더파일과 라이브러리를 지정하는 방법.

아시겠지만 DLL 참조시 lib 파일이 함께 필요합니다.

DLL 파일은 EXE 파일이 실행될때 필요 한 것일뿐이고 Lib 파일은 컴파일시 링크때 필요한 파일 입니다.



#pragma comment(lib, "./Others/Libs/xxx.lib")

#pragma comment(lib, "./Others/Libs/xxx2.lib")



위 코드는 VC6.0, VC9.0 (2008) 에서 적용했습니다.


Posted by +깡통+
1.2Mb 나 되는 데이터를 읽어들였다.
1296 x 964 정도 되는 이미지 파일인데 처리를 위해서는 2차원 배열이 필요 했다.

 int cols=1296, rows=964;
 unsigned char *p  = new unsigned char [rows * cols];
 unsigned char (*pdata)[1296] = (unsigned char (*)[1296])p;   // 여기서 [] 안의 값은 1차 배열의 크기를 뜻한다.

즉..  처리 후에는 pdata[964][1296]  가 생기는 것이다.  ^^

 FILE *fp;
 fp = fopen("1.RAW", "rb");
 fread(p, 1, cols * rows, fp);



참고 자료 : http://blog.naver.com/yonguk6726/30084714204
Posted by +깡통+
※ WM_SYSCOMMAND → WM_CLOSE → WM_DESTROY → WM_QUIT




1. WM_CLOSE
   - 윈도우가 닫히기 전에 메시지가 전달 된다.
   - 아직 윈도우가 파괴된 것은 아니므로 윈도우가 파괴되는 것을 중간에 제어 할 수 있다.
   - 윈도우의 “닫기” 를 누르거나, 키보드의 “Alt + F4”를 눌렀을 경우 발생



   - WM_CLOSE 의 핸들러(OnClose) 에서 추가적인 제어를 하지 않는다면 메시지는
      DefWindowsProc 로 보내진다.
   - CDialog::OnClose() 는 내부적으로 DestroyWindow() 함수를 호출 한다.
   - DestroyWindow() 함수는 내부적으로 WM_DESTROY 메시지를 발생 시킨다.


2. DestroyWindow()
   - CWnd내부에 있는 윈도우를 destroy 한다.
   - 윈도우를 해제하고 입력 포커스를 제거하기 위한 적절한 message를 윈도에게 보낸다.
   - 윈도우의 메뉴 제거 
   - application queue를 비운다.
   - timer를 제거
   - Clipboard의 소유주 제거
   - Clipboard-viewer chain을 끊는다. ( CWnd가 viewer chain의 맨 위에 있을 경우 )
   - WM_DESTROY(OnDestroy)와 WM_NCDESTROY(OnNcDestroy) 메시지를 윈도우 에게 보낸다.
     하지만 아직 CWnd 객체는 destroy하지 않는다.


3. WM_DESTROY
   - Framework이 CWnd에게 현재 CWnd가 소멸되고 있는 중이라고 알려 주기 위하여 호출 
   - 화면에 윈도우를 숨긴 후 메시지 발생, 아직 윈도우 자체는 파괴되지 않았다
   - DestroyWindows() 함수에서 발생 시킨다.
   - WM_CREATE 에 반대되는 동작을 수행 한다.
   - 차일드 윈도우가 있다면 이 메시지를 차례대로 전달 한다.
   - 메인 윈도우에서 PostQuitMessage() 함수를 반드시 호출하여 프로세스의 메시지 루프
     를 종료시켜야 한다. 그렇지 않다면 윈도우만 파괴되고 메시지 루프는 계속 실행중인
     상태가 되므로 프로세스가 종료되지 않는다.


4. WM_NCDESTROY
   - Client 영역이 아닌 영역이 Destroy 될 때 Framework 에 의하여 불려짐.
   - 윈도우가 소멸될 때 마지막으로 호출되는 메시지
   - 핸들러를 재정의 한다면 기본 호출 함수를 가장 위에서 해주자.

  
5. PostNcDestroy()
   - 윈도우가 소멸된 후 OnNcDestroy() 함수에 의해 불려지는 함수
   - 사용자들이 상속받아 만든 클래스의 정리를 위한 코드를 넣음.


6. View가 닫혀질 때 호출되는 핸들러 순서
BOOL CAniView::DestroyWindow()
{
 
// TODO: Add your specialized code here and/or call the base class
// 윈도우가 안보여 지기전에 해야 할 작업 처리
 
 return CView::DestroyWindow();
 
}
 
void CAniView::OnDestroy()
{
 
  CView::OnDestroy();
 
  // TODO: Add your message handler code here
 
}
 
void CAniView::PostNcDestroy()
{
 
  // TODO: Add your specialized code here and/or call the base class
 
  CView::PostNcDestroy();
 
}


7. WM_QUIT
   - 응용프로그램을 종료 하라는 메시지
   - PostQuitMessage() 가 발생 시키는 메시지
   - GetMessage() 함수가 0 을 리턴하도록 함으로써 메시지 루프를 종료
   - PeekMessage() 함수는 따로 WM_QUIT 메시지를 점검해야 한다.



자료 출처 : http://six605.tistory.com/257

Posted by +깡통+

 static const unsigned int maxNum = 16;
 GLuint m_image[maxNum];


 error C2258: illegal pure syntax, must be '= 0'
 error C2252: 'maxNum' : pure specifier can only be specified for functions
 error C2065: 'maxNum' : undeclared identifier
 error C2057: expected constant expression
 warning C4200: nonstandard extension used : zero-sized array in struct/union


이거 하나로 에러가 무진장 생기네요.
일단 원인 파악중...
말 그대로...  정적 상수 부호없는 정수 maxNum    ㅋㅋㅋ

문제해결!!  위 코드는 VS2005 에서는 잘 돌아가지만 VC++ 6.0 에서는 안됩니다.

클래스 선언과 변수 초기화는 동시에 불가능 하기 때문인데..
열거형 초기화는 가능합니다.
그래서 아래와 같이 변경하면 잘 됩니다 ^^

enum { maxNum = 16 };




Posted by +깡통+
다시 오래간만에 VS2005 (MFC)를 하게 되었습니다.
약 2년을 쉬었는데 -_- 다시 하려니 머리가 썩었나봐요..

warning C4819: 현재 코드 페이지(949)에서 표시할 수 없는 문자가 파일에 들어 있습니다. 데이터가 손실되지 않게 하려면 해당 파일을 유니코드 형식으로 저장하십시오.

해결방법
메뉴 -> 프로젝트 -> 속성 -> 구성속성 -> C/C++ -> 고급 -> 특정 경고 사용안함    항목에다가..

4819 라고 적어줍니다.
추가로 더 적을땐..   다음줄에 적으시던지 아래 방법으로 ^^
4819;4996
Posted by +깡통+
출처 : http://ultrasoo.linuxtop.co.kr/bbs/view.php?id=mfc&no=7
 
MFC 소켓 프로그래밍을 하기 위해서는 처음에 프로젝트를 생성할 때 MFC 응용 프로그램
마법사(MFC application wizard)에서 “Windows 소켓” 옵션을 선택해야 한다고 했다. 그런데
만약 이 옵션을 선택하지 않고 프로젝트를 생성했는데, 나중에 네트워크 프로그램을 추가해야 할
경우엔 어떻게 해야 할까?
처음에 “Windows 소켓”을 선택하지 않았다고 해서 프로젝트를 새로 만들고 코드를 복사해 넣는
수고를 할 필요는 없다. 사실 MFC 애플리케이션 위저드에서 “Windows 소켓” 옵션을 체크했을
때 추가되는 코드는 매우 간단한 것이다. 단지 하나의 함수를 호출해주는 코드를 삽입해 줄 뿐이다.
MFC 소켓을 사용하기 위해서는 AfxSocketInit이라는 함수를 먼저 호출해 주어야 한다. MFC
애플리케이션 위저드에서 “Windows 소켓” 옵션을 체크했을 때 추가되는 코드는
AfxSocketInit 함수를 호출해주는 코드를 삽입하는 것 뿐이다.
일반적으로 그 코드가 삽입되기에 가장 적절한 곳은 CWinApp 클래스를 상속받은 여러분의
클래스 파일의 InitInstance 함수 내에서이다. 만약 여러분이 생성한 프로젝트의 이름이
Test라면 CTestApp라는 클래스가 구현되어 있을 것이며, 그 클래스의 구현 파일(.cpp)에는
InitInstance 멤버 함수가 정의되어 있을 것이다. 이 함수 내에서 AfxSocketInit 함수를
호출하도록 코드를 넣어주면 된다.
아마 MFC 애플리케이션 위저드는 다음과 같은 코드를 자동으로 넣어줄 것이다.
if (!AfxSocketInit())
{
AfxMessageBox(IDP_SOCKETS_INIT_FAILED);
return FALSE;
}
IDP_SOCKETS_INIT_FAILED라는 상수는 string table에 있는 문자열인데, “Windows 소켓
을 초기화하지 못했습니다.”라는 문자열을 가리킨다. 따라서 여러분이 MFC 애플리케이션 위저드
에서 “Windows 소켓”을 선택하지 않고 직접 AfxSocketInit 함수를 호출해주려면
IDP_SOCKETS_INIT_FAILED 대신 “AfxSocketInit 호출에 실패했습니다.”와 같이 적절한
문자열을 직접 넣어주면 될 것이다.

참고로..
stdafx.h 파일에

#include <afxsock.h>  // MFC 소켓 확장

라인을 삽입해야한다~
Posted by +깡통+
error C2146: 구문 오류 : ';'이(가) 'PVOID64' 식별자 앞에 없습니다.
 
이렇게 되어 있던것을
typedef void *PVOID;
typedef void * POINTER_64 PVOID64;   
 
아래처럼 바꾸자.
typedef void* PVOID;
typedef void* POINTER_64;
typedef POINTER_64 PVOID64;

Posted by +깡통+

아래의 주소에서 다운받자

http://www.microsoft.com/msdownload/platformsdk/sdkupdate/psdk-full.htm

Posted by +깡통+

CButton 을 상속받는 클래스를 만들어 처리합니다.


// MSNButton.cpp : 구현 파일입니다.
//

#include "stdafx.h"
#include "ImageButton.h"
#include "MSNButton.h"


// CMSNButton

IMPLEMENT_DYNAMIC(CMSNButton, CButton)

CMSNButton::CMSNButton()
{
 m_bTracking = FALSE;
 m_bHover = FALSE;
}

CMSNButton::~CMSNButton()
{
}


BEGIN_MESSAGE_MAP(CMSNButton, CButton)
 ON_WM_DRAWITEM()
 ON_MESSAGE(WM_MOUSELEAVE, OnMouseLeave)
 ON_MESSAGE(WM_MOUSEHOVER, OnMouseHover)
 ON_WM_MOUSEMOVE()
END_MESSAGE_MAP()

 

// CMSNButton 메시지 처리기입니다.

void CMSNButton::DrawItem(LPDRAWITEMSTRUCT lpDrawItemStruct)
{

 // TODO:  지정된 항목을 그리는 코드를 추가합니다.
 CDC* pDC = CDC::FromHandle(lpDrawItemStruct->hDC);
 CDC MemDC;
 MemDC.CreateCompatibleDC(pDC);

 BITMAP bmpInfo;
 CBitmap Bmp;
 CBitmap* pOldBitmap = NULL;
 Bmp.LoadBitmapW(IDB_BITMAP1);
 Bmp.GetBitmap(&bmpInfo);

 pOldBitmap = MemDC.SelectObject(&Bmp);

 // 버튼이 선택되었는가?
 if(lpDrawItemStruct->itemState & ODS_SELECTED)
 {
  // 세번째 버튼 이미지 출력
  pDC->BitBlt(0,0,bmpInfo.bmWidth, bmpInfo.bmHeight, &MemDC, 206, 0, SRCCOPY);
 }
 else
 {
  // 마우스 포인터가 버튼 위에 존재하는가?
  if(m_bHover)
  {
   // 두번째 버튼 이미지 출력!
   pDC->BitBlt(0,0, bmpInfo.bmWidth, bmpInfo.bmHeight, &MemDC, 103, 0, SRCCOPY);
   //pDC->BitBlt(0,0, bmpInfo.bmWidth, bmpInfo.bmHeight, &MemDC, 50, 0, SRCCOPY);
  }
  else
  {
   // 첫번째 버튼 이미지 출력!
   pDC->BitBlt(0,0, bmpInfo.bmWidth, bmpInfo.bmHeight, &MemDC, 0, 0, SRCCOPY);
  }
 }

 MemDC.SelectObject(pOldBitmap);
}

void CMSNButton::OnMouseMove(UINT nFlags, CPoint point)
{
 // TODO: 여기에 메시지 처리기 코드를 추가 및/또는 기본값을 호출합니다.
 
 // 마우스 트래킹이 시작되었는가???
 if(!m_bTracking)
 {
  TRACKMOUSEEVENT tme;
  tme.cbSize = sizeof(tme);
  tme.hwndTrack = m_hWnd;
  tme.dwFlags = TME_LEAVE | TME_HOVER;
  tme.dwHoverTime = 1;
  m_bTracking = _TrackMouseEvent(&tme);
 }
 
 CButton::OnMouseMove(nFlags, point);
}

LRESULT CMSNButton::OnMouseHover(WPARAM wparam, LPARAM lparam)
{
 // 마우스 포인터가 버튼 위에서 움직이고 있음.
 m_bHover = TRUE;
 RedrawWindow();
 return 0;
}

LRESULT CMSNButton::OnMouseLeave(WPARAM wparam, LPARAM lparam)
{
 // 마우스 포인터가 버튼 밖으로 나갔음.
 m_bTracking = FALSE;
 m_bHover = FALSE;
 RedrawWindow();
 return 0;
}


출처 : Windows MFC 정복 (가남사)

Posted by +깡통+

TRACKMOUSEEVENT 구조체

 희한하게 검색해보니, TRACKMOUSEEVENT구조체를 이용하는 팁이 하나도 안올라와 있더군요. 그래서 팁 비슷하게 올려봅니다.
예를 든다면, 윈도우에서 마우스 포인터의 위치가 클라이언트에 있는지 아닌지를 알려주는 간단한 팁입니다.
일단 TRACKMOUSEEVENT 구조체를 보면 다음과 같이 정의 되어 있습니다.

typedef struct tagTRACKMOUSEEVENT {
    DWORD cbSize; // 구조체의 크기
    DWORD dwFlags; // TME_HOVER, TME_LEAVE등 지정할 수 있다.
    HWND  hwndTrack; // 실지로 이벤트를 받을 윈도우 핸들
    DWORD dwHoverTime; // 밀리세칸단위의 hover 타임아웃을 지정한다.
} TRACKMOUSEEVENT, *LPTRACKMOUSEEVENT; 

사용할 함수는 BOOL _TrackMouseEvent(LPTRACKMOUSEEVENT lptrack);
윈도우 95에서는 안되고, 98이상에서만 되고, NT에서는 당근이 됩니다.

그럼 간단하게 예를 들어보겠습니다. 
먼저 WM_MOUSEMOVE 이벤트를 정의합니다.
int m_Flag = 1;

..CMyDlg::OnMouseMove(...)
{
    MouseEvent(); //새로 정의할 함수입니다.
}

void CMyDlg::MouseEvent()
{
   TRACKMOUSEEVENT tme;
   tme.cbSize = sizeof(TRACKMOUSEEVENT);
   if(m_Flag == 0)  tme.dwFlags = TME_LEAVE;
   else tme.dwFlags = TME_HOVER;
   tme.hwndTrack = m_hWnd; // 현재 자신의 윈도우 핸들 지정
   tme.dwHoverTime = 10; //10 밀리세칸으로 지정

   _TrackMouseEvent( &tme );
}

여기서 tme.dwFlags=TME_HOVER 이렇게 정의해놓으면, 즉 마우스가 클라이언트영역으로 들어올때, WM_MOUSEHOVER 이벤트를 발산시킵니다. 발산? 그럼 여기에 맞게, 이벤트 부분을 정의합니다.
먼저 헤더에 다음과 같이 정의합니다.
afx_msg UINT OnMouseHover(WPARAM, LPARAM);
그리고 cpp에다가 ON_MESSAGE(WM_MOUSEHOVER, OnMouseHover)
이렇게 선언합니다.
그리고, 함수를 정의합니다.

UINT MyDlg::OnMouseHover(WPARAM, LPARAM)
{
   m_Flag = 0;
   m_edit.ShowWindow(TRUE);
   return 0;
}
마찬가지로 OnMouseLeave도 같은 방식으로 정의해줍니다.
UINT MyDlg::OnMouseLeave(WPARAM, LPARAM)
{  m_Flag = 1;
   m_edit.ShowWindow(FALSE);
   return 0;
}
위와 같이 정의하시고, 컴파일해보십시오.
아마 클라이언트로 마우스가 위치되면, 에디트박스가 보이고
그렇지 않으면, 에디트가 사라질겁니다.
반응속도도 빠르고, 깜빡임도 없고, 무리없이 잘돌아가더군요.
이걸로, hotButton기능을 구현해봐도 되겠더라고요.
참고로 SetCapture, ReleaseCapture도 이런 기능을 충분히 구현해주지만, 모든 이벤트를 잡아먹어버리는 그런식의 기능은 않습니다. 참 편리합니다만 더 나은 방법이 있으면, 더 글을 올려주세요.

 

http://www.devpia.com/Forum/BoardView.aspx?no=1025&ref=545&forumname=VC_LEC&stype=VCF&KeyW=TRACKMOUSEEVENT&KeyR=titlecontent

Posted by +깡통+

1>d:\vc2005\mfcexam\modaless\modaless\modalessdlg.h(34) : error C2143: 구문 오류 : ';'이(가) '*' 앞에 없습니다.
1>d:\vc2005\mfcexam\modaless\modaless\modalessdlg.h(34) : error C4430: 형식 지정자가 없습니다. int로 가정합니다. 참고: C++에서는 기본 int를 지원하지 않습니다.
1>d:\vc2005\mfcexam\modaless\modaless\modalessdlg.h(34) : error C4430: 형식 지정자가 없습니다. int로 가정합니다. 참고: C++에서는 기본 int를 지원하지 않습니다.



이러한 에러가 발생하였다.
이것은 서로 다른 클래스가 서로를 참조하고 있을때 발생한다.
따라서 이런경우 해결책은 '전방참조'라고 하는 방법을 사용한다.

어느 한쪽의 클래스 선언문 위에 다른 클래스의 이름을 적어준다.


// ModalessDlg.h : 헤더 파일
//

#pragma once
#include "childdlg.h"

class CChildDlg; // 전방참조

// CModalessDlg 대화 상자
class CModalessDlg : public CDialog
{
// 생성입니다.
public:
 CModalessDlg(CWnd* pParent = NULL); // 표준 생성자입니다.

// 대화 상자 데이터입니다.
 enum { IDD = IDD_MODALESS_DIALOG };

 protected:
 virtual void DoDataExchange(CDataExchange* pDX); // DDX/DDV 지원입니다.


// 구현입니다.
protected:
 HICON m_hIcon;

 // 생성된 메시지 맵 함수
 virtual BOOL OnInitDialog();
 afx_msg void OnSysCommand(UINT nID, LPARAM lParam);
 afx_msg void OnPaint();
 afx_msg HCURSOR OnQueryDragIcon();
 DECLARE_MESSAGE_MAP()
public:
 CChildDlg *m_pDlg;
public:
 afx_msg void OnBnClickedShowDialog();
};

Posted by +깡통+
부모창의 클래스 선언부에서 아래와 같이 포인트 변수를 추가해야한다.
public:
 CChildDlg *m_pDlg;

어떠한 버튼을 클릭하면 모달리스 창을 띄우는데..
주의할것은 NULL 체크를 하지 않으면 새로운 창이 여러개 생긴다는 것이다.


void CModalessDlg::OnBnClickedShowDialog()
{
 // TODO: 여기에 컨트롤 알림 처리기 코드를 추가합니다.
 if(m_pDlg != NULL)
  m_pDlg->SetFocus();
 else {
  m_pDlg = new CChildDlg;
  m_pDlg->Create(IDD_CHILD_DIALOG);
  m_pDlg->ShowWindow(SW_SHOW);
 }
}

이렇게 하면.. 생성은 된다.
하지만 모달리스는 힙에 생성되기 때문에 메모리에서 소멸을 시켜주지 않으면 메모리 누수가 발생한다.
따라서 아래의 코드가 필수적이다.

void CChildDlg::OnBnClickedExit()
{
 // TODO: 여기에 컨트롤 알림 처리기 코드를 추가합니다.
 DestroyWindow();
}

이렇게하면 모달리스로 생성된 자식창은 한번은 닫기지만 두번째 생성은 불가능하다.
이미 부모창에서 생성시킨 포인터 변수를 초기화 못했기 때문이다.
그럼 또 아래와 같은 코드가 필요하다.

void CChildDlg::PostNcDestroy()
{
 // TODO: 여기에 특수화된 코드를 추가 및/또는 기본 클래스를 호출합니다.
 CDialog::PostNcDestroy();
 
 CModalessDlg *pMainWnd = (CModalessDlg *)AfxGetMainWnd();
 pMainWnd->m_pDlg = NULL;
 delete this; 
}


부모창을 호출해서 m_pDlg 를 초기화 하고.  자신을 delete 시켜준다.
만약 CModalessDlg 를 참조하기 위해 부모헤더 참조하였다면 에러가 발생할수 있다.
그러면 '전방참조' 라는 글을 참조하기 바란다.
Posted by +깡통+

  모달 모달리스 
 생성  CDialog::DoModal()  CDialog::Create()
 소멸  CDialog::EndDialog()  CDialog::DestoryWindow()
 생성 위치  스택에 생성  힙에 생성
     
     



Posted by +깡통+

먼저 선언되어 있지 않은 OnIntitDialog 를 재정의 통해서 추가한다.

자식창 코드
BOOL CNewDialog::OnInitDialog()
{
 CDialog::OnInitDialog();

 // TODO:  여기에 추가 초기화 작업을 추가합니다.

// 부모창의 포인터를 얻어서 GetValue 라는 사용자 정의 함수를 호출한다.
 CString m_str;
 CModalDlg *pMainWnd = (CModalDlg *)AfxGetMainWnd();
 m_str = pMainWnd->GetValue();
 TRACE(L"GET = %s\n", m_str);
 CEdit *pEdit = (CEdit *)GetDlgItem(IDC_EDIT1);
 pEdit->SetWindowTextW(m_str);

 return TRUE;  // return TRUE unless you set the focus to a control
 // 예외: OCX 속성 페이지는 FALSE를 반환해야 합니다.
}


부모창 코드.
CString CModalDlg::GetValue(void)
{
 CString m_str;
 CEdit *pEdit = (CEdit *)GetDlgItem(IDC_EDIT1);
 pEdit->GetWindowTextW(m_str);
 TRACE("GetValue = %s \n", m_str);
 return m_str;
}

Posted by +깡통+

포인터 캐스팅을 이용하여 자식창에서 부모창의 포인터 주소를 얻어 처리합니다.

자식창에 입력 버튼을 만들고 아래와 같이 코딩합니다.
void CNewDialog::OnBnClickedInput()
{
 // TODO: 여기에 컨트롤 알림 처리기 코드를 추가합니다.
 CString m_strTemp;
 CEdit *pEdit = (CEdit *)GetDlgItem(IDC_EDIT1);
 pEdit->GetWindowText(m_strTemp);
 TRACE(L"%s \n", m_strTemp);

 CModalDlg *pMainWnd = (CModalDlg *)AfxGetMainWnd();
 pMainWnd->m_str2 = m_strTemp;
 pMainWnd->ShowValue();

}

부모창에는 m_str2 전역변수를 만들고 아래와 같이 추가합니다.
void CModalDlg::ShowValue(void)
{
 CEdit *pEdit = (CEdit *)GetDlgItem(IDC_EDIT1);
 pEdit->SetWindowTextW(m_str2);
}

위는 동강으로 배운 내용이고 응용하자면...
// 부모창에는
void CNewDialog::OnBnClickedInput()
{
 // TODO: 여기에 컨트롤 알림 처리기 코드를 추가합니다.
 CString m_strTemp;
 CEdit *pEdit = (CEdit *)GetDlgItem(IDC_EDIT1);
 pEdit->GetWindowText(m_strTemp);
 TRACE(L"%s \n", m_strTemp);

 CModalDlg *pMainWnd = (CModalDlg *)AfxGetMainWnd();
 //pMainWnd->m_str2 = m_strTemp;
 pMainWnd->ShowValue2(m_strTemp);

}

// 자식창에는
void CModalDlg::ShowValue2(CString m_str)
{
 CEdit *pEdit = (CEdit *)GetDlgItem(IDC_EDIT1);
 pEdit->SetWindowTextW(m_str);
}


이렇게 하는것이 효과적이지 않을까?  굳이 전역변수를 만들 필요까지는 없을듯...
물론 문제는 있다.
예를들어 어떠한 옵션창을 오픈하여 여러 옵션을 선택한뒤 사용자가 저장 버튼을 눌렀다고 가정한다면
그건 부모창에서 처리하는 옵션데이터 struct 변수에 저장해야 하지 않을까?

Posted by +깡통+

VS2005 기준으로 설명합니다.
1. 리소스에서 다이얼로그를 추가한다.
2. 다이얼로그 창에서 팝업을 띄워 클래스 추가를 한다.
3. CDialog 파생클래스인 CNewDialog 를 생성한다.
4. 기존의 CModalDlg 헤더파일에 NewDialog.h 를 선언한다.
5. 부모창에서 아래와 같이 코딩한다.

void CModalDlg::OnBnClickedNewDialog()
{
 // TODO: 여기에 컨트롤 알림 처리기 코드를 추가합니다.
 CNewDialog pDlg;
 pDlg.DoModal();
}

6. 자식창에서 아래와 같이 코딩한다.
void CNewDialog::OnBnClickedExit()
{
 // TODO: 여기에 컨트롤 알림 처리기 코드를 추가합니다.
 OnOK();
}


OnOK();
OnCancel();
PostMessage(WM_CLOSE, 0, 0); 
을 이용하여 모달을 닫는다.
대소문자 구별 주의~  Ok 가 아니다 OK 이다.

Posted by +깡통+
새로운 책이 도착했다.

VS2005 버전에서의 인터페이스가 영~ 적응이 안되어서 구입했다.

지금 보유하고 있는 MFC 책은 모두 6.0 으로 설명이 되어 있었다.

Visual C++ 6.0 완벽가이드 (영진출판사) 김용성 저 - 6.0

Windows MFC 정복 (가남사) 최호성, 김태훈, 장지웅 공저 - 6.0

윈도우 프로그래밍 Visual C++ MFC Programming (한빛미디어) 김선우, 신화선 공저  - 6.0

초보개발자를 위한 비주얼 C++ MFC 입문 (대림) 성윤정, 서보원 공저 [2008.05] - Visaul Studio.NET 2005 기준으로 설명

원리에서 활용까지 윈도우즈 MFC 프로그래밍 (정보문화사) 유동근 저 [2007.03]   - Visual Studio.NET 2003 기준으로 설명



책 구입을 하실때 도움이 되시기 바랍니다.

난이도가 가낭 낮은건 초보개발자를 위한 비주얼 C++ MFC 입문 책이고,
중급난이도는 원래에서 활용까지 윈도우즈 MFC 프로그래밍 입니다.

참고로 한빛미디어 홈페이지에서는 MFC 동영상 강좌를 유료(3만원)로 제공하고 있습니다.
한번 동영상을 봤는데 훨씬 이해가 잘되더군요.

아오~  궁금하면 사야됨!  이 책사면 답이 있을까? 고민을 그만해야 겠습니다.
책값 아까지 맙시다 ㅋ.  좋은 책은 책값에 몇 배의 가치를 하더이다. ㅋ
Posted by +깡통+
지난 10년간 Visual Basic만 죽어라 했습니다.

어디까지가 끝인지도 모르고 말이지요.

계속 한가지 언어만 공략하자니 답답한 마음만 커져 갔습니다.

그래서 큰 결심을하고 MFC를 공부하기 시작했습니다.

늦은감이 있지만 이런 결정이 훗날 저를 더욱 강하게 해줄것이라 믿습니다.

첫번째 맞이한 책은..

"윈도우 프로그래밍 Visual C++ MFC Programming" 입니다.

출판사 - 한빛미디어 ,  저자 김선우, 신화선 공저 입니다.

신화선님은 Direct Show 멀티미디어 프로그래밍이라는 책을 저서하셨던 분이죠. ^^

한빛미디어에서 제공하는 동영상 강의(유료)를 곁들여 공부하고 있습니다.

이제 이 책에 절반 정도? 왔네요.
Posted by +깡통+
퍼온 글 입니다.
출처는 http://kin.naver.com/detail/detail.php?d1id=1&dir_id=102&eid=+vUb9qg6V3gU9ILc4vq9XnyR9hOHha3u&qb=TUZDv80gQVBJIMilv+s=&pid=fgMHGsoi5UNssbu2M1Zsss--044627&sid=STO54OenM0kAAGC2MNY

윈도우 프로그래밍과 관련하여서 언어로는 C, C++언어가 사용되고 있고 이들 언어를 이용하여서 윈도우 프로그래밍을 하는 방법으로는 api를 이용하는 방법과 MFC를 이용하는 방법이 있습니다.

api는 C언어로 작성이 되어있고, MFC는 C++언어로 작성이 되어 있습니다. MFC는 api중에서 일부를 C++로 클래스화 시켜 놓은 것입니다. 결국 윈도우 프로그래밍에서는 MFC를 주로 하면서 api를 혼용해서 하게 됩니다.

MFC를 먼저 하고 api를 공부하는 것은 추천하지 않습니다. 그 이유는 api를 알고 MFC를 공부하면 MFC 이해가 훨씬 쉬워집니다. api를 모르고 MFC를 공부하는 과정에서 겪게 되는 시행착오나 개념의 불명확한 이해를 피할 수가 있습니다. 그러나 api가 워낙 방대하고 MFC조차도 api 모두를 MFC로 만들지 못하였기에 api를 다 공부하고 MFC로 들어간다는 것은 너무 힘이 낭비되는 면이 있습니다. 그래서 api책에서 현재 우리나라에서 이쪽으로 가장 많이 읽히는 책이 김상형씨의 api정복이라는 책이 있는데 이 책에서 나오는 11장 윈도우 메시지 정도까지 보셔서 윈도우에서 메시지를 처리하는 기본적인 개념에 대한 이해를 하시고 MFC로 들어가기를 추천합니다. 이렇게 하면 api에 대해서 기초지식을 공부하는 시간이 오히려 MFC를 보면서 이해안되어서 헤매는 시간보다는 더 적게 걸립니다. 그리고 MFC로 기본적인 서적을 보고 본격적으로 MFC를 이용할려면 결국 MFC와 api를 혼용할 수 밖에 없기에 api에 대해서 기본개념 정도는 익히고 들어가세요.

api책을 보실려면 결국 C에 대해서 공부를 하셔야 합니다. C를 먼저 공부하시고서 api 기초부분을 공부하시면 됩니다. api를 공부하실 때 C++도 같이 하시던지 아니면 api를 보고서 C++를 하시던지 순서는 상관없습니다 MFC에 들어가기전에 C+하고 api에 대한 기본학습이 되어야 합니다.

이상은 실제 프로그래밍에서 사용하는 도구의 학습일 뿐입니다. 이것으로 어떤 프로그램개발을 할 수는 없습니다. 요즘 한창 논의되는 지문인식, 생체인식 포토샵 같은 그래픽 관련 프로그램이나 게임등 이런 분야들에서 인공지능이니 영상처리니 하는 내용들이 실제 상용화하는 프로그램개발에 사용되는 지식들인데 이러한 지식들은 프로그램의 내부 로직을 결정하는 것입니다.

결국 도구의 사용법과 로직이 결합되었을 때 비로서 프로그램개발이 가능하게 되는 것입니다.

로직과 관련한 공부가 자료구조, 알고리즘입니다. 이러한 자료구조와 알고리즘에는 기본적인 수준의 정렬, 검색, 트리 등이 있고 전문분야의 알고리즘에는 인공지능, 영상처리에 고유한 알고리즘들이 있습니다. 기본적인 알고리즘은 대학에서 이산수학이라는 분야와 관련되어있고, 전문분야의 알고리즘은 미적분, 통계, 수치해석 등과 밀접한 관련이 있습니다.

도구에 대한 학습과 병행해서 로직을 위한 공부를 계속 하셔야 하는 것입니다. 님께서 말씀하시는 자료구조, 알고리즘이 도구를 공부하는 데에서 중간에 지나야 하는 하나의 단계가 아닙니다. 위에서 말한 기본알고리즘은 이산수학과 관련된 분야로 이산수학을 굳이 하지 않아도 학습이 되지만 전문분야의 알고리즘은 수학을 모르고서는 알고리즘 이해자체가 되지 않습니다.

프로그래밍 학습이 언어를 비롯한 도구에 대한 학습과 논리를 위한 알고리즘, 수학 공부가 병행이 되어야 합니다. 기본알고리즘은 물론 C언어나 C++로 구현이 되기에 이들 언어를 일단은 학습을 하셔야 공부하실 수 있습니다.

이후에는 데이터베이스, 네트워크 등도 공부하셔야 할 분야입니다. 데이터베이스나 네트워크를 배제한 프로그램개발이라는 것은 오늘날 상상할 수 없기 때문입니다. 물론 깊이는 님께서 나아가시는 쪽에 따라서 달라지겠죠.

질문에 C와 C++의 차이에 대해서 말씀을 하셨는데 C언어는 절차중심입니다. 그래서 어떤 자료를 처리하는 절차를 강조하는 것이고 C++은 자료와 절차가 혼합이 된 것입니다. 오히려 자료에 중심을 두고 있습니다. 일부에서 C 언어를 배우고 C++로 들어가면 절차적 사고로 인해 C++의 객체지향적 사고가 방해받을 수 있다고 하는데 그것은 C언어로 개발을 오랜 기간 한 분들에게나 해당할 듯 싶습니다. 님처럼 api를 이해하기 위한 수준으로 C를 배우시게 되면 그러한 염려는 없지 않나 봅니다. 그리고 C++의 객체지향적 사고는 C++문법책으로 공부가 되는 것이 아니고 C++언어는 디자인패턴, 리팩토링 등 클래스 설계와 관련된 공부를 계속 꾸준히 하셔야 합니다. 디자인패턴 등이 쉬운 주제들은 아닙니다. 체화하여서 쓴다는 것이 시간을 필요로 하고 경험을 필요로 합니다.
Posted by +깡통+
이전버튼 1 이전버튼