'Programming Tips'에 해당되는 글 9건

  1. 2008/05/29 윈도우 시작프로그램에 등록하기(레지스트리 건드려서..) by 모니터에습기찼어
  2. 2008/03/15 [DevPia] MFC vs. ATL by 모니터에습기찼어
  3. 2008/02/22 MPICH Install & VS 설정 by 모니터에습기찼어
  4. 2008/02/22 클러스터에서 MPI 설치 by 모니터에습기찼어
  5. 2008/01/30 C++/MFC공부할때 팁 by 모니터에습기찼어
  6. 2008/01/30 C++에서 객체를 delete시.. by 모니터에습기찼어
  7. 2008/01/30 BSD 소켓예제 by 모니터에습기찼어
  8. 2008/01/30 프로세스이름으로 검색 및 죽이기 by 모니터에습기찼어
  9. 2008/01/11 이야~ 다시 오픈 ㅋㅋㅋ by 모니터에습기찼어

우선.. 윈도우 시작프로그램에서 실행할 프로그램에관련된 레지스트리..

HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\Run

이곳에 모든 정보가 저장되어있다.. (윈도 부팅시 실행될 프로그램관련정보들이..)

이거만 알면...

레지스트리 읽기/쓰기 함수를 통해서 건드리면 될거같다..

int ReadRegVal(char *reg_path, char *key, char *val, int val_buf_size ) // reg읽기

{

    HKEY phk=0;

    DWORD nEC = REG_BINARY;                                         // 바이너리모드로 읽기

    DWORD size = val_buf_size;                                            // 레지스트리읽기시 버퍼크기

  

    memset(val,0,val_buf_size);                                              //mem clear

  

    RegOpenKey(HKEY_LOCAL_MACHINE,reg_path,&phk);

    RegQueryValueEx(phk, key, NULL,&nEC, (LPBYTE)val, &size );  //읽기 값은 val에 저장

   //val은 걍 맘편히 타입케스팅 바로 하셔서 쓰셔욧....

    RegCloseKey(phk);


    return 0;

}


int WriteRegVal(char *reg_path, char *key, char *val)          //reg write

{

    HKEY phk=0;

    long nRet;


    RegCreateKey(HKEY_LOCAL_MACHINE, reg_path, &phk);

    nRet = RegSetValueEx(phk, key, 0, REG_SZ, (LPBYTE)val, strlen(val));

  

    RegCloseKey(phk);

  

    if(ERROR_SUCCESS == nRet)   return 0;


    return 1;

}



사용법:

레지스터 쓰기.

WriteRegVal("SOFTWARE\\Microsoft\\Windows", "Windows", "5.2" );

Posted by 모니터에습기찼어
[데브피아] MFC vs ATL Copy url
박윤선 2008.02.22 11:03
조회 105   스크랩 0

 질문&답변
 [질문] MFC ActiveX , ATL MFC지원이랑 무슨차이죠?  | VC++ 일반
임대진 (vs2002)  임대진님께 메시지 보내기임대진님을 내 주소록에 추가합니다.임대진님의 개인게시판 가기 번호: 678738   / 평점:  (-)  / 읽음:18

안녕하세요

프로젝트 생성할때 보면

MFC ActiveX, ATL MFC 지원 또는 미지원 이 있잖아요?

여기서 mfc actiex랑 ATL mfc지원이랑

다르기때문에 나줘지겠죠!

말 그대로 하나는 ATL을 쓰는거구 하나는 Activex형식으로 짜는거겠지만

웹에 import할 때 덩치는 비슷할 거 같은데....

차이가 뭐에요?



 [답변]...
조희원 (neogeist)  조희원님께 메시지 보내기조희원님을 내 주소록에 추가합니다.조희원님의 개인게시판 가기 번호: 678749   / 평점:  (-)  

mfc activeX는 말그대로 mfc로 액티브액스 만드는거고

mfc atl지원은 프로젝트 안에서 정해주는 속성입니다.

mfc atl라이브러리를 쓰면 체크해줘야죠.

atl은 유틸리티와 많은수의 기능들이 헤더에 선언되어있어서
 atl관련기능을 써도 반드시 atl라이브러리를 임포트할 필요는 없습니다.

문제생기면 그때그때...

 [답변]C++로 COM 을 만든는 방법
김진수 (ekklesiaV)  김진수님께 메시지 보내기김진수님을 내 주소록에 추가합니다.김진수님의 개인게시판 가기 번호: 678778   / 평점:  (-)  


C++ 로 COM Component을 만드는 방법에는 크게 두가지가 있습니다.


하나는 MFC로 만드는 방법.

나머지 하나는 ATL로 만드는 방법.


MFC로 만들면 기존의 MFC 라이브러리의 풍부한 기능을 사용할수 있어

GUI 작업시에 많은 편리함을 제공합니다.


ATL은 GUI 작업시에는 윈 32 라이브러리를 사용해서
작업해야 하는 경우가

많습니다. MFC에 비해 GUI 지원이 약합니다.

ATL 프로젝트에서 MFC 지원의 의미는 보통 CString 클래스를
ATL 프로젝트에서 사용하고

싶을 때 이 부분을 체크해줍니다. 또한 그래픽 관련
MFC 클래스를 사용하기 위해서

체크해줍니다. 이 부분을 옵션으로 설정하게 한 이유는
 MFC 라이브러리가

부피가 커서입니다.


ActiveX 컨트롤은 MFC, ATL 둘다 만둘수 있습니다.


2000년전 까지만해도 느린 인터넷 속도와 낮은 PC 사양으로
ATL 로 COM Component를 만드는 것을

추천 하였으나, 지금 같은 빠른 인터넷 속도와 Giga byte 넘는
메모리에 쿼드 프로세서가 장착한 컴퓨터가

나오는 상황에서는 MFC 로 ActiveX  Control 과 COM  
컴포넌트를 만드는 것이 더 낫겠지요.



 [답변]또 하나 차이점
노영선 (roh0sun)  노영선님께 메시지 보내기노영선님을 내 주소록에 추가합니다.노영선님의 개인게시판 가기 번호: 678808   / 평점:  (-)  

COM 관련 자동 코드 생성이 (기본적인 코드가 자동 생성되죠)

MFC는 매크로 방식이고 ATL은 템플릿 기반 C++ 소스 방식입니다.


당근 코드 보기가 소스 이해는 ATL이 더 쉽죠
(템플릿에 대한 기본적인 지식이 있다면)

MFC는 희한한 매크로가 많이 생기는데

그냥 규정대로 매크로 사용법을 잘 따라주면 별 문제 없지만
뭔가 꼬이기 시작하면 디버깅이 더 어려울 수도 있습니다.

Posted by 모니터에습기찼어

출처 블로그 > 자운님의 블로그
원본 http://blog.naver.com/baida21/50015052635

병렬분산처리를 Visual Studio에서 하려고 mpich를 사용한다.


1. 인스톨

http://www-unix.mcs.anl.gov/mpi/mpich2/

여기서 윈도우용을 다운받는다.

 

mpich2-1.0.5p2-win32-ia32.msi 를 실행한다.

닷넷 1.1을 설치하라는 지시가 나오면 설치한다.

환경변수 path에 C:\MPICH2\bin 을 추가한다.

mpiexec -n 1 cpi.exe 를 실행해서 예제를 돌려본다.

 

처음 실행시에는 username과 password를 물어볼수 있다. 향후 묻지 않게 하려면

mpiexec -register 를 실행해서 레지스트리에 등록하면 된다.

 

2. Visual Studio 에서 실행

 

examples/cpi.exe를 Visual studio에서 컴파일 해보자

 

먼저 적당한 이름의 프로젝트를 생성한다. 그리고 그 프로젝트는 콘솔타입에 "빈프로젝트"로 생성한다.

 

 


사용자 삽입 이미지
 
 
 



프로젝트 속성에서 "추가 포함 디렉터리"에 MPICH의 include 디렉토리를 지정한다.


사용자 삽입 이미지




추가 라이브러리 디렉터리에 MPICH의 lib 디렉터리를 지정한다.

사용자 삽입 이미지
 
 
 
 
추가 종속성에서 mpi.lib 라이브러리를 포함한다.


 

사용자 삽입 이미지
 
위와 같이 설정하고 , 이제 컴파일을 해보자 그러면 Debug 디렉토리에 cpi.exe가 생성되었음을 볼 수 있다.
 
 
2. sundials compile in VC++
 
DAE solver는 위의 sundials를 사용하려고 한다.
왜냐면, 위 라이브러리가 mpich등 병렬분산처리를 지원하는 ODE 라이브러리이기때문입니다.
 
압축을 풀면 INTSTALL 관련 정보를 볼 수 있다.
기본 인스톨은
./configure
make
make install
이다.
단, 예제를 돌려보려면 configuration에서 추가적인 옵션을 설정해 주어야 하는데, 이것은
 
 
To follow up on comments on the sundials cvodes email list, here is how I compiled a freshly downloaded CVODES using VC++ from the command line

1. Create sundials\shared\include\sundials_config.h with these two lines #define SUNDIALS_DOUBLE_PRECISION #define SUNDIALS_USE_GENERIC_MATH

2. IN CVODES SOURCE FOLDER cl /c /I..\include /I..\..\shared\include *.c lib /out:cvodes.lib *.obj

3. IN SUNDIALS SHARED SOURCE cl /c /I..\include *.c lib /out:sundials.lib *.obj

4. IN SUNDIALS nvec_ser cl /c /I..\shared\include *.c lib /out:nvec_ser.lib *.obj

5. Build application by compiling it and linking to cvodes.lib sundials.lib nvec_ser.lib
 

이 내용은 일종의 예시일 뿐이다. 구체적으로 VC++안에서 프로젝트를 구성해서 컴파일을 해보자.
 
3. VC++ sundials 컴파일
 
일단 sundials의 소스를 cygwin에서 푼 다음, 여기서 ./configure를 실행한다.
이렇게 되면, 몇몇 *.h 파일들이 생성된다. 특히 sundials_config.h 가 만들어지는데, 이것은 컴파일 할때 빼 놓아서는 안된다.
 
프로젝트 디렉토리를 구성한다. 각 라이브러당 하나씩 추가한다.
 
 
사용자 삽입 이미지
 
정적라이브러리 프로젝트로 구성한다.
 
 
 
또한, sudials의 include를 복사한다.
그리고 src/cvode/* 와 src/sundials/* 를 모두 복사한다.
 
사용자 삽입 이미지


 

사용자 삽입 이미지
 
이렇게 옮기면 디렉토리의 구조는 원래와 조금 다르지만, 컴파일 하기에는 무리는 없다.
 
여기에서 헤더파일들의 정보를 포함해 주면된다.

사용자 삽입 이미지


 

이렇게 하면 컴파일은 무난하게 이루어진다.
 
각각의 라이브러리에 대해 동일하게 만들어준다.
 
위와 같이 모두 하고나서 마지막으로 sundials.lib를 만들면서 다른 라이브러리를 모두 하나로 합해서 사용했다.
 
 
사용자 삽입 이미지
 
 
이제 sundials\sundials_config.h 만 include 디렉토리로 옮기면 하나의 라이브러리와 include를 이용해서 예제에 대한 컴파일이 가능하다.
 
 
사용자 삽입 이미지
 
 
 
 
리눅스용으로 나온 것이지만, 기본적으로 VC++에서도 크게 컴파일하는데 어렵지 않다. 헤더와 라이브러리만 잘 포함시키면 문제없이 컴파일이 된다.
다만 비주얼 툴이라 개별 라이브러리로 만들때 일일히 프로젝트를 생성해야 한다는 것이 귀찮기는 하다.
 
VS2005에서 컴파일시 주의점
 
컴파일시 다음 사항을 주의해야 한다.
vs2005부터는 C runtime의 단일 쓰레드 디버그를 위한 LIBCD.lib를 지원하지 않는다.
해결책은 링커에서 포함하지 않을 라이브러리로 지정하는 방법이 가장 간단하다.

사용자 삽입 이미지

2. mpich 사용법
 
간단하게 사용하는 방법을 보면 다음과 같다.
 
Unix계열은
 
mpd &
cd /home/you/mpich2-installed/examples
mpiexec -n 3 cpi
mpdallexit
 
이렇게 해주면 된다.
windows계열은 smpd.exe를 사용하는데, smpd는 윈도우, 유닉스에서 mpd대신 모두 사용할 수 있는 데몬이다.
Posted by 모니터에습기찼어

Instructions to get MPICH.NT.1.2.5 up and running on a cluster:

  1. Download the package.

    mpich.nt.1.2.5.zip (6 MB June 8, 2003)

  2. Don't run setup yet.  Unzip the contents to a temporary location in a shared directory.
  3. Use notepad to edit setup.iss
  4. Find the line:

    szDir=C:\Program Files\MPICH

  5. Change it to whatever directory you want.
  6. Find the lines:

    Component-count=7
    Component-0=runtime dlls
    Component-1=mpd
    Component-2=SDK
    Component-3=Help
    Component-4=SDK.gcc
    Component-5=RemoteShell
    Component-6=Jumpshot

  7. Delete the components you don't want installed and adjust the count and numbers.

    A typical setting for a non-interactive node would be as follows:

    Component-count=2
    Component-0=runtime dlls
    Component-1=mpd

    A typical setting for an interactive node would be as follows:

    Component-count=5
    Component-0=runtime dlls
    Component-1=mpd
    Component-2=SDK
    Component-3=Help
    Component-4=Jumpshot

  8. From each host in the cluster, execute the following command:

    \\myhost\myshare\setup -s -f1\\myhost\myshare\setup.iss

    Here is an example.  I unzipped mpich.nt.1.2.5.zip into the directory c:\temp on a machine called FRY.  I edited setup.iss as explained above and then typed the following from a command prompt on a machine called FRENCH:

    C:\>\\fry\c$\temp\setup -s -f1\\fry\c$\temp\setup.iss

    Note: c$ is an administrative share for c: on fry

    Note: There is no space between -f1 and \\myhost\...

  9. Finally, delete the files you unzipped from the archive.

출처 : 유토피아님의 블로그
원문 : http://blog.naver.com/orpheus2001?Redirect=Log&logNo=120019322867

Posted by 모니터에습기찼어
*다이얼로그 기반의 프로그래밍에서
MFC에서 제공하는 메세지맵을 이용하기 보다는 직접 코드를 작성하도록 한다.
커맨드 메세지에 대한 일괄적인 정의를 받기 위해서는 ON_COMMAND_RANGE(id1, id2, memberFxn )를 이용하고
버튼의 이벤트처리를 윟새넌 ON_CONTROL_RANGE(wNotifyCode, id1, id2, memberFxn )
를 이용하도록 한다.

*Format의 다양한 옵션을 알도록 한다.
특히 %.15G라는 옵션은 double형 변수를 15자리 이내에서 값이 있는 자리까지만 출력한다.

*atof(char *)
_wtof(wchar *)
되도록 TCHAR형을 쓰도록 한다.

*변수의 갯수는 가능한한 줄이고 각 변수에 대한 기능도 최대한 중복되거나 겹치지 않게 한다

*Create 란 윈도우자식을 만들어 Cwnd 객체에 붙이는 것
*OnCreate 란 WM_CREATE라는 메세지를 받았을때 베이스클래스에서 상속받은 클래스를 호출하는 것.

*각종 콘트롤도 결국에는 하위 윈도우인 것이다.
콘트롤을 상속받은 클래스의 경우 또한 마찬가지이다. 그러므로 각각의 변형된 콘트롤클래스를 생성하면
윈도우 핸들이 생성되고 일반 윈도우를 사용하듯이 onCreate에서 초기화를 해주고
onPaint에서 그려주는 방식으로 구현하면 된다. 여기서 중요한 것은 클래스를 정의하고 메세지에 대한 정의를 할때
메세지맵을 잘 이용하는 것이 중요하다. 그리고 클래스 추가할때 VS의 도움을 받으면 쉽게 할수 있다.(추가->클래스->MFC클래스->...)

*상속받은 클래스의 경우 클래스 선언부에서 클래스 이름을 클릭하게 되면 우측에 처리가능한 메세지에 뜬다.(VC6.0의 클래스위자드처럼)

*인자의 값이 바뀌었을때 클래스의 초기화에 대한 부분을 정확하게 이해하고 있어야 한다.
예를 들어 개인버튼클래스를 만드는 과제의 경우 버튼의 위치를 바꾸어주는 함수를 구현할때 시작위치만 바꾸어줄 것이 아니라 버튼이미지가 그려지는 리전도 함께 옮겨주어야 한다.
나는 setskin이라는 함수에 리전 옮기는 함수가 있어서 그곳에서만 집착을 했지만 막상 리전을 옮겨주는 함수는 버튼의 위치를 바꾸어주는 함수를 호출했을때 아무 영향도 받지 않았다!?!

*비트맵 출력을 하려고 하는 경우에 메모리에 먼저 그려준 다음에 그려주게 되는데 메모리에 그려주는 위치는 화면상의 위치가 아니라 메모리상의 상대적 위치임을 잊지 말고 있어야 한다.

*WM_CREATE 라는 메세지가 올때.
The framework calls this member function when an application requests that the Windows window be created by calling the Create or CreateEx member function.
윈도우가 생성되어 보여주기 직전에 OnCreate라는 함수가 호출된다.

*WM_PAINT라는 메세지가 올때
OnPaint라는 함수를 호출하게 된다. WM_PAINT메세지는 UpdateWindow | RedrawWindow멤버함수가 호출될때 보내온다.

*PreSubclassWindow 라는 버츄얼 함수는 윈도우가 서브클래싱되기전에 필요한 서브클래싱이 일어나게 하려고 호출된다.
*owner-drawn버튼의 시각적인 요소가 변할때 호출된다.

*보통은 OnPaint와 OnCreate가 쌍이고 PreSubclassWindow와 DrawItem이 쌍으로 작동하게 된다. DrawItem과 OnPaint는 그려주는 영역이 미묘하게 다르다.
우리네 작업에서는 앞의 쌍을 주로 쓰게 된다.

*Owner-drawn이란? 기존에 있는 윈도우 클래스들-ex. 버튼. 정적. 리스트박스 등등-를 상속받아 유사한 속성의 새로운 클래스를 만들 경우 이 임의의 클래스를 owner-drawn class라고 한다.

*리소스의 경우 리소스뷰에서 편집가능한 경우와 코드상에서만 존재해서 수정하려면 리소뷰에서 편집못하고 코드로만 수정가능한 경우 두가지가 있다.

*CWnd클래스의 멤버함수중에 Create라는 함수가 있다. 클래스를 동적 생성하는 함수인데. 마지막 인자 UINT nID는 적당하게 큰수를 주는 것이 좋다. 왜냐하면 특히 다이얼로그 기반의 프로그램일경우
ID 중복으로 인해서 원치 않는 메세지 처리가 일어날수 있다. 예를 들어 아이디가 1일경우 확인 혹은 취소버튼과 아이디가 같은 확률이 아주 높다- 확인 | 취소버튼이 있다면- 그러면 새롭게 생성한 버튼에
서-특히나 owner-drawn일 경우는 더더욱- 메세지가 발생했을 경우에 확인|취소버튼의 메세지처리부와 연결되서 프로그램이 자동 종료될수도 있게 된다. 그러므로 nID는 200이상으로 넉넉하게 주는 것이
좋다. 아니면 메세지 처리를 일일이 해주어도 좋고.

*클래스의 초기회는 항상 신경을 써주어야 할 부분이다. 특히 한 클래스의 객체가 여러개 있을 경우 확실한 초기화 코드가 없다면 중복 생성후에 실행시 메모리 오류가 날 확률이 아주 높다.
윈도우 클래스라면 OnCreate에서, 다이얼로그 기반이라면 InitDialog에서 꼭!꼭!꼭!해주어야 한다.

*MFC SDI형태의 프로그램을 시작하기 위해서는 CView클래스를 상속받은 OnCreate함수를 통해서 일단 빈문서가 생성가능한지 여부를 타진한 다음에 -1이 반환되지 않으면 프로그램이 시작하게 된다.!! 뽀인트는 CView 클래스가 있다는 사실!

*표준콘트롤은 WM_CREATE류의 메세지를 받아서 실행되는 곳에서 Create를 해주어야 한다. SDI경우 view생성자가 아닌 OnCreate에서 생성해주어야 한다.

*윈도우를 새로 그리게 되는경우(invalidate(true))인 상황에서 윈도우는 두가지 메세지를 만들게 된다.
배경을 지우기 위한 WM_ERAGSEBKGND : 이 메세지를 받게 되면 윈도우는 배경용 브러쉬를 이용해서 윈도우를 그리게 된다. 그것이 일종의 지워지는 효과를 내는 것이다. 호출함수는 OnEraseBkgnd
지워진 배경에 그림을 그리기 위한 WM_PAINT : 이 메세지는 윈도우에 원하는 내용을 새로 그리게 되는 메시지이다. 호출함수는 프레임이 윈도우 그려줄때는 OnPaint, 윈도우가 다큐먼트 그려줄때는 OnDraw.


*MFC SDI에서 원하는 윈도우로 활성화시키는 코드 app.c에서 수정해야 함.
m_pMainWnd->MoveWindow(0,0,880,1000);    //윈도우 크기를 재정의한다.
m_pMainWnd->CenterWindow();        //상위 윈도우를 기준으로 중앙에 윈도우를 생성한다.
m_pMainWnd->ShowWindow(SW_SHOW);    //윈도우를 일정한 크기로 보여준다(min, max에 반해서)
m_pMainWnd->UpdateWindow();


///////////////////////////////////////////////////////////////////////////////
*더블버퍼핑의 구현개념. 메모리에 비트맵을 생성하여 그 비트맵정보에 화면에 그리듯 그린 다음에 윈도우에 그려줘야 할때 메모리에 저장된 비트맵 정보를 한번에 BitBlt함으로써 완성이 된다. 단, WM_ERAGEBKGND메세지에 주의할것.
구현예)
CRect rect;
GetClientRect(&rect);        //비트맵을 그려줄 영역을 위한 Rect
m_dcMem.CreateCompatibleDC(pDC);    //메모리 DC를 생성한다.
CBitmap    bitMem;            //메모리에 그릴 비트맵변수를 선언
bitMem.CreateCompatibleBitmap(pDC,1916, 1060);    //메모리에 비트맵을 설정한다. 그림으로 치면 도화지를 만드는 개념인것.
m_dcMem.SelectObject(&bitMem);    //생성한 비트멥을 메모리에 셋팅해준다.

CBrush    brush(RGB(255,255,255));
m_dcMem.FillRect(rect, &brush);    //단지 배경을 흰색으로 만들어주기 위해서 메모리에 한번 그려준 것일뿐 필요에 따라 얼마든지 바뀔수 있는 부분이고 전체적으로는 메모리에 한번 그려준것뿐이다.
DrawKeyboard(&m_dcMem);        //일련의 그림을 메모리에 그려주고 있다.
   
pDC->BitBlt(0, 0, 1916, 1060, &m_dcMem,0 , 0, SRCCOPY);    //윈도우에 보여주어야 하는 순간에 BitBlt한다.

m_dcMem.DeleteDC();    //항상 BitBlt한 이후에는 DC를 삭제해주어야 한다.
bitMem.DeleteObject();

그리고 WM_ERAGEBKGND에서는 return TRUE;를 추가해준다.   
///////////////////////////////////////////////////////////////////////////////////

*해당하는 포인터를 포함하는 윈도우 핸들을 구하는 방법
1. CWnd* A = WindowFromPoint(&point);
A->m_hWnd;
A->GetSafehwnd();

2. HWND B = WindowFromPoint(&point)

의미상 같아 보이나 반드시 두번째 방법을 써야 한다.CWnd 구조체를 사용하는 것은 메모리 애러에 대한 보장을 해주지 못할 가능성이 아주 크다.

*현재 포커스가 있는 윈도우 기준이 아닌 스크린 기준의 좌표를 구하는 함수 GetCursorPos(&point);


*define 단어를 만들어 사용할 경우 왠만하면 예약어는 사용하지 않도록 한다.
VS의 단어바꾸기는 대소문자를 구별하지 않기때문에 낭패를 볼수있고 전체솔루션 옵션도 사용하지 않도록 한다.

*dll의 클래스를 다른 플젝에서도 사용할수 있게 하기 위한 것 : class AFX_EXT_CLASS class이름.....


*dll 클래스 작성시 클래스 이름 앞에는 AFX_EXT_CLASS를 넣어주고 클래스 선언 안에는 DECLARE_DYNAMIC(CSPYWINDlg)을
클래스 구현 앞에는 IMPLEMENT_DYNAMIC(CSPYWINDlg, CDialog)을 넣어주어야 한다.

*dll의 출력이름을 바꾸어줄 경우 .def에서 LIBRARY 앞에 ";"를 붙여줘야 한다.

*CTreeCtrl은 트리콘트롤이다. 일반적인 사용은 CString 텍스트를 만들어서 각 아이템에 삽입하고 삭제하는 방식으로 사용한다.
하지만 이것은 화면에 보여지는 것에 대한 정보를 다루는 방법이다. 각 아이템에 정보를 저장해서 보여지는 방법과 다르게 다루어야 할때는
SetItemData와  GetItemData를 사용하여야 한다. 가가 아이템의  HTREEITEM 이름을 가지고 데이터를 삽입하고 삭제하거나 접근이 가능할수 있게되는
함수이다. 트리콘트롤은 각 아이템별로 DWORD 값을 하나 가질수 있는 여지를 만들어 놓았다. 그래서 이 DWORD에 어떤 데이터 혹은 데이터를 가진
구조체의 포인터를 넘겨준다면 어떤 형태의 데이터로 각 아이템이 가질수 있게 되는 것이다. 다음은 각 아이템이 핸들을 가질수 있게 만든 코드이다.
ex) 데이터를 삽입할때
HTREEITEM    leaf =     m_pTree.InsertItem(str,0,1,linked,TVI_LAST);
DWORD    item = (DWORD)present->m_hWnd;
m_pTree.SetItemData(leaf,item);

데이터를 획득할때
HTREEITEM    hItem = m_pTree.GetSelectedItem();
if(hItem != NULL)
{
    DWORD    item = m_pTree.GetItemData(hItem);
    m_selected = (HWND)item;
}
와 같이 사용할수 있다.

*::OutputDebugString(_T(".........."))  - 디버깅상태에서 출력창에 메세지를 출력하게 해줄수 있고, 실행상태에서는 디버거에 메세지를 출력할수 있게 해주는 함수
                                               - 디버깅시에 아주  유용함.(현재 디버그뷰 라는 프로그램을 깔았다)

*%appdata% -> 응용프로그램이 실행되면서 필요한 자료를 받을수 있도록 기본경로가 되는 것. 이것으로 각기 다른 환경에서도 프로그램은 원하는 정보를 찾을수 있다.

*::GetCursorPos -> 현재 마우스 위치를 받아오는 함수



Sort와 stable_sort의 차이
일반 sort는 같은 리스트를 연속으로 키가 같은 경우 sort된 내용이 계속 바뀌게 된다. 하지만 stable_sort는 키가 같은 경우 키를 구별할수 있는 무언가를 찾아낸다
그래서 항상 일정한 sort 결과를 만들어 낼수 있다.
참고 stable_sort에 대한 msdn의 설명이다.
Arranges the elements in a specified range into a nondescending order or according to an ordering criterion specified by a binary predicate and
preserves the relative ordering of equivalent elements.

-------------------------------------------------------------------------------------
출처 : http://blog.naver.com/bmwe3?Redirect=Log&logNo=50026775509
Posted by 모니터에습기찼어
객체 삭제시...

MyObject *cObject = new cObject; 로 생성을 해버렸으면...

delete cObject;가 아니다..

항상 까먹지 말고..

if( cObject != NULL){
    delete cObject;
    cObject = NULL;
}

이것을 하나의 덩어리로 보고 코드를 짜자..

내가 자주 까먹는 짓거리 -_ -
Posted by 모니터에습기찼어

원문 : http://kkamagui.springnote.com/pages/551093

들어가기 전에...

  • 이 글은 kkamagui에 의해 작성된 글입니다.
  • 마음껏 인용하시거나 사용하셔도 됩니다. 단 출처(http://kkamagui.springnote.com)는 밝혀 주십시오.
  • 기타 사항은 kkakkunghehe at daum.net 이나 http://kkamagui.egloos.com 으로 보내주시면 반영하겠습니다.

0.시작하면서...


 BSD 소켓 프로그래밍은 MFC 소켓에 비하면 쓰기가 까다롭고 알아야할 부분이 많다. 특히나 윈도우 프로그래밍을 하면 MFC 소켓에 익숙해지기때문에 까먹기가 십상이다.


 이번에 NDS 소켓 프로그래밍을 하면서 우연히 다시 볼 기회가 생겨 정리한다.

1.참고 함수들


1.1 select 함수


 Single Thread로 Multi-Socket을 컨트롤 하는 방법은 여러가지가 있겠지만, 가장 대표적인 것이 select이다. select는 아래와 같은 원형을 가지고 있다.

  1. int select(
      int nfds,
      fd_set FAR* readfds,
      fd_set FAR* writefds,
      fd_set FAR* exceptfds,
      const struct timeval FAR* timeout
    );

 select 함수는 nfds에 설정된 소켓의 수만큼 소켓을 체크하므로 반드시 가장 큰 소켓 번호 + 1의 크기만큼을 nfds로 넘겨줘야 함을 잊지 말자( ex: fd + 1 ) 

 return 값은 아래와 같은 의미를 가진다.



  • 양수 : readfds or writefds or exceptfds 중에 양수 개의 fd가 이벤트가 발생했다.

    • fds에 이벤트가 발생한 fd만 플래그가 설정되므로 FD_ISSET 매크로를 이용해서 해당 socket을 찾을 수 있다.
    • timeout에 남은 시간이 저장되므로 이를 활용하면 추가적인 처리가 가능하다

  • 0 : timeout이 되었다. timeout 값의 경우 0으로 설정되면 무한대로 대기한다.
  • 음수 : readfds에 닫힌 소켓이 있거나 기타 에러가 발생했다.

 fd_set 및 timeval은 구조체로 아래와 같은 형태를 가진다.


  1. typedef struct fd_set {
      u_int fd_count;
      SOCKET fd_array[FD_SETSIZE];
    } fd_set;
  2. struct timeval {
      long tv_sec;  // second 단위
      long tv_usec; // millisecond 단위
    };

 timeval은 위에서 보는 것 그대로 second/millisecond 단위로 설정해서 사용하면 된다.

 하지만 fd_set과 같은 경우 어떻게 사용해야할지 좀 막막하다. 다행이 이를 처리해주는 매크로가 있으니 아래와 같다.

  • FD_ZERO( fd_set* fdset ) :  fdset을 초기화. 처음에는 반드시 한번 호출해야 함
  • FD_SET( int fd, fd_set* fdset ) : fdset에 fd 소켓을 등록한다.
  • FD_CLR( int fd, fd_set* fdset ) : fdset에 fd 소켓을 삭제한다.
  • FD_ISSET( int fd, fd_set* fdset ) : fdset에 fd 소켓이 있는가 확인한다.

 자주 사용하는 매크로이니 한번쯤은 읽어두자. 자세한 사용 방법은 아래의 Linux 예제를 보면 된다.

2.윈도우(Window) 환경

2.1 서버(Server)

#include <winsock2.h>
#include <stdio.h>
#include <string.h>

#define DEFAULT_PORT 2924
#define DEFAULT_BUFFER_SIZE 4096

int main()
{
    char Buffer[DEFAULT_BUFFER_SIZE + 1];
    WSAData wsd;
    if(WSAStartup(MAKEWORD(2, 2), &wsd) != 0) {
        printf("Winsock 초기화 에러!\n");
        return -1;
    }
   SOCKET ls = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
    if (ls == INVALID_SOCKET) {
        printf("소켓 생성 실패!\n");
        return -1;
    }
    sockaddr_in service;
    memset(&service, 0, sizeof(service));
    service.sin_family = AF_INET;
    service.sin_addr.s_addr = INADDR_ANY;
    service.sin_port = htons(DEFAULT_PORT);
 
    if (bind(ls, (SOCKADDR*) &service, sizeof(service)) == SOCKET_ERROR) {
        printf("bind 실패!\n");
        return -1;
    }

    if (listen(ls, 1) == SOCKET_ERROR) {
        printf("listen() 실패!\n");
        return -1;
    }

    SOCKET as;
    printf("클라이언트 연결 대기.\n");
    while (1) {
        as = accept(ls, NULL, NULL);
        if (as == SOCKET_ERROR) continue;
        printf("클라이언트 연결됨.\n");
        int nbyte = recv(as, Buffer, DEFAULT_BUFFER_SIZE, 0);
        if (nbyte <= 0) {
            printf("recv 에러!\n");
            break;
        }      

        Buffer[nbyte] = '\0';
        printf("에코 : %s\n", Buffer);
        send(as, Buffer, nbyte, 0);
        if (strncmp(Buffer, "quit", 4) == 0) {
            printf("클라이언트의 요청에 의해 서버 종료\n");
            break;
        }  
        closesocket(as);
        printf("클라이언트 연결 해제.\n새로운 클라이언트 연결 대기.\n");
    }
    closesocket(ls);
    WSACleanup();

    return 0;
}

2.2 클라이언트(Client)

#include <winsock2.h>
#include <stdio.h>
#include <string.h>
#define DEFAULT_PORT 2924
#define DEFAULT_BUFFER_SIZE 4096

int main(int argc, char** argv)
{
    char Buffer[DEFAULT_BUFFER_SIZE + 1];
    WSAData wsd;
    if (argc != 2) {
        printf ("사용법 : %s [IP 주소]\n", argv[0]);
        return -1;
    }  

    if(WSAStartup(MAKEWORD(2, 2), &wsd) != 0) {
        printf("Winsock 초기화 에러!\n");
        return -1;
    }

    SOCKET cs = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);  

    if (cs == INVALID_SOCKET) {
        printf("소켓 생성 실패!\n");
        return -1;
    }

    sockaddr_in client;
    memset(&client, 0, sizeof(client));

    client.sin_family = AF_INET;
    client.sin_addr.s_addr = inet_addr(argv[1]);
    client.sin_port = htons(DEFAULT_PORT);

    if (connect(cs, (SOCKADDR *)&client, sizeof(client)) == SOCKET_ERROR) {
            printf("connect 에러!\n");
            return -1;
    }

    printf("입력 : ");
    gets(Buffer);
    send(cs, Buffer, strlen(Buffer), 0);
    int nbyte = recv(cs, Buffer, DEFAULT_BUFFER_SIZE, 0);
    Buffer[nbyte] = '\0';
    printf("에코 : %s", Buffer);
    closesocket(cs);
    WSACleanup();  

    return 0;
}


3.Linux or Unix or NDS

3.1 서버(Server)

 윈도우쪽 소스를 조금 수정했다.

#include <sys/socket.h>
#include <netinet/in.h>
#include <netdb.h>

int main()
{
    char Buffer[256 + 1];
    int ls = socket(AF_INET, SOCK_STREAM, 0);

    if (ls == INVALID_SOCKET) {
        printf("소켓 생성 실패!\n");
        return -1;
    }

    sockaddr_in service;
    memset(&service, 0, sizeof(service));

    service.sin_family = AF_INET;
    service.sin_addr.s_addr = INADDR_ANY;
    service.sin_port = htons(DEFAULT_PORT);  

    if (bind(ls, (SOCKADDR*) &service, sizeof(service)) == SOCKET_ERROR) {
        printf("bind 실패!\n");
        return -1;
    }  

    if (listen(ls, 1) == SOCKET_ERROR) {
        printf("listen() 실패!\n");
        return -1;
    }

    int as;
    printf("클라이언트 연결 대기.\n");

    while (1) {
        as = accept(ls, NULL, NULL);
        if (as == SOCKET_ERROR) continue;

        printf("클라이언트 연결됨.\n");
        int nbyte = recv(as, Buffer, DEFAULT_BUFFER_SIZE, 0);

        if (nbyte <= 0) {
            printf("recv 에러!\n");
            break;
        }      

        Buffer[nbyte] = '\0';
        printf("에코 : %s\n", Buffer);
        send(as, Buffer, nbyte, 0);
        if (strncmp(Buffer, "quit", 4) == 0) {
            printf("클라이언트의 요청에 의해 서버 종료\n");
            break;
        }      

        close(as);

        printf("클라이언트 연결 해제.\n새로운 클라이언트 연결 대기.\n");
    }

    close(ls);  

    return 0;
}

3.2 클라이언트(Client)

 NDS에서 사용하는 예제를 조금 수정했다.

#include <sys/socket.h>
#include <netinet/in.h>
#include <netdb.h>

int main(void)
{
    //////////////////////////////////////////////////////////////////////////
    // Let's send a simple HTTP request to a server and print the results!
    // store the HTTP request for later

    const char * request_text =    "GET / HTTP/1.1\r\n\r\n";

    //        "Host:
www.akkit.org\r\n"
    //        "User-Agent: Nintendo DS\r\n\r\n";  
    // Find the IP address of the server, with gethostbyname
    // DNS를 이용해서 Name으로 IP를 얻는다.
    // 2007/10/24 현재, 아직 잘 안되는 것 같다.

    iprintf( "DNS Resolve Start\n" );

    //struct hostent * myhost = gethostbyname( "
www.google.org" );
    //iprintf("Found IP Address![www.google.org] [%08X]\n",
    //        myhost->h_addr_list[0] );

    // Tell the socket to connect to the IP address we found, on port 80 (HTTP)

    struct sockaddr_in sain;
    sain.sin_family = AF_INET;
    sain.sin_port = htons(80);

    // Host Resolve가 끝났으면 아래와 같이 사용한다.
    //sain.sin_addr.s_addr= *( (unsigned long *)(myhost->h_addr_list[0]) );

    // 아래는 google의 IP 주소이다.
    sain.sin_addr.s_addr = inet_addr( "72.14.235.99" );    

    // Create a TCP socket
    int my_socket;
    fd_set readfd;
    fd_set tempfd;

    struct timeval stTime;
    struct timeval stTempTime;

    int iRet;  

    stTime.tv_sec = 5;
    stTime.tv_usec = 0;

Retry:
    my_socket = socket( AF_INET, SOCK_STREAM, 0 );
    iprintf("Created Socket!\n");
    iprintf( "Try To Connect\n" );
    connect( my_socket,(struct sockaddr *)&sain, sizeof(sain) );
    iprintf("Connected to server!\n");

    // send our request
    send( my_socket, request_text, strlen(request_text), 0 );
    iprintf("Sent our request!\n");
    // Print incoming data
    iprintf("Printing incoming data:\n");
    int recvd_len;
    char incoming_buffer[256];
    iprintf("Recv Start\n");

    FD_ZERO( &readfd );
    FD_SET( my_socket, &readfd );

    while( 1 )
    {
        tempfd = readfd;
        stTempTime = stTime;
        iRet = select( my_socket + 1, &tempfd, NULL, NULL, &stTempTime );

        if( iRet > 0 )
        {
            recvd_len = recv( my_socket, incoming_buffer, 255, 0 );
            iprintf("Recv End Size[%d]\n", recvd_len );

            if( recvd_len > 0 )
            { // data was received!
                incoming_buffer[ recvd_len ] = 0; // null-terminate
                iprintf( incoming_buffer );
            }
        }
        // Time Expired
        else if( iRet == 0 )
        {
            iprintf( "Time Expired If You Press B, Exit Receiving Process\n" );

            if( ~REG_KEYINPUT & KEY_B )
            {
                break;
            }
        }
        else
        {
            iprintf( "Error~~!!\n" );
            break;
        }
    }  

    iprintf("Other side closed connection!\n");
    shutdown(my_socket,0); // good practice to shutdown the socket.

    close(my_socket); // remove the socket.  
    iprintf( "Press Any A Key To Retry\n" );

    while( REG_KEYINPUT & KEY_A ) ;    

    goto Retry;
    while(1);
    return 0;
}

4.마치면서...
 간단하게나마 코드 조각을 정리해 보았다. 이제 구글링할 필요없이 바로 붙여넣고 쓰면된다. 다시한번 네트워크의 세계로 빠져보자. 

---------------------------------------------------------------------------
아직도 갈길이 멀구나..

Posted by 모니터에습기찼어
출처 블로그 > Let's Shoveling
원본 http://blog.naver.com/may30jo/70018616184

/* 프로세스 이름으로 프로세스 죽이는 함수 */
bool ProcessKill(CString strProcessName)
{
    HANDLE         hProcessSnap = NULL;
    BOOL           bRet      = FALSE;
    PROCESSENTRY32 pe32      = {0};

    hProcessSnap = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);

    if (hProcessSnap == (HANDLE)-1)
       return false;

    pe32.dwSize = sizeof(PROCESSENTRY32);

    //프로세스가 메모리상에 있으면 첫번째 프로세스를 얻는다
    if (Process32First(hProcessSnap, &pe32))
    {
       BOOL          bCurrent = FALSE;
       MODULEENTRY32 me32       = {0};

       do
       {
         // 모듈을 검색.. 실행파일이 길면 pe32.szExeFile 이걸로 확인불가??
           bCurrent = GetProcessModule(pe32.th32ProcessID,strProcessName);

           if(bCurrent)
           {
               HANDLE hProcess = OpenProcess(PROCESS_ALL_ACCESS,
                                                                     FALSE, pe32.th32ProcessID);

              if(hProcess)
              {
                  if(TerminateProcess(hProcess, 0))
                  {
                     unsigned long nCode; //프로세스 종료 상태
                     GetExitCodeProcess(hProcess, &nCode);
                  }
                 CloseHandle(hProcess);
             }
         }
    }
    while (Process32Next(hProcessSnap, &pe32));

    //다음 프로세스의 정보를 구하여 있으면 루프를 돈다.
  }

  CloseHandle (hProcessSnap);

  return true;
}
/* 프로세스 내의 모듈을 검색하는 함수
* 파일 이름이 길면 모듈의 이름을 검색해서 찾는다
*/
bool GetProcessModule(DWORD dwPID,CString sProcessName)
{
  HANDLE        hModuleSnap = NULL;
  MODULEENTRY32 me32        = {0};

  hModuleSnap = CreateToolhelp32Snapshot(TH32CS_SNAPMODULE, dwPID);
  if (hModuleSnap == (HANDLE)-1)
    return (FALSE);

  me32.dwSize = sizeof(MODULEENTRY32);

  //해당 프로세스의 모듈리스트를 루프로 돌려서 프로세스이름과 동일하면
  //true를 리턴한다.
  if(Module32First(hModuleSnap, &me32))
  {
    do
    {
      if(me32.szModule == sProcessName)
      {
        CloseHandle (hModuleSnap);
        return true;
      }
    }
    while(Module32Next(hModuleSnap, &me32));
  }

  CloseHandle (hModuleSnap);

  return false;
}

/////////////////////////////////////////////////////////////////////////////////
이걸 잘 활용하면 프로세스 중복실행도 방지할수 있다 ㅋㅋㅋ

Posted by 모니터에습기찼어
이번엔 관리좀 잘해야지 ㅎㅎㅎㅎ
Posted by 모니터에습기찼어
TAG 인사