2014년 12월 2일 화요일

[WINDOW] PID 찾기

1. 윈도우 커맨드 창을 띄워 다음을 입력

   netstat -ano 1 | find "ESTABLISH"

   뭐 기타 응용은 가능하다.
   포트로 찾고 싶을때는 netstat -ano 1 | find "8080"
   IP로도 찾고 싶을때는 netstat -ano 1 | find "8080" | find "10.10.10.10" 등등
   혹 output을 파일로 저장하고 싶으면 netstat -ano 1 | find "ESTABLISH" > output.log
   참 옵션뒤에 '1'을 붙이는 이유는 netstat라는 넘이 현재의 상태만을 보여주고 바로 끝내기
   때문에 1초 간격으로 계속 실행하라는 옵션이다.
   즉, 해당 옵션을 걸어 한 1분이상 모니터링을 하다보면 원하는 값을 얻을 수 있지 않을까 싶다.

2. 윈도우 작업관리자를 실행시킨후 '보기' -> '열선택' 중 PID을 check 해준다.
   그럼 프로세스 항목에 '이미지이름'에  'PID'가 표시되게 된다.

3. 자....이젠 아까 1번항에서 확인했던 output의 확인하고 싶었던 PID를 작업관리자의 PID와
    비교 하고 이상한 프로세스라면 종료 시키거나 지워버리면 될것이다...

출처 : http://blog.daum.net/_blog/BlogTypeView.do?blogid=0Af9k&articleno=8213826

2014년 11월 30일 일요일

[MFC] 2008 -> 2005 Down grade

Microsoft Visual Studio Solution File, Format Version9.0# Visual Studio2005Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Project Paein", "Project Paein\Project Paein.vcproj", "{16A03C2D-938D-405F-BFAE-955A906655C4}"
EndProject
Global
 GlobalSection(SolutionConfigurationPlatforms) = preSolution
  Debug|Win32 = Debug|Win32
  Release|Win32 = Release|Win32
 EndGlobalSection
 GlobalSection(ProjectConfigurationPlatforms) = postSolution
  {16A03C2D-938D-405F-BFAE-955A906655C4}.Debug|Win32.ActiveCfg = Debug|Win32
  {16A03C2D-938D-405F-BFAE-955A906655C4}.Debug|Win32.Build.0 = Debug|Win32
  {16A03C2D-938D-405F-BFAE-955A906655C4}.Release|Win32.ActiveCfg = Release|Win32
  {16A03C2D-938D-405F-BFAE-955A906655C4}.Release|Win32.Build.0 = Release|Win32
 EndGlobalSection
 GlobalSection(SolutionProperties) = preSolution
  HideSolutionNode = FALSE
 EndGlobalSection
EndGlobal


이와 비슷하게 나올겁니다.

여기에서 맨 위에,Format Version 10.0을 9.0으로 바꾸어 주시고

Visual Studio 2008을 2005로 바꿔줍시다.

그리고, vcproject 파일으 다시 메모장으로 여신 후에

<?xml version="1.0" encoding="ks_c_5601-1987"?>
<VisualStudioProject
 ProjectType="Visual C++"
 Version="8.00"
 Name="Project Paein"
 ProjectGUID="{16A03C2D-938D-405F-BFAE-955A906655C4}"
 RootNamespace="ProjectPaein"
 Keyword="MFCProj"

2014년 11월 27일 목요일

(MFC) CEdit 메시지

대부분의 컨트롤을 다룰 때 초기에는 별 필요성이 없다가, 이것 저것 기능을 처리할려다 보면 꼭 필요한
것들이 바로 이벤트를 핸들링 하는 일이다.
정확한 개념 이해를 위해서 MSDN의 원문을 첨가한다. 물론 딸려오는 한글 설명은 번역한 내용을 기술하는 것이 아니고, 그냥 정리된 개념을 서술하는 것이다.

에디트 컨트롤에 특화되어 제공되는 이벤트는 음과 같이 8개가 있다.

1. EN_CHANGEThe EN_CHANGE notification message is sent when the user has taken an action that may have altered text in an edit control. Unlike the EN_UPDATE notification message, this notification message is sent after the system updates the screen. The parent window of the edit control receives this notification message through a WM_COMMAND message.

위 이벤트는 에디트 박스에서 데이터를 입력하거나 수정, 제거 등의 행동을 취하면 발생하는 이벤트이다.
이런걸 사용하는 이유는 방금 입력되거나 수정된 데이터가 올바른지, 혹은 어떤 정해논 범위의 캐릭터가 들어오는지, 아니면 범위를 초과하는지 등등등.. 변화에 민감하게 바로 바로 처리할 수 있도록 할 때 사용한다.

예를 들면 입력을 16진수로만 받아 들인다고 가정했을 때 입력 받을 수 있는 범위는
012345678ABCDEFX이다. 방금 입력된 값이 저 범위에 들어가지 않는다면 삑 소리를 내주거나 메시지 박스등을 뛰워 사용자로 부터 잘못된 입력이 있음을 경고해 줄 수도 있다.

2. EN_ERRSPACE
The EN_ERRSPACE notification message is sent when an edit control cannot allocate enough memory to meet a specific request. The parent window of the edit control receives this notification message through a WM_COMMAND message. 

개발하면서 사실상 한번도 써본적이 없는 메시지이다. 에디트에 어떤 입력이 있을 경우 당연히 그것을 저장할 공간이 할당되어야 한다. 그런데 너무 많이 데이터를 넣어서 더이상 처리될 공간이 없을 때 발생하는 메시지이다. 요즘 윈도우에선 사실상 걸어놔도 걸릴지 의문이다 -_-;

3. EN_HSCROLL, EN_VSCROLLThe EN_HSCROLL notification message is sent when the user clicks an edit control's horizontal scroll bar. The parent window of the edit control receives this notification message through aWM_COMMAND message. The parent window is notified before the screen is updated. 

데이터를 입력하면서 수평/수직 스크롤바에 크기 변경이 생기거나, 사용자가 에디트 박스의 수평/수직 스크롤바를 이동시키면 발생하는 이벤트이다. 이 이벤트 또한 사용자가 에디트 내부를 직접 건드리거나 하지 않는 이상 자주 사용되지 않는다. 샘플을 기준으로 간단하게 어떻게 저 정보를 이용하는지 코드를 적어본다.

void CSssDlg::OnHscrollEdit1() 
{
    SCROLLINFO info;
    GetDlgItem(IDC_EDIT1)->GetScrollInfo(SB_HORZ or SB_VERT or SB_BOTH, &info);
}
위와 같이 현재 에디트 컨트롤의 포인터를 얻어와서 GetScrollInfo에 인자를 채운후 호출하게 되면 info라는 구조체에 현재 스크롤바의 모든 정보가 들어오게 된다.

4. EN_SETFOCUS, EN_KILLFOCUSThe EN_SETFOCUS notification message is sent when an edit control receives the keyboard focus. The parent window of the edit control receives this notification message through a WM_COMMANDmessage. 

사용자가 마우스나 TAB버튼을 이용하여, 에디트 컨트롤에 포커스가 갔을 경우나, 혹은 포커스가 있는 상태에서 다른 컨트롤등으로 포커스가 이동할 경우에 발생하는 이벤트이다. 요런걸 어떨 때 사용하냐면..
검색창등에 있는 에디트 컨트롤을 보면..
<검색어를 입력하세요> 라고 써있어서, 마우스로 콕 찍으면 저 문자열이 사라지고 글자를 입력할 수 있는 상태가 되는걸 본적이 있을 것이다. 기타 등등의 이유가 많겠지만.. 

5. EN_MAXTEXT
The EN_MAXTEXT notification message is sent when the current text insertion has exceeded the specified number of characters for the edit control. The text insertion has been truncated. 

에디트 컨트롤을 변수로 연결할 하고 나서, 클래스 위저드를 열 은 후에..

IDC_EDIT1 을 m_data라고 하는 CString 변수에 연결 한 후.. Memver Variable 라는 탭을 열어 보면 현재 다얄로그 폼에 존재하는 컨트롤과 어떤 변수가 연결되어 있는지 쭈욱 항목이 나온다.
거기서 Maximum Characters : 라는 곳에 5라고 넣었다.
의미는 현재 에디트 IDC_EDIT1에는 최대 5개까지의 문자를 입력 받을 수 있도록 제한을 걸었다는 것이다.

저렇게 제한을 걸어 놓았을 경우 6번째 문자가 입력되면 EN_MAXTEXT이벤트가 발생하게 된다.
void CSssDlg::DoDataExchange(CDataExchange* pDX)
{
    CDialog::DoDataExchange(pDX);
    //{{AFX_DATA_MAP(CSssDlg)
    DDX_Text(pDX, IDC_EDIT1, m_data);
    DDV_MaxChars(pDX, m_data, 5);
    //}}AFX_DATA_MAP
}
라고 추가되는 것이 보일 것이다.
개념을 다시 되 집어 보면, 저걸 직접 손으로 코딩해도 하등 문제가 없다는 이야기이다.
DoDataExchange 에 변수와 컨트롤을 연결하는 DDX_ , DDV_ 계열의 매크로는 상당히 다양하지만 현재 그렇게 까지 자세하게 설명하진 않을 것이다. [궁금하면 콕 찍은 다음 F12를 눌러 보아라]

6. EN_UPDATE
The EN_UPDATE notification message is sent when an edit control is about to redraw itself. This notification message is sent after the control has formatted the text, but before it displays the text. This makes it possible to resize the edit control window, if necessary. The parent window of the edit control receives this notification message through a WM_COMMAND message.

이 이벤트는 에디트 컨트롤을 다시 그려야할 필요가 있는 모든 경우에 발생하는 이벤트이다. EN_CHANGE는 문자열에 대한 변과하 있을 때만 발생하지만, 컨트롤의 크기가 변경된다던가 스타일을 바꾼다던가.. 외관상 및 내부 데이터가 바뀔 때 모두 발생한다는 점이 다르다..

아래 그림은 예제 샘플의 화면이다. 위에 나온 내용중에 몇가지를 구현하여 보았다.


출처 :
http://mins79.tistory.com/entry/%EC%A0%9C%EA%B3%B5%EB%90%98%EB%8A%94-%EC%9D%B4%EB%B2%A4%ED%8A%B8%EC%97%90-%EB%8C%80%ED%95%98%EC%97%AC-%EC%95%8C%EC%95%84%EB%B3%B4%EC%9E%90-MFC-CEdit-%EC%9D%B4%EB%B2%A4%ED%8A%B8

2014년 11월 6일 목요일

신뢰할 수 있는 사이트

http://www.devpia.com/Maeul/Contents/Detail.aspx?BoardID=47&MaeulNo=19&no=291500&ref=291500

2014년 10월 29일 수요일

[JAVA] Iterator


1) key

Iterator<[타입(String, int ... )]> it = [ConcurrentHashMap].keySet().iterator();
while( it.hasNext() )
{
      [value] = [ConcurrentHashMap].get(it.next());
}

2) value


[MFC] 한글 ASCII UTF8 코드 변환

[Tip] 한글 ASCII 코드를 웹 URL에서 사용되는 UTF8 코드로 변환
 
팁스소프트에서 제공하는 프로그래밍과 관련된 자료나 정보들을 무단으로 복제하거나 게재하는 행위는
상호간의 신뢰를 무너뜨리는 행위이며, 법적인 문제를 야기할 수 있으므로 각별한 주의를 당부드립니다.
* 팁스소프트 저작권 정책 보기 -  http://www.tipssoft.com/bulletin/tb.php/FAQ/637
 
이 자료들은 팁스소프트에서 제공하는 [ 알짜배기 ] 프로그램을 이용하면 더 편리하게 볼수 있습니다.
* 알짜배기 프로그램 받기 -  http://www.tipssoft.com/bulletin/tb.php/QnA/8406
 
 
 
안녕하세요~!
 
한글 ASCII 형식의 문자열을 웹 URL에서 사용되는 멀티바이트 코드인 UTF8 형식의 문자열로 변환하는
방법에 대해서 설명하겠습니다.
 
웹에서는 ASCII 형식의 문자열이 사용되지 않고 UTF8 형식의 문자열이 사용됩니다. 특히 URL에서 한글이
적용되는 형태는 UTF8 형식에서 한단계 더 변형된 형태가 사용됩니다. 예를 들어 검색사이트 에서 "한글"
이라는 단어를 검색하게 되면 적용되는 URL에서 "한글" 이라는 단어는 "%ED%95%9C%EA%B8%80"
과 같은 형태로 변형 되어 사용됩니다.
 
일반 프로그래밍시 사용되는 문자열의 형태는 ASCII 코드이기 때문에 웹과 관련된 프로그래밍을 위해서는
ASCII 코드 형태의 문자열을 UTF8 형태로 변형해야 하고 URL에 적용되는 한글의 경우 위와 같이 한단계
더 변형된 형태로 프로그래밍이 이루어 져야 합니다.
 
한글 ASCII 코드를 UTF8 코드로 변환하기 위해서 ASCII 코드를 UTF8 코드로 바로 변환할 수 있는 함수가
없기 때문에 먼저 ASCII 코드를 유니코드로 변환하고 변환된 유니코드를 UTF8 코드로 변환해야 합니다.
 
 
          "ASCII 코드" -> "유니코드" -> "UTF8 코드"
 
 
ASCII 코드를 유니코드로 변환하기 위해서는 MultiByteToWideChar 함수를 사용하고 유니코드를
ASCII 코드로 변환하는것은 특별한 함수를 사용하지 않아도 CString 클래스가 변환해 주기 때문에
CString 클래스를 사용하면 됩니다.
 
그리고 변환된 한글 UTF8 코드를 URL에서 적용되는 형태로 변형합니다. 단, 영어의 경우 한글과 같이
UTF8 코드에서 한단계 더 변형된 형태로 사용되지 않습니다. 영어는 UTF8 코드 형태 그대로 사용되고
한글일 경우에만 위와 같이 변형 되어 사용됩니다.
 
 
// UTF8 코드로 변환하고자 하는 CString 타입의 parm_ascii_string, UTF8 코드로 변환된
// 값을 넣어줄 CString 타입의 parm_utf8_string 2개의 함수 인자를 사용한다.
void AsciiToUTF8(CString parm_ascii_string, CString &parm_utf8_string)
{
     parm_utf8_string.Empty();

     // 아스키 코드를 UTF8형식의 코드로 변환해야 한다. 아스키 코드를 UTF8 코드로 변환할때는
     // 아스키 코드를 유니코드로 먼저 변환하고 변환된 유니코드를 UTF8 코드로 변환해야 한다.

     // 아스키 코드로된 문자열을 유니코드화 시켰을 때의 길이를 구한다.
      int temp_length = MultiByteToWideChar(CP_ACP, 0, (char *)(const char *)parm_ascii_string, -1, NULL, 0);
     // 변환된 유니코드를 저장할 공간을 할당한다.     BSTR unicode_str = SysAllocStringLen(NULL, temp_length + 1);

     // 아스키 코드로된 문자열을 유니 코드 형식의 문자열로 변경한다.      MultiByteToWideChar(CP_ACP, 0, (char *)(const char *)parm_ascii_string, -1, unicode_str, temp_length);

     // 유니코드 형식의 문자열을 UTF8 형식으로 변경했을때 필요한 메모리 공간의 크기를 얻는다.     temp_length = WideCharToMultiByte( CP_UTF8, 0, unicode_str, -1, NULL, 0, NULL, NULL );

     if(temp_length > 0){
        CString str;
        // UTF8 코드를 저장할 메모리 공간을 할당한다.        char *p_utf8_string = new char[temp_length];
        memset(p_utf8_string, 0, temp_length);
        // 유니코드를 UTF8코드로 변환한다.        WideCharToMultiByte(CP_UTF8, 0, unicode_str, -1, p_utf8_string, temp_length, NULL, NULL);
 
        // UTF8 형식으로 변경된 문자열을 각 문자의 코드값별로 웹 URL에 사용되는 형식으로 변환한다.        for(int i = 0; i < temp_length - 1; i++){
            if(p_utf8_string[i] & 0x80){
                // 현재 코드가 한글인 경우..
                // UTF8 코드로 표현된 한글은 3바이트로 표시된다. "한글"  ->  %ED%95%9C%EA%B8%80
                for(int sub_i = 0; sub_i < 3; sub_i++){
                    str.Format("%%%X", p_utf8_string[i] & 0x00FF);
                    parm_utf8_string += str;
                    i++;
                }
   
                i--;
            } else {
                // 현재 코드가 영문인 경우, 변경없이 그대로 사용한다.
               parm_utf8_string += p_utf8_string[i];
            }
        }                                                             
 
        delete[] p_utf8_string;
     }

      // 유니코드 형식의 문자열을 저장하기 위해 생성했던 메모리를 삭제한다.
      SysFreeString(unicode_str);
}


출처 : http://www.tipssoft.com/bulletin/board.php?bo_table=FAQ&wr_id=749

2014년 10월 27일 월요일

[web] referer

레퍼러(Referer) 를 얻어오는 방법

# 레퍼러(Referer : 유입경로) 를 얻어오는 방법    request.getHeader(“referer”);
      – 버튼이나 링크를 클릭해서, 혹은 폼을 전송해서 들어오는 경우 이전 페이지의 URL을 구할 수 있다.
# 참고 : referer 가 null 이 되는 경우
           – 브라우저 URL 입력란에 직접 입력하고 엔터 쳐서 들어오는 경우

[java] annotation

자바에서 Annotation은 소스코드에 주석을 다는 일이다.
별도의 properties파일이나 xml같은 설정파일에 작성하는 부가적인 정보를 어노테이션으로 간편하게 설정할 수 있으므로, 코드의 양을 줄일 수 있다. 

어노테이션은 @를 붙여 사용하며, 우리가 흔히 볼 수 있었던 어노테이션에는 @Override, @Deprecated 등이 있다.

어노테이션은 아래와 같이 사용자가 정의해서 쓸 수 있다.

@Target(ElementType.TYPE) 
@Retention(RetentionPolicy.RUNTIME) 
public @interface Anno { 
    public String defaultVal() default "OK"
    public String val(); 
}

여기서 Target은 어노테이션을 적용할 대상을 선택하고, Retention은 이 어노테이션의 정보가 어디까지 유지되는지 지정한다.

@Target - Constructor, Field, Enum, Local Variable, Method, Package, Parameter, Type(Class)
@Retention - Source, Class, Runtime
@Documented - 어노테이션을 javadoc에 포함한다.
@Inherited - 어노테이션 상속을 가능케 한다.

다음은 위에 정의한 어노테이션을 어떻게 사용하는지 보겠다.

@Anno(val = "Annotation!!"
public class Member { 
.....
}

Target을 TYPE인 클래스에 했으므로 위와 같이 클래스 위에 어노테이션을 사용하고, 아래와 같은 방식으로 어노테이션의 정보를 알아 올 수 있다.

Member member = new Member(); 
System.out.println(member.getClass().getAnnotation(Anno.class).val()); 
System.out.println(member.getClass().getAnnotation(Anno.class).defaultVal());

결과는
Annotation!!
OK


출처 : http://blog.naver.com/cracker542/40159657935

What are Java Annotations

Java5 에 소개된 기능으로, meta data 를 코드형태로 담을 수 있고, runtime 에 이 meta data 에 접근할 수 있다. pre-compiler 가 코드를 conversion 할 때 사용되기도 한다.

Annotation 은 interface 형태이다.

@Retention( RetentionPolicy.RUNTIME );
@Target( ElementType.TYPE )
public @interface TestAnnotation{
public String name();
public String value();
}

@TestAnnotation(name="variable", value="value")
public class TestClass{
// ...
}

@Retention( RetentionPolicy.RUNTIME ) 은 runtime 에 reflection 형태로 사용될 수 있다는 것을 의미한다.
이 구문이 없으면 runtime 에 이 annotation 은 사라진다. ( 구체적으로 compile time 에 제거한다. )

@Target( ElementType.TYPE ) 은 class, interface 와 같은 type 에 쓰인다는 것이다. TYPE 대신 METHOD, FIELD 를 줄수도 있다. 만약 이를 명시해주지 않으면 모든 곳에 사용될 수 있다.



Class Annotations

Annotations[] annotations = aClass.getAnnotations();

if ( annotaion instanceof TestAnnotation ){
((TestAnnotation )annotaion).name();
((TestAnnotation )annotaion).value();
}



Method Annotations

method.getDeclaredAnnotations();





Parameter Annotations

method.getParameterAnnotations();



Field Annotations

field.getDeclaredAnnotations();
field.getAnnotation( TestAnnotation.class );


2014년 8월 24일 일요일

The 25 Best Push up Exercises: http://youtu.be/tccdbY5xcf4
The 35 Best Pullup Exercises: http://youtu.be/_kGoGFsLi1Q

2014년 8월 6일 수요일

[ 트리컨트롤(Tree Control) ]



1. 대화상자에 트리컨트롤을 붙이고 옵션을 다음과 같이 수정하자.






   Edit labels: 트리컨트롤에서 에디트 기능을 사용할때.

   Show selection always: 선택된 아이템을 표시할때.

2. 맴버 변수를 m_ctrTree라고 만들자(Control형 하나밖에 없다).

3. 아이템 추가하기
   TVINSERTSTRUCT  TI;
   TI.hParent  = TVI_ROOT;        // TVI_ROOT, NULL
                         // HTREEITEM값을 사용하면 해당하는 아이템의 자식으로 아이템이 추가된다.
   TI.hInsertAfter = TVI_LAST;    // TVI_FIRST, TVI_LAST, TVI_SORT
   TI.item.mask = TVIF_TEXT | TVIF_IMAGE | TVIF_SELECTEDIMAGE;
   TI.item.iImage = 0;                // Tree가 선택안되었을때 표시될 아이콘
   TI.item.iSelectedImage = 1;   // Tree가 선택되었을때 표시될 아이콘
   TI.item.pszText = "root";

   HTREEITEM hTreeItem = m_ctrTree.InsertItem(&TI); // 추가된 아이템의 HTREEITEM이 리턴된다.

4. 아이템 확장하기.
   m_ctrTree.Expand(hTreeItem, TVE_EXPAND);

5. 아이템 선택시 선택된 아이템 알아보기
   + TVN_SELCHANGED메시지를 사용한다.
   NM_TREEVIEW* pNMTreeView = (NM_TREEVIEW*)pNMHDR;
   HTREEITEM hTreeItem = pNMTreeView->itemNew.hItem;   // 이 값이 선택된 아이템의 핸들이다.

6. 아이템 문자열 가져오기
   CString str = m_ctrTree.GetItemText(hTreeItem);

7. 아이템 개수 알아내기
   int nCount = m_ctrTree.GetCount();

8. 아이템 제거하기
   m_ctrTree.DeleteItem(hTreeItem);   // 핸들 아래단의 아이템들도 모두 제거된다.

9. 현재 선택된 아이템 알아내기
   HTREEITEM hTreeItem = m_ctrTree.GetSelectedItem();

10. 위치로 아이템 찾기
   CPoint  p;
   GetCursorPos(&p);
   ::ScreenToClient(m_ctrTree.m_hWnd, &p);
   HTREEITEM hItem = m_ctrTree.HitTest(p);

11. 아이템 확장 축소 감지
   + TVN_ITEMEXPANDED메시지를 사용한다.
   NM_TREEVIEW* pNMTreeView = (NM_TREEVIEW*)pNMHDR;

   TVITEM  item;
   item.mask = TVIF_HANDLE;
   item.hItem = pNMTreeView->itemNew.hItem;
   m_ctrTree.GetItem(&item);            // 아이템 정보를 알아낸다.

   if(item.state & TVIS_EXPANDED)
   {
      // 확장
   }
   else
   {
      // 축소
   }

12. 아이템 아이콘 설정 변경
   m_ctrTree.SetItemImage(hTreeItem, 0, 1);

13. 아이템 에디트 입력중 포커스가 나갈때 입력중인 값 아이템에 적용하기
   + TVN_ENDLABELEDIT메시지를 사용한다.
   TV_DISPINFO* pTVDispInfo = (TV_DISPINFO*)pNMHDR;

   CEdit *pEdit = m_ctrTree.GetEditControl();
   if(pEdit)
   {
      CString str;
      pEdit->GetWindowText(str);
      if(str.GetLength() > 0)
      {
         m_ctrTree.SetItemText(pTVDispInfo->item.hItem, str);
      }
   }

14. 이미지 리스트 설정
   + CImageList  m_Image;      // 32 x 16 아이콘 BITMAP 16 x 16 2개 짜리

   m_Image.m_hImageList = ImageList_LoadImage(
                                          (HINSTANCE) GetWindowLong(m_hWnd, GWL_HINSTANCE),
                                          MAKEINTRESOURCE(IDB_BITMAP_SMALL), 16, 2,
                                          RGB(255,255,255), IMAGE_BITMAP, LR_CREATEDIBSECTION);
   m_ctrTree.SetImageList(&m_Image, TVSIL_NORMAL);







- 드래그 앤 드롭 사용하기



1. 드래그 시작

   - 트리컨트롤의 TVN_BEGINDRAG메시지 사용

   CImageList  *m_pTreeDragImage = NULL; // 드래그시 생성된 이미지 사용
   HTREEITEM  m_hDragItem = NULL;           // 드래그시 처음 선택된 아이템 핸들 기억용



   void CDlg::OnBegindragTree(NMHDR* pNMHDR, LRESULT* pResult) 
   {
      NM_TREEVIEW* pNMTreeView = (NM_TREEVIEW*)pNMHDR;
      // TODO: Add your control notification handler code here

      // 드래그 이미지 생성
      if(m_pTreeDragImage) m_pTreeDragImage->DeleteImageList();
      m_pTreeDragImage = m_ctrTree.CreateDragImage(pNMTreeView->itemNew.hItem);



      // 드래그시 사용할 이미지 크기 계산
      RECT  rc;
      m_ctrTree.GetItemRect(pNMTreeView->itemNew.hItem, &rc, TRUE); // 아이콘을 포함하는 크기

      // 드래그를 시작
      m_pTreeDragImage->BeginDrag(0, CPoint(pNMTreeView->ptDrag.x-rc.left+16, 

                                                       pNMTreeView->ptDrag.y-rc.top));
      // 드래그 이미지 표시
      m_pTreeDragImage->DragEnter(&m_ctrTree, pNMTreeView->ptDrag);
   
      // 마우스 메시지를 잡아두고
      SetCapture();


      // 현재 선택된 아이템 핸들을 기억
      m_hDragItem = pNMTreeView->itemNew.hItem;


      *pResult = 0;
   }



2. 이동

   - WM_MOUSEMOVE메시지 사용



   void CDlg::OnMouseMove(UINT nFlags, CPoint point) 
   {
      // TODO: Add your message handler code here and/or call default
      // 드래그 중이라면
      if(m_pTreeDragImage)
      {

         // 트리컨트롤 기준으로 마우스 좌표 계산
         CPoint  p = point;
         ClientToScreen(&p);
         ::ScreenToClient(m_ctrTree.m_hWnd, &p);



         // 마우스가 위치한 아이템을 검사한다.항목이 트리 뷰 항목위에 있는지 확인하고 그렇다면 항목이 밝게 표시되도록한다.
         HTREEITEM hItem = m_ctrTree.HitTest(p);



         // 밝게 표시된 부분과 현재 선택된 아이템이 틀리다면

         if(hItem != m_ctrTree.GetDropHilightItem())
         {
            // 드래그 이미지 그리기 중지
            m_pTreeDragImage->DragLeave(&m_ctrTree);



            // 새로운 항목을 밝게 표시한다.
            m_ctrTree.SelectDropTarget(hItem);



            // 드래그 이미지를 다시 보여준다.
            m_pTreeDragImage->DragEnter(&m_ctrTree, p);
         }
         else
         {
            m_pTreeDragImage->DragMove(p);
         }
      }



      CDialog::OnMouseMove(nFlags, point);
   }



3. 드롭

   - WM_LBUTTONUP메시지 사용



   void CDlg::OnLButtonUp(UINT nFlags, CPoint point) 
   {
      // TODO: Add your message handler code here and/or call default



     // 드래그 중이 었다면

      if(m_pTreeDragImage)
      {

         // 마우스 메시지 캡쳐 기능을 제거한다.

         ReleaseCapture();



         // 드래그 과정을 중단한다.
         m_pTreeDragImage->DragLeave(&m_ctrTree);
         m_pTreeDragImage->EndDrag();
         m_pTreeDragImage->DeleteImageList();
         m_pTreeDragImage = NULL;
  
         // 일단 마지막으로 밝게 표시되었던 항목을 찾는다.
         HTREEITEM hTargetItem = m_ctrTree.GetDropHilightItem();
  
         // 밝게 표시된 드롭 항목의 선택을 취소한다.
         m_ctrTree.SelectDropTarget(NULL);



         // 선택된 항목(아이템)이 있다면

         if(hTargetItem)
         {
            // 선택된 아이템과 이동될 곳의 아이템이 같다면 이동할 필요가 없다.
            if(m_hDragItem != hTargetItem)
            {

               // 현재 자식의 부모 아이템 핸들을 구한다.
               HTREEITEM hParentItem = m_ctrTree.GetNextItem(m_hDragItem,

                                                                                       TVGN_PARENT);



               // 이동하려는 곳이 자신이 직접속한 항목 이라면 이동할 필요가 없다.
               if(hParentItem != hTargetItem)
               {
                  // 트리의 내용을 이동하자.
                  MoveTreeItem(&m_ctrTree, m_hDragItem, hTargetItem);



                  // 이동된 곳의 트리를 확장하자.
                  m_ctrTree.Expand(hTargetItem, TVE_EXPAND);


                  // 이미지도 확장한걸로 바꾸자
                  m_ctrTree.SetItemImage(hTargetItem, 1, 1);
     
                  // 원본 트리의 모든 아이템이 사라졌다면 이미지 그림을 기본으로 바꾸자.
                  HTREEITEM hItem = m_ctrTree.GetChildItem(hParentItem);
                  if(!hItem)
                  {
                     m_ctrTree.SetItemImage(hParentItem, 0, 0);
                  }
               }
            }
         }

         m_hDragItem = NULL;
      }



      CDialog::OnLButtonUp(nFlags, point);

   }



4. 트리 항목(아이템) 이동 함수

   // 아이템 데이터 이동
   BOOL MoveTreeItem(CTreeCtrl *pTree, HTREEITEM hSrcItem, HTREEITEM hDestItem)
   {
      // 이동할 아이템의 정보를 알아내자.
      TVITEM    TV;
      char    str[256];
      ZeroMemory(str, sizeof(str));
      TV.hItem = hSrcItem;
      TV.mask  = TVIF_TEXT | TVIF_IMAGE | TVIF_SELECTEDIMAGE;
      TV.pszText = str;
      TV.cchTextMax = sizeof(str);
      m_ctrTree.GetItem(&TV);
      DWORD dwData = pTree->GetItemData(hSrcItem);



      // 아이템을 추가 하자.
      TVINSERTSTRUCT  TI;
      TI.hParent        = hDestItem;
      TI.hInsertAfter   = TVI_LAST;
      TI.item.mask     = TVIF_TEXT | TVIF_IMAGE | TVIF_SELECTEDIMAGE;
      TI.item.iImage   = TV.iImage;
      TI.item.iSelectedImage = TV.iSelectedImage;
      TI.item.pszText   = TV.pszText;
      HTREEITEM hItem  = pTree->InsertItem(&TI);
      pTree->SetItemData(hItem, dwData);



      // 현재 아이템에 자식 아이템이 있다면
      HTREEITEM hChildItem = pTree->GetChildItem(hSrcItem);
      if(hChildItem)
      {
         // 자식 아이템이 있다면 같이 이동하자.
         MoveChildTreeItem(pTree, hChildItem, hItem);
      }

      // 확장 여부를 알아서 똑같이 하자.
      TVITEM  item;
      item.mask = TVIF_HANDLE;
      item.hItem = hSrcItem;
      pTree->GetItem(&item);
      if(item.state & TVIS_EXPANDED)
      {
         pTree->Expand(hItem, TVE_EXPAND);
      }



      // 아이템을 선택하자.
      pTree->SelectItem(hItem);



      // 기존 아이템을 제거한다.
      pTree->DeleteItem(hSrcItem);



      return TRUE;
   }





   // 현재 트리의 모든 아이템 데이터 이동
   BOOL MoveChildTreeItem(CTreeCtrl *pTree, HTREEITEM hChildItem,
                                                                       HTREEITEM hDestItem)
   {
      HTREEITEM hSrcItem = hChildItem;



      while(hSrcItem)
      {
         // 이동할 아이템의 정보를 알아내자.
         TVITEM    TV;
         char    str[256];
         ZeroMemory(str, sizeof(str));
         TV.hItem     = hSrcItem;
         TV.mask     = TVIF_TEXT | TVIF_IMAGE | TVIF_SELECTEDIMAGE;
         TV.pszText = str;
         TV.cchTextMax = sizeof(str);
         m_ctrTree.GetItem(&TV);
         DWORD dwData = pTree->GetItemData(hSrcItem);



         // 아이템을 추가 하자.
         TVINSERTSTRUCT  TI;
         TI.hParent       = hDestItem;
         TI.hInsertAfter  = TVI_LAST;
         TI.item.mask    = TVIF_TEXT | TVIF_IMAGE | TVIF_SELECTEDIMAGE;
         TI.item.iImage   = TV.iImage;
         TI.item.iSelectedImage = TV.iSelectedImage;
         TI.item.pszText   = TV.pszText;
         HTREEITEM hItem  = pTree->InsertItem(&TI);
         pTree->SetItemData(hItem, dwData);



         // 현재 아이템에 자식 아이템이 있다면
         HTREEITEM hChildItem = pTree->GetChildItem(hSrcItem);

                                         // pTree->GetNextItem(hSrcItem, TVGN_CHILD);
         if(hChildItem)
         {
            MoveChildTreeItem(pTree, hChildItem, hItem);
         }



         // 확장 여부를 알아서 똑같이 하자.
         TVITEM  item;
         item.mask = TVIF_HANDLE;
         item.hItem = hSrcItem;
         pTree->GetItem(&item);
         if(item.state & TVIS_EXPANDED)
         {
            pTree->Expand(hItem, TVE_EXPAND);
         }



         // 다음 아이템을 알아보자.
         hSrcItem = pTree->GetNextItem(hSrcItem, TVGN_NEXT);
      }
  
      // 기존 아이템을 제거한다.
      pTree->DeleteItem(hChildItem);

      return TRUE;
   }

출처 : http://intel.tistory.com/2460735