블로그 이미지
Every unexpected event is a path to learning for you.

카테고리

분류 전체보기 (2738)
Unity3D (817)
Programming (475)
Server (33)
Unreal (4)
Gamebryo (56)
Tip & Tech (228)
협업 (58)
3DS Max (3)
Game (12)
Utility (136)
Etc (96)
Link (32)
Portfolio (19)
Subject (90)
iOS,OSX (53)
Android (14)
Linux (5)
잉여 프로젝트 (2)
게임이야기 (3)
Memories (20)
Interest (38)
Thinking (38)
한글 (30)
PaperCraft (5)
Animation (408)
Wallpaper (2)
재테크 (18)
Exercise (3)
나만의 맛집 (3)
냥이 (10)
육아 (16)
Total
Today
Yesterday
05-03 19:49

變/Portfolio "

사용자 삽입 이미지
 프로그램의 자동 업데이트 기능은 인터넷 보급율이 타의 추종을 불허하는 국내에서는 필수적인 요소가 되어 버렸다. V3, 알약 같은 백신은 물론이고, 곰플레이어 등 사용자 Application에도 모두 포함되어 있다.

2년 전쯤에 간단한 기능의 자동 업데이트 프로그램을 만든 적 있었는데; 지인들도 찾지 않는 내 유령 블로그에서 (사실 나도 거의 하지 않는다..) 가장 인기 게시물이었다; 그 프로그램과 관련해 질문도 많이 받고, 링크 복구 요청도 많이 받아... 마지막으로 다시 올린다.

아래 DLL과 자동 업데이트 프로그램은 Microsoft Visual Studio.NET 2005를 이용해 C#으로 개발하였으며, 사용한 모든 함수는 Microsoft .NET Framework 2.0에 포함되어 있다.

 일단 자동 업데이트 프로그램의 구성은 매우 심플하다.
(1) 프로그램 버전 체크를 위한 DLL과 Configuration 파일
- UpdateChecker.dll
- update.ini

(2) 프로그램 업데이트를 위한 자동 업데이트 프로그램과 Configuration 파일
- SmartUpdater.exe
- start.ini

 프로그램의 자동 업데이트 로직은 간단하다. (물론, 복잡하게 만들려면 복잡하게도 만들 수 있으나, 그건 각자의 특수성에 맞게 고민해야할 문제.)

STEP 1. 프로그램을 실행한다.

STEP 2. 업데이트 서버에 연결하여, 현재 프로그램의 버전과 업데이트 서버가 가지고 있는 업데이트 버전과 비교해서 최신 업데이트가 있으면, 자동 업데이트 프로그램을 실행하고, 현재 프로그램을 종료한다.

 물론, 간혹 이런 경우도 있다. 자동 업데이트 프로그램을 업데이트해야 되는 경우; 그 때는 실행하기 전 자동 업데이트 프로그램의 파일명을 rename해서 변경한 후, 실행하면 된다; 그리고 프로그램 업데이트 후, rename된 자동 업데이트 프로그램을 삭제하면 끝;

(1) 프로그램 버전 체크를 위한 DLL의 함수들
사용자 삽입 이미지

DLL의 함수는 달랑 3개다. (하나는 기본 생성자)

ReadConfigFile은 업데이트 서버의 주소와 버전 정보가 담긴 파일명이 저장된 Configuration 파일(update.ini)을 읽는다. 말이 거창하게 Configuration 파일이지, 실제로 파일을 열어보면 달랑 2줄의 내용이 들어있다.

라인 1: http://www.nohungry.net/UpdateServer/
라인 2: version.txt

라인 1은 Update 서버의 URL이고, (반드시 끝에 /를 붙여줘야 한다.)
라인 2는 버전 정보가 저장된 파일명이다.

IsNewUpdateExists는 인자(parameter)로 현재 프로그램의 버전과 업데이트 서버의 버전 정보 파일(http://www.nohungry.net/UpdateServer/version.txt)에 저장된 버전을 비교하여, 현재 프로그램의 버전이 구버전인 경우, true를 반환하고 아니면 false를 반환한다.

GetLastError는 UpdateCheck 시 발생한 에러 메시지를 반환한다. 예를 들면, 업데이트 서버를 연결할 수 없다거나, 새로운 업데이트 파일이 없다는 내용을 반환한다.

(2) 프로그램 업데이트를 위한 자동 업데이트 프로그램
 자동 업데이트 프로그램은 상기 업데이트 체크 DLL에서 새로운 업데이트가 존재할 경우, 호출되는 프로그램이다. 이 프로그램은 업데이트 서버에서 업데이트 파일들을 다운로드 받고, 설치하는 역할을 한다.

 자동 업데이트 프로그램의 Configuration 파일(start.ini) 역시 DLL과 마찬가지로 단순한 정보를 담고 있다.
라인 1: http://www.nohungry.net/UpdateServer/
라인 2: file_list.txt
라인 3: MyNewProgram.exe

라인 1은 업데이트 서버의 URL
라인 2는 업데이트 파일 목록이 저장된 파일명
라인 3은 업데이트 완료 후, 실행할 파일명

사실 업데이트 서버 URL이나 이런 것들은 보안을 생각한다면, 위에 예처럼 무식하게 텍스트 파일로 쓰는 것은 좋지 않다. 이러한 것들은 바이너리로 저장한다거나 아니면 Configuration 파일이 아닌 레지스트리에 쓴다거나 아니면 기타 각자의 아이디어를 이용하도록 하자.

앞서 언급한 DLL과 자동 업데이트 프로그램을 이용해, 내 프로그램에 자동 업데이트 기능을 구현해보자고 한다면, 다음과 같이 할 수 있다. (예외 처리나 기타 복잡한 내용은 빼고, 심플한 코드)

사용자 삽입 이미지

이 게시물에 언급한 모든 내용 및 소스 코드는 아래 링크에서 다운로드 가능합니다.
http://www.nohungry.net/Data/SmartUpdateChecker.zip

관련 게시물 주소
http://www.nohungry.net/tt1/34

이 소스를 그대로 쓰시든지 수정해서 상용으로 쓰시든지 모든 것이 자유입니다. 단, 수정 요청은 받지 않습니다.
또한, 이 소스를 이용해 발생한 어떠한 문제도 책임지지 않습니다.

끝으로 이 게시물의 소스를 다운로드 받아가시거나, 게시물 내용을 블로그에 퍼가시더라도... 댓글이나 출처는 꼭 남겨주세요!


출처 : http://www.nohungry.net/tt1/category/24
반응형
Posted by blueasa
, |

우리는 근래에 자동 업데이트 프로그램에 둘러쌓여 산다.
Windows XP는 시도 때도 없이.. 새로운 패치가 나왔다고 자동 업데이트 하겠냐고 물어보고.-ㅁ-
카트라이더에 로그인 하면.. 알아서 새로운 버젼이 나왔다고 설치한다.

프로그램 개발자에게 있어 새로운 버젼이 나왔는데, 이걸 사용자에게 어떻게 전해주느냐는 중요한 문제다. 사실 사용자에게 새버젼이 나왔을 때 마다 전화해서 알려줄 수도 없으니..

자동 업데이트 프로그램.. 간지나는 디자인이 어디서 본 듯 하다.



내가 맹근 자동 업데이트 프로그램의 흐름은 심플하다.
프로그램을 실행시키면, 프로그램은 업그레이드 서버에 연결하고, 프로그램 내에 이식된 업데이트 체커는 프로그램의 현재 버젼을 읽어와 업그레이드 서버의 업그레이드 정보 파일(단순한 txt 파일)에서 읽은 버젼과 비교한다.

프로그램의 버젼 정보



비교한 결과, 현재 버젼보다 새로운 버젼이 존재하면.. 자동 업데이트 프로그램을 호출해 업그레이드 서버로부터 최신 파일들을 다운 받아 설치한다.

내가 구현한 자동 업데이트 프로그램의 스펙 및 개략적인 소개를 하면 다음과 같다.
(1) SmartUpdater.exe - C#으로 구현했으며, .NET Framework 2.0이 설치되어 있어야 돌아간다. (소스는 공개하지 않음.)
(2) UpdateCheck.h & UpdateCheck.cpp - 사실 이 소스는 내가 구현한 것이 아니라,  CodeProject란 곳의 Alexander Bischofberger란 아저씨가 구현한 소스를 내 입 맛에 맡게 약간의 수정을 거쳤다.
(3) UpdateChecker.exe - 앞 서 언급한 (1)과 (2)를 이용해 만든 예제 프로그램이다. (소스도 공개한다.)



UpdateCheck.h 파일을 열면 위 그림과 같다.

UpdateCheck.h


수정할 부분은 대략 IDS_UPDATE 부터 IDS_UPDATE_NO 정도까지가 되겠다.
IDS_UPDATE는 업그레이드 정보가 담긴 파일의 URL이다. 이 파일의 형식은 다음과 같다.


앞에 3과 4는은 Major Version과 Minor Version이다. 그러니까 내 프로그램의 버젼이 1.0.0.1 이라면 앞의 1과 0이 Major Version과 Minor Version이라 할 수 있다. 그리고 젤 마지막의 URL은 원래 원저작자는 업데이트 페이지로 연결하도록 구현하였는데, 난 그냥 업데이트 프로그램을 로딩시켜서 설치하도록 하였기 때문에, 마지막 URL은 의미가 없다. 그리고 각 항목의 구분자(delim)는 "|(\ 위에 있는 녀석)" 이다.

그 아래 IDS_UPDATE_AVAILABLE은 새로운 버젼을 찾았을 경우, 설치하겠냐고 묻는 문구이다. 그 이하는 읽어보면 대충 감이 올 것이다. (입맛에 맞게 바꾸도록 하자.)

아, 그리고 참고로 #include <wininet.h> 하면 링크 에러가 뜰 것이다-ㅁ-.. "wininet.lib version.lib" 녀석들을 참조하도록 해야된다.

UpdateCheck 사용


그리고, 실제 사용은.. MyProgramApp 내에 InitInstance() 함수 안에서 위의 내용을 써주면 된다. 이 때 _T("SmartUpdater.exe")는 내가 개발한 자동 업데이트 프로그램(업데이트를 위한 웹 서버에서 Update File List를 읽어와 Update File들을 Local PC로 다운로드 하는 역할을 함.)을 호출하는 부분이므로, 각자가 구현한 자동 업데이트 프로그램을 추가해주면 된다.

어떻게 자동 업데이트 프로그램을 구현하였는지는.. 다음 문서에서 자세히 소개하도록 할 예정이다. (전체 소스를 공개하지는 않지만.. 핵심 부분은 알 수 있다.)

모든 소스 코드를 공개하였습니다. 수정 및 재배포도 모두 허용합니다. 대신, 수정 요청이나 디버깅 요청은 사절입니다.

다운로드 : http://www.nohungry.net/Data/AutoUpdateChecker.zip
참조: http://www.codeproject.com/cpp/updatecheck.asp


출처 : http://www.nohungry.net/tt1/34
반응형
Posted by blueasa
, |

C# - C++/CLI - C++ 연결 후,
IME 때문에 일주일여간 삽질한 걸 잊지 않기 위해 Log 남김.(혼잣말)

1) C# 툴에 C++ 클라이언트를 렌더링하게 클라이언트를 수정(exe를 Lib로 만들어버림)
2) 뜨긴 떴는데..한글이 안먹힘..
3) 디버깅 해보니 한글 변환 메시지가 안들어옴
   (WM_IME_NOTIFY는 들어오는데, IMN_SETCONVERSIONMODE 메시지가 안들어옴)
4) 좀 더 확인해보니 툴의 핸들로 IMC를 Get 하려고 했지만 NULL값이 돌아옴..-_-
5) 클라만 따로 돌리면 IMC 획득 잘하고 , 한/영 변환 잘됨.
6) 일주일여간의 온갖 경우의 수를 생각하며, 인터넷 뒤지며(IME 관련 자료 찾기힘듬..) 삽질..
7) 결국, 마지막으로 한 짓은..
    C#의 IME를 죽이고, IME를 직접 생성해서 사용했음. -_-;
    이것도 임시방편 같기도 하고..맞는건지..
    우선 되니깐..진행..


[사용한 IME 관련 API 함수]
        [DllImport("imm32.dll", CharSet = CharSet.Auto)]
        public static extern IntPtr ImmGetContext(IntPtr hWnd);

        [DllImport("imm32.dll", CharSet = CharSet.Auto)]
        public static extern IntPtr ImmReleaseContext(IntPtr hWnd, IntPtr hImc);

        [DllImport("imm32.dll", CharSet = CharSet.Auto)]
        public static extern bool ImmGetConversionStatus(IntPtr hImc, out int fdwConversion, out int fdwSentence);

        [DllImport("imm32.dll")]
        public static extern bool ImmSetConversionStatus(IntPtr hIMC, int fdwConversion, int fdwSentence);

[아래는 IME 생성관련 API 함수]
        [DllImport("imm32.dll", CharSet = CharSet.Auto)]
        public static extern IntPtr ImmCreateContext();

        [DllImport("imm32.dll", CharSet = CharSet.Auto)]
        public static extern IntPtr ImmAssociateContext(IntPtr hWnd, IntPtr hImc);

        [DllImport("imm32.dll", CharSet = CharSet.Auto)]
        public static extern bool ImmDestroyContext(IntPtr hImc);

반응형
Posted by blueasa
, |
반응형
Posted by blueasa
, |


richTextBox에 클립보드로부터 붙이기를 할 때 rtf 포맷으로 붙이기가 될 때가 있다. 그런데, 지금 하려는

작업이 plain text를 붙여야만 하는 경우여서 구글링해봤으나.. 결국은 속임수를 쓰기로...
방법은 richTextBox에서 Ctrl+V 키보드 이벤트를 가로채서 클립보드의 텍스트만 집어넣는 것이다. 간단?

ㅋㅋ 코드는 다음과 같다.


private void richTextBox1_KeyDown(object sender, KeyEventArgs e)
{
    if ((e.KeyCode == Keys.V) && (e.Modifiers == Keys.Control))
    {
        e.Handled = true;
        richTextBox1.SelectedText = Clipboard.GetText();
    }
}

출처 : 모름 -ㅅ-;;

반응형
Posted by blueasa
, |

치킨 명소

Etc / 2010. 9. 9. 14:26


반응형
Posted by blueasa
, |




내용추가 (2010.9.4)
[3]-6번은 미국에만 해당되고 국내는 해당 안된다고 합니다. 
원글 내용 수정했습니다. 

아이폰4를 받고 최초로 동기화하기 전에 반드시 확인해야 할 것들, 
동기화하는 동안에 체크할 것들, 동기화하고 나서 체크할 것들을 
일목요연하게 정리해 놓은 글이 있어서 옯겨봤습니다. 

몇가지를 제외하고는 아이폰 3GS 사용자라면 이미 아는 팁들일 수도 있겠지만 
막상 아이폰4를 받으면 체크 리스트를 만들지 않는 한  
빠짐없이 확인하기가 힘들 것 같아서 미리 정리해 봤어요. 

이 팁은 TUAW에서 가져왔어요. 
대략의 내용만 옮겼으니 좀 더 자세히 보고 싶으신 분은 원문 링크 
를 참조하시구요.  



[1] 아이튠스 동기화 전에 체크할 것들

1. 표면 유리와 연결 부위.
유리에 스크래치는 없는지, 갈라진 틈은 없는지, 
느슨하게 연결된 부위는 없는지, 
앞/뒷면 유리와 스테인레스 부분이 평행을 이루는지 확인.  
틈새가 있으면 내부에 먼지가 유입되는 것은 물론, 
실수로 떨어뜨리는 경우 치명적인 손상을 가져올 수 있습니다.  
틈새가 벌어진 부분은 육안으로 식별하기가 힘들기 때문에 
아주 밝은 불빛 아래서 확대경으로 구석구석 살피는 것이 좋습니다. 


2. 홈버튼/슬립버튼
아이폰을 동기화하기 전 반드시 테스트해야 하는 것들 중 하나.  
너무 느슨하거나 너무 빡빡한지, 
힘을 줘서 눌려야 작동한다면 문제가 있는겁니다.

3. 진동 스위치
진동 스위치가 잘 밀어지는지, 진동이 즉각 적용되는지 확인합니다. 



[2] 아이튠스 동기화 하는 동안 체크할 것들

1. 케이블 접속 불량 여부
케이블을 PC에 연결했을 때 아이튠스에 아이폰이 뜨는지, 충전이 되는지 확인합니다. 
케이블 접속 불량인 경우 컴퓨터와 동기화되지 않거나 충전이 되지 않습니다. 


2. 플래시 메모리
아이폰의 플래시 메모리 칩이 오염된 경우 아이튠스 동기화시 에러가 뜰 수 있어요. 
먼지를 털어낸다던가 컴퓨터 USB 드라이브를 다른 곳에 꽂는 등 
여러가지 시도를 했음에도 불구하고 동기화가 안되다면 
아이폰 플래시 메모리에 문제점이 있는지 의심해 봐야 합니다.
메모리 불량 여부를 테스트하는 가장 간단한 방법은 
처음 동기화할 때 가능한 많은 동영상이나 음악을 넣어보는 것입니다. 
32GB 아이폰4라면 동기화하는데 보통 1-2시간 걸리는 것이 정상입니다.



[3] 동기화 하고 나서 체크할 것들

1. 볼륨 버튼 
볼륨 버튼이 제대로 작동하는지 확인해 봅니다. 


2. 이어폰 잭
아이폰에 딸려온 번들 이어폰을 꽂았을 때 흔들림이 없이 딱 맞는지 확인합니다.  
이어폰으로 음악을 들어보고, 잘 들리지 않는 경우 다른 이어폰으로 테스트해서 
이어폰 문제인지 이어폰 잭 접속부위 문제인지를 확인해 봅니다. 
플레이, 중지, 앞뒤 트랙 넘어가기, 볼륨 등 모든 기능을 확인해 봅니다. 


3. 카메라
사진 몇장을 찍어서 셔터가 잘 열리고 닫히는지 확인해 봅니다. 
아이폰의 "tap to focus" 기능을 테스트해 봅니다.  
거리와 조명의 차이를 두고. 배경을 밝게 하거나. 
화면에서 탭을 했을 때 포커스/밝기가 조절되는지 확인해 봅니다.   
사진찍을 때 스크린 왼쪽 윗부분을 탭해서 
LED 플래시가 작동하는지 테스트 해봅니다.  
동영상을 촬영해 보고, 촬영한 동영상을 플레이할 때 사운드가 들리는지 확인.
찍은 사진에 왜곡이나 문제점이 없는지 확인해 봅니다.  


4. 액셀로메터
아이폰을 가로/세로 로 놓았을 때 화면이 바뀌는지 확인. 
메모 어플로 키보드가 가로세로 모드로 잘 작동하는지 확인
입력 후 흔들면 입력을 취소하겠느냐고 묻는 창이 뜨는지 확인


5. 안테나
3G가 되는 곳에서 신호가 자동으로 잡히는지 확인합니다.   
사파리를 열어서 웹페이지 접속이 잘 되는지 확인해 봅니다. 
속도 차이는 있겠지만, 3G를 사용하는 경우 
페이지가 뜰때까지 몇분씩 기다려야 한다면 안테나를 의심해 봐야 합니다. 


6. EDGE/GPR (요 부분은 미국에만 해당된다고 해요. 국내 사용자는 패스~)
3G 신호가 잡히는 경우, 설정 - 일반 - 네트워크로 가서 
3G사용을 꺼주면 아이폰은 몇초만에 EDGE/GPRS 모드로 변환됩니다. 
사파리로 웹페이지에 접속해 보고 지나치게 속도가 느린지 확인해 봅니다. 
--> 

7. GPS
지도 어플을 열고 왼쪽 아래 화살표 버튼을 눌러서 
현재 위치가 파란색 원으로 표시되는지 확인해 봅니다. 
전파가 약한 지역에 있지 않는 한 현재 위치가 잡힐겁니다. 
아이폰 4의 GPS 안테나는 3GS보다 훨씬 정확하고 강력하기 때문에 
3G의 경우 실내에서 위치를 잡지 못하는 경우가 있지만 
아이폰4는 실내에서도 현재 위치를 잘 잡아줍니다. 
따라서 현재 위치가 잘 표시되어야 정상입니다. 
만일 못잡는다면 실외에서 테스트해 봅니다. 
실외에서도 못잡는다면 문제가 있는 것으로 봐야 합니다. 


8. 블루투스
설정 - 일반 - 네트워크 - 인터넷 테터링 On - 블루투스 활성화
주변의 블루투스 기기를 테스트해 봅니다. 


9. 와이파이
아이폰의 와이파이 옵션을 On 시켜놓은 상태에서 
아이폰이 주변의 모든 무선 네트워크 기기를 인식하는지 확인해 봅니다. 


10. 터치 스크린
아이폰 터치스크린에 데드 스팟이 없는지 확인.
노트 어플이나 사파리 등 텍스트 입력이 가능한 어플을 실행시키고 
"The quick brown fox jumps over the lazy dog" 을 
가로모드, 세로모드(홈 버튼이 왼쪽, 오른쪽으로 가게 놓고)로 입력해 봅니다. 
사진 어플을 실행시켜 사진을 열어 확대해보고, 화면 전체 보기 모드로 놓고 
화면을 손으로 밀어서 사진이 제대로 움직이는지 확인해 봅니다. 


11. LCD
플래시라이트 어플을 받아서 확인해 봅니다. 
백라이트는 설정 - 밝기 조절 - 슬라이더를 좌우로 움직여서 확인해 봅니다.


12. 라이트 센서
어두운 곳에서 설정 - 밝기 메뉴로 제대로 작동하는지 확인해 봅니다. 
밝기 자동 조절 옵션을 켠 상태에서 주변을 어둡게 헤서 밝기가 자동으로 조절되는지 확인해 봅니다.  


13. CPU/GPU
아이폰 4의 프로세서와 그래픽 하드웨어는 
3D 게임에서 뛰어난 성능을 발휘합니다. 
그래픽이 왜곡되거나 겹쳐 보이면 GPU에 문제점이 있는 것입니다. 
 지나치게 뜨거워지거나 버벅거리면 CPU 문제점을 의심해봐야 합니다. 
고화질 무비기 아이폰4에서 잘 보이는지도 확인해 봅니다.


14. 자기 탐지기 
나침반 어플을 실행시켜 우측 하단 버튼을 눌러서 
진북/좌북 변환이 가능한지 확인해 봅니다. 
8가지 위치로 변경해도 신호를 잡지 못하면 문제가 있는 것입니다. 


15. 자이로스코프
아이폰4에는  기본으로 제공되는 자이로스코프 어플이 없습니다. 
무료 어플 Gyroscope를 다운받아서 테스트해 봅니다. 
이 어플을 사용하면 아이폰4의 자이로스코프가 작동하는지 즉각 알 수 있습니다. 



16. 통화 테스트

1) 마이크로폰
스피커폰 모드와 정상 모드에서 통화 테스트를 해봅니다. 
전화를 걸어서 잘 들리는지 확인해 봅니다. 
아이폰4로 통화랄 때 들리지 않는다는 경우도 있었습니다. 
아이폰 4의 마이크로폰 문제점 때문인지, 
노이즈 제거 기능이 지나치게 민감해서 그런 것인지는
아직 확인되지 않은 것 같습니다. 

2) 스피커
이어폰 스피커와 아이폰 하단 스피커가 잘 들리는지, 사운드의 왜곡이 없는지 획인해 봅니다.

3) 근접 센서
아이폰 4 터치 스크린은 아이폰을 귀에 대면 꺼지고, 귀를 떼면 다시 켜져야 정상입니다. 
아이폰 4의 근접 센서가 통화하는 동안 제멋대로 활성회되고 
뺨을 대면 꺼진다는 보고도 있었지만 
이것은 하드웨어 문제점이라기 보다는 iOS 소프트웨어 문제점으로 보입니다.  
만일 센서가 전혀 작동되지 않는다면 하드웨어 문제점으로 보는 것이 좋습니다. 


17. 배터리
배터리에 문제점이 없는지 확인하는 방법은 여러가지가 있지만 
가장 널리 사용되는 방법은 배터리가 완전 소진될 때까지 동영상을 돌리는 것입니다. 
애플에 의하면 동영상 배터리가 완전 소진될 때까지 드는 시간은 약 10시간이라고 합니다. 
하지만 결과의 차이는 항상 존재하기 때문에 
디폴트 화면 밝기에서 완충된 아이폰으로 동영상을 돌려서
배터리가 완전 소진되는데 7시간 정도 걸리면 정상으로 볼 수 있습니다.


위의 모든 테스트는 아이폰4 하드웨어에 전혀 해를 주거나 영향을 주지 않는다고 합니다. 
저는 진리의 화이트를 기다리느라 이번 예판은 눈물을 머금고 참여하지 않았지만.. ㅠㅠ
언제 마음이 변할지 모르겠어서.. 열심히 준비하고 있답니다. ^^

아이폰 4가 손에 들어오면 꼼꼼하게 체크해봐야겠습니다. ^^
반응형
Posted by blueasa
, |

Cecil Lew

네트워크 관리 및 워크플로 처리 같은 대부분의 응용 프로그램 유형에는 다이어그램 작성 인터페이스가 필요합니다. 그러나 Windows 응용 프로그램에서 Visio와 같은 다이어그램 작성 인터페이스를 개발하기는 좀처럼 쉬운 일이 아닙니다. 이 기사에서는 Cecil Lew가 UserControl 및 몇 가지 단순한 클래스를 기반으로 하여 간단한 다이어그램 작성 도구를 빌드하는 방법을 소개합니다.

응용 프로그램에서 다이어그램 작성 기능이 필요한 경우에는 어떻게 하시겠습니까? 이 경우 다음과 같은 네 가지 방법이 있습니다. 즉, 1) 타사 라이브러리를 구입하거나 2) Netron 등의 공개 소스 라이브러리를 사용하거나(확장도 가능함) 3) 응용 프로그램을 Visio와 통합하거나 4) 새 도구를 처음부터 빌드하는 것입니다.

1번이 가장 쉽겠지만 타사 지원에 의존해야 하므로 위험도도 가장 높습니다. 2번도 괜찮은 방법 같지만, 개인적으로 이 방법을 사용해 봤는데 솔직히 25,000줄의 코드로 이루어진 다른 사람이 작성한 라이브러리를 확장하는 것은 쉬운 일이 아닙니다. 3번은 Microsoft Office 커뮤니티에서 많은 지원을 받을 수 있으므로 쉽게 수행할 수 있습니다. 그러나 이 경우 응용 프로그램을 통합하려면 대상 컴퓨터에 올바른 버전의 Visio가 설치되어 있어야 한다는 단점이 있습니다. 여기까지 읽으셨다면 제가 개인적으로 4번을 선호한다는 사실을 눈치채셨을 것입니다. Windows Form 및 GDI+에서는 확대/축소, 변환 및 회전 같은 그리기 및 2D 변환에 뛰어난 기능을 제공합니다.

이 기사에서는 이를 검증하기 위해 개발한 간단한 다이어그램 작성 응용 프로그램에 대해 설명합니다. 먼저 클래스 디자인을 중점적으로 설명한 다음 보다 중요한 기능을 자세히 설명합니다. 이 기사에서 설명하는 응용 프로그램은 C# 및 Windows Form을 사용하여 작성되었습니다. 그림 1은 이 응용 프로그램을 보여 줍니다.

그림 1

왼쪽에는 BlockControl 또는 Connector를 오른쪽의 그리기 영역으로 끌어서 놓을 수 있는 도구 상자가 있습니다. 그리고 컨트롤의 텍스트를 두 번 클릭하여 수정할 수 있습니다. 마지막으로 Connector 핸들을 끌어 BlockControl 주위의 핸들 중 하나에 부착할 수 있습니다.

물론 이 응용 프로그램에서 유용한 기능을 많이 제공하는 것은 아닙니다. 그러나 이 응용 프로그램을 통해 다이어그램 작성 프레임워크의 기초가 되는 상속, 컴퍼지션 및 다양한 C# 구문을 사용하는 방법에 대한 기본 개념을 파악할 수 있습니다.

클래스 디자인
DiagramLib 클래스 라이브러리에는 8개의 클래스가 포함됩니다. 표 1에서는 이러한 클래스 및 해당 용도를 나열합니다.

표 1. DiagramLib 라이브러리의 8개 클래스

클래스 목적
Draggable 이 프로젝트에서 발생하는 대부분의 문제는 개체 이동 및 크기 조정과 관련된 것입니다. 이 일반 Draggable UserControl은 마우스 끌기 동작과 위치 변경을 캡처하기 위한 것입니다.
LabelBox 마우스를 두 번 클릭하면 편집 모드로 전환되는 Label 형식 컨트롤입니다. BlockControl 및 Connector 개체가 사용합니다.
ResizeHandle 크기 조정 작업을 처리하는 BlockControl 주위의 작은 사각형입니다.
ConnectorHandle BlockControl 개체 끌기 및 이 개체에 부착하는 작업을 처리하는 Connector 개체 끝점의 작은 사각형입니다.
DiagramControl BlockControl 및 Connector가 상속을 받는 간단한 클래스입니다. "ID" 등의 일반적인 특성을 제공합니다.
BlockControl 텍스트 입력, 이동 및 크기 조정을 위한 주 다이어그램 작성 컨트롤로, Connector 개체와 연결됩니다.
Connector BlockControl 개체를 선 및 화살표와 연결하는 컨트롤입니다.
DrawingBoard BlockControl 및 Connector 개체를 배치하기 위한 화이트보드입니다.

그림 2그림 3에서는 DiagramLib의 클래스 계층 구조 및 이러한 클래스의 구성/연결을 확인할 수 있습니다. 또한 그림 4에서는 보다 뚜렷하게 다양한 클래스 간의 관계를 이해할 수 있습니다.

그림 2

그림 3

그림 4

Connector를 처리하는 방식에는 두 가지가 있습니다. 첫 번째는 다른 다이어그램 작성 컨트롤과 동일하게 취급하는 것입니다. 즉, Connector를 끌거나 크기를 조정할 수 있습니다. 그러나 보다 중요한 것은 Connector를 다른 화면 개체에 연결하지 않아도 된다는 것입니다. Visio에서는 이 방식을 사용합니다. 두 번째 방식을 사용하는 경우 Connector의 양 끝을 항상 무엇인가에 부착해야 합니다. 그러므로 Connector의 끝점이 아무 것에도 부착되지 않은 상태로 둘 수는 없습니다. Netron에서는 이 방식을 사용합니다. 개인적으로는 첫 번째 방식이 두 번째보다 직관적이라고 생각합니다. 그러므로 이 기사의 디자인은 Visio의 방식을 따릅니다.

다음 섹션에서는 클래스 및 여러 클래스를 함께 사용하는 방법에 대해 자세히 설명합니다.

끌기
Draggable 클래스는 UserControl에서 상속되지만 이 클래스에는 시각적인 구성 요소가 없습니다. 이 클래스는 MouseDown 이벤트 다음에 MouseMove 이벤트와 LocationChanged 이벤트가 뒤따르도록 정의되어 있는 마우스 끌기 동작을 처리합니다. 즉, 화면에서 클래스가 실제로 "끌기"되는 것이 아니라 사용자 정의 이벤트인 DraggableMouseMove, DraggableMouseStop 및 DraggableLocationChanged가 발생하는 것입니다. 이 Draggable 개체의 컨테이너가 실제 이동 또는 크기 조정을 수행합니다. 목록 1에는 Draggable 클래스의 세 가지 마우스 이벤트 처리기인 OnMouseDown, OnMouseUp 및 OnMouseMove가 있습니다.

목록 1. Draggable 클래스의 마우스 처리 루틴
 public event MouseEventHandler DraggableMouseMove; public event MouseEventHandler DraggableMouseStop; protected virtual void OnDraggableMouseStop( MouseEventArgs e) { if (DraggableMouseStop != null) { // 대리자를 호출합니다. DraggableMouseStop(this, e); } } protected virtual void OnDraggableMouseMove( MouseEventArgs e) { if (DraggableMouseMove != null) { // 대리자를 호출합니다. DraggableMouseMove(this, e); } } protected virtual void OnMouseDown(Object o, MouseEventArgs e) { IsMouseDown = true; initX = e.X; initY = e.Y; } protected virtual void OnMouseUp(Object o, MouseEventArgs e) { if (IsMouseDown) { MouseEventArgs evt = new MouseEventArgs( e.Button, e.Clicks, e.X - initX, e.Y - initY, e.Delta); OnDraggableMouseStop(evt); } IsMouseDown = false; } protected virtual void OnMouseMove(object o, MouseEventArgs e) { if (IsMouseDown) { // Delta 값(이동한 거리)만 필요합니다. // e.X는 커서의 상대 위치입니다. MouseEventArgs evt = new MouseEventArgs( e.Button, e.Clicks, e.X - initX, e.Y - initY, e.Delta); OnDraggableMouseMove(evt); } }(참고: 프로그래머 코멘트는 샘플 프로그램 파일에는 영문으로 제공되며 기사에는 설명을 위해 번역문으로 제공됩니다.) 

Draggable 클래스에서는 이벤트 처리기를 제공하는 반면 LabelBox 및 ResizeHandle 클래스에서는 시각적 요소 및 이벤트 처리기 간의 링크를 제공합니다. 예를 들어 ResizeHandle에는 마우스 이벤트를 캡처하고 Draggable 마우스 이벤트 처리기에 작업을 위임하는 Label 컨트롤(lblHandle)이 있습니다.

public ResizeHandle() { ... lblHandle.MouseDown += new MouseEventHandler( base.OnMouseDown); lblHandle.MouseUp += new MouseEventHandler( base.OnMouseUp); lblHandle.MouseMove += new MouseEventHandler( base.OnMouseMove); this.LocationChanged += new EventHandler( base.OnLocationChanged); ... } 

앞서 Draggable 클래스에서 컨트롤의 실제 이동을 처리하지 않음을 언급했습니다. 이는 ResizeHandle 또는 LabelBox도 마찬가지입니다. 이러한 클래스는 DraggableMouseMove 이벤트를 상향 전파하여 부모 BlockControl 개체 또는 Connector 개체가 해당 작업을 처리하도록 합니다.

그림 5는 사용자가 ConnectorHandle을 끌면 클래스가 상호 작용하는 방법을 보여 주는 실제 시나리오 다이어그램입니다.

그림 5

부착 및 부착 해제 프로세스(1부): 부착
Connector의 ConnectorHandle을 BlockControl의 ResizeHandle과 아주 가까운 위치로 끌면 부착이 수행됩니다. 반대로 ConnectorHandle을 연결된 BlockControl에서 비교적 먼 위치로 끌면 연결 부착이 해제됩니다. 이 메커니즘을 설명하려면 BlockControl, Connector 및 ConnectorHandle의 구조를 자세히 살펴봐야 합니다.

BlockControl의 중앙에는 LabelBox가 있고 그 주위에는 8개의 ResizeHandle 개체가 있습니다. ResizeHandle 개체에는 그림 6과 같이 0에서 7까지의 인덱스가 지정되어 있습니다.

그림 6

나중에 살펴보겠지만 ConnectorHandle은 BlockControl에 부착되면 이 번호를 기록하기 때문에, ResizeHandle의 인덱스에는 중요한 의미가 있습니다.

Connector에는 각각 반대쪽 끝에 ConnectorHandle 개체가 두 개 있습니다(그림 7 참조).

그림 7

화면에서 ConnectorHandle을 끌면 모든 기존 BlockControl이 호출되어 해당 ResizeHandle 개체 중 ConnectorHandle에 부착될 수 있을 만큼 가까운 위치에 있는 개체가 있는지 확인합니다. BlockControl의 FindHandle 메서드(목록 2 참조)가 특정 지점으로부터 거리를 계산하여 해당 지점이 충분히 가까운 경우에는 ResizeHandle 인덱스를 반환합니다.

목록 2. BlockControl의 FindHandle 메서드
public int FindHandle(Point p) { const int GLUE_DISTANCE = 20; // 길이 20px int x = this.handles[HD_NW].Left; int y = this.handles[HD_NW].Top; int index = 0; double minDist = double.MaxValue; double dist = 0; for (int i = 0; i < NUM_HANDLE; i++) { ResizeHandle hd = this.handles[i]; dist = Math.Sqrt(Math.Pow(hd.Left - p.X, 2) + Math.Pow(hd.Top - p.Y, 2)); if (dist < minDist) { index = i; minDist = dist; } } if (minDist < GLUE_DISTANCE) { return index; } else { return -1; } } 

그림 8에는 BlockControl이 하나만 있지만 실제로 프로그램에서는 화면의 모든 BlockControl 개체를 호출합니다.

그림 8

BlockControl 개체 중 하나에서 유효한 ResizeHandle 인덱스를 반환하는 경우, 이는 Connector가 해당 BlockControl에 즉시 연결되어야 함을 의미합니다. 그러면 ConnectorHandle 위치가 갑자기 변경되어 맞추기 및 붙이기 형식으로 이동합니다.

ConnectorHandle은 ResizeHandle에서 상속되며 BlockControl에 부착되거나 BlockControl에서 부착이 해제되는 기능이 추가됩니다. ConnectorHandle은 BlockControl에 부착되면 BlockControl 이동을 따르며, 그로 인해 부모 Connector 개체의 크기와 모양을 변경합니다. ConnectorHandle은 부착된 BlockControl 및 ResizeHandle을 기억함으로써 이 작업을 수행합니다.

public class ConnectorHandle: ResizeHandle { private BlockControl connectedBlock; private int blockHandleIndex; ... 

부착 및 부착 해제 프로세스(2부): 부착 후 이동
Connector 및 BlockControl이 서로 부착된 후에 BlockControl의 해당 부분을 끌거나 크기를 조정하면 Connector의 크기도 자동으로 조정됩니다. 이는 ResizeHandle에서 LocationChanged 이벤트를 부모 BlockControl로 전송하면 부모 BlockControl은 연결된 모든 Connector가 해당 ConnectorHandle의 위치를 변경하도록 지시하기 때문입니다(그림 9 참조).

그림 9

부착 및 부착 해제 프로세스(3부): 부착 해제
연결된 BlockControl에서 ConnectorHandle을 끌거나 LabelBox 개체를 끌어 중앙에서 다른 위치로 이동하면 부착 해제가 수행됩니다. 이 작업은 끈 위치가 임계값에 도달할 때까지 마우스 이동을 무시함으로써 수행됩니다.

// ConnectorHandle 클래스 protected override void OnMouseMove(Object o, MouseEventArgs e) { if (this.connectedBlock == null) { base.OnMouseMove(o, e); } else { if (ShouldBreakBinding(e)) { connectedBlock.RemoveConnectorHandle( this, blockHandleIndex); connectedBlock = null; base.OnMouseMove(o, e); } } } private Boolean ShouldBreakBinding(MouseEventArgs e) { return (Math.Sqrt(Math.Pow(e.X,2) + Math.Pow(e.Y, 2)) > 20); } 

Connector의 LabelBox 개체를 끌어서 이동해도 역시 양 끝의 연결이 끊어집니다.

// Connector 클래스 private void Label_DraggableMouseMove(Object o, MouseEventArgs e) { // 핸들 중 하나가 Block 컨트롤에 연결되어 있는 경우 // 저항이 필요합니다. if (handles[0].ConnectedBlockControl != null || handles[1].ConnectedBlockControl != null) { double dist = Math.Sqrt(Math.Pow(e.X, 2) + Math.Pow(e.Y, 2)); if (dist <= 20) return; } ... } 

그림
이 섹션에서는 화면에서 컨트롤을 그리는 방법에 대해 자세히 다룹니다. 일부 컨트롤은 Windows Label로 구성되는 ResizeHandle 같은 Windows 기본 요소만으로 이루어져 있습니다. 그리고 GDI+ 라이브러리를 사용하여 화면 업데이트를 수행하는 컨트롤도 있습니다. 여기서는 GDI+ 관련 컨트롤에 대해 주로 설명합니다.

LabelBox 클래스 LabelBox는 개체의 텍스트 설명을 보여 주는 직사각형 상자입니다(그림 4 참조). BlockControl 및 Connector 클래스는 모두 이 클래스를 사용합니다. 이 클래스를 두 번 클릭하면 텍스트 상자가 표시되어 사용자가 내용을 편집할 수 있습니다. 이름에서 짐작되듯이 이 클래스에는 Label 컨트롤이 포함되어 있다고 생각될 수 있습니다. 그리고 이전 버전까지는 실제로 그랬습니다. 그러나 Label 컨트롤은 새로 고침 속도가 매우 느립니다. 화면에서 함께 움직이는 Label 컨트롤이 5개 이상인 경우에는 속도가 너무 느려서 이상하게 보이기도 합니다. 그러므로 이 LabelBox 버전의 경우에는 GDI+ 호출을 통해 직사각형과 텍스트를 다시 그리도록 했습니다.

// LabelBox 클래스 private void LabelBox_Paint(Object o, PaintEventArgs e) { €| e.Graphics.FillRectangle(backgroundBrush, 0, 0, this.Width, this.Height); e.Graphics.DrawRectangle(textPen, 0, 0, this.Width - 1, this.Height - 1); e.Graphics.DrawString(text, txtEdit.Font, textBrush, 2, 2); } 
Connector DrawingBoard 개체는 화면을 새로 고쳐야 할 때 Connector 개체의 Paint 메서드를 호출합니다. ConnectionStyleEnum 속성이 이 클래스에서 설정할 수 있는 스타일을 지정합니다. 이 값과 각 값을 설정했을 때의 효과가 그림 10에 나와 있습니다.

그림 10

LeftRight 및 UpDown 스타일의 경우 정적 다차원 배열을 사용하여 화살표 회전 각도를 결정합니다.

// Connector 클래스 private static int[,] degrees = new int[4,2]; static Connector() { // 화살촉을 그리기 위한 각도 매트릭스를 초기화합니다. // updown, 핸들 1 위에 핸들 0 degrees[Convert.ToInt16(ConnectorStyleEnum.UpDown), Convert.ToInt16(true)] = 0; // updown, 핸들 1 아래 핸들 0 degrees[Convert.ToInt16(ConnectorStyleEnum.UpDown), Convert.ToInt16(false)] = 180; // leftright, 핸들 1 왼쪽에 핸들 0 degrees[Convert.ToInt16(ConnectorStyleEnum.LeftRight), Convert.ToInt16(true)] = -90; // leftright, 핸들 1 오른쪽에 핸들 0 degrees[Convert.ToInt16(ConnectorStyleEnum.LeftRight), Convert.ToInt16(false)] = 90; } 

정적 생성자가 배열 각도를 초기화합니다. 클래스의 정적 생성자는 응용 프로그램 수명 동안 단 한 번만 호출됩니다. 생성자가 트리거되는 때는 클래스의 첫 번째 인스턴스를 만든 때나 정적 멤버가 처음으로 참조되는 때입니다. 화살표의 회전 각도를 확인하려면 치수를 채우면 됩니다.

// Connector 클래스 private void DrawHandlesArrows(Graphics g) { double h0Deg = 0; double h1Deg = 0; switch (connStyle) { case ConnectorStyleEnum.LeftRight: h0Deg = degrees[(int) connStyle, Convert.ToInt16(handles[0].Left < handles[1].Left)]; break; €| } 

화살촉 좌표가 일련의 점으로 기록됩니다. 그림 11그림 12에는 이러한 점이 각각 좌표축 및 화면 좌표로 표시되어 있습니다.

그림 11

그림 12

선 끝에 올바른 각도로 화살촉을 그리려면 세 가지 변환 작업을 수행해야 합니다.

  • 변환 - 화살촉이 중앙(0, 0)에서 약간 벗어나도록 이동합니다. 이 작업은 화살촉이 ConnectorHandle과 같은 영역에 있지 않도록 하기 위해 수행합니다.

  • 회전 - 선 경사도를 기준으로 정확한 각도를 계산합니다.

  • 변환 - 화살촉을 선 끝으로 이동합니다.

다음 코드 세그먼트에서는 화살촉 생성 및 그림 13에 나와 있는 3단계 변환 과정을 설명합니다.

double grad = (float) (handles[1].Top - handles[0].Top) / (float) (handles[1].Left - handles[0].Left); double deg = Math.Atan(grad) * (180 / Math.PI); €| Point[] p = new Point[] { new Point(0, 0), new Point(5, 7), new Point(0, 5), new Point(-5, 7), new Point(0, 0)}; path.AddLines(p); Matrix m = new Matrix(); m.Translate(x, y); // 직선 끝 m.Rotate((float) deg); m.Translate(0, 5); path.Transform(m); 

그림 13

결론
이 기사에서 소개한 8가지 클래스에는 기본적인 기능만이 포함되지만, 이를 기반으로 하여 보다 수준 높은 프레임워크를 만들 수 있습니다. 즉시 사용할 수 있는 라이브러리가 필요한 경우에는 http://netron.sourceforge.net/ (영문)의 공개 소스 Netron 그래프 라이브러리를 확인해 보십시오.

다운로드 단추를 클릭하면 코드(506LEW.ZIP)를 다운로드할 수 있습니다.

Visual Studio .NET Developer 및 Pinnacle Publishing에 대한 자세한 내용을 보려면 해당 웹 사이트인 http://www.pinpub.com/(영문 사이트)을 방문하십시오.

참고: 이 사이트는 Microsoft Corporation 웹 사이트가 아니므로 Microsoft는 그 내용에 책임을 지지 않습니다.

이 기사는 Visual Studio .NET Developer 2005년 6월호를 바탕으로 다시 쓰여진 것입니다. Copyright 2005, by Pinnacle Publishing, Inc., unless otherwise noted. All rights are reserved. Visual Studio .NET Developer는 Pinnacle Publishing, Inc에서 독립적으로 제작한 발행물입니다. 이 기사의 어떤 부분도 Pinnacle Publishing, Inc.의 사전 동의 없이는 어떤 형식으로도(중요한 기사나 논평에서 간략하게 인용하는 경우는 제외함) 사용하거나 복제할 수 없습니다. Pinnacle Publishing, Inc.에 연락하려면 1-800-788-1900으로 전화 주십시오.


 
출처 : http://www.xdotnet.com/xdotnet/board/BoardRead.aspx?F_Code=11&B_Code=1010&B_Index=1280&B_Page=0
반응형
Posted by blueasa
, |

KeyDown이벤트시에 한글 입력은 무조건 229(?)만 나오기 때문에 어떤 글자를 쳤는지는 알 수가 없지요.

 

그래서 한글 입력은 윈도우 메시지를 가로채서 알아냅니다.

 

먼저 윈도우 메시지를 가로채는 방법은 크게 두가지정도를 생각해 볼 수 있겠는데요,

WndProc 메서드를 오버라이드 하는 방법과 IMessageFilter를 구현해서 가로채는 방법이 있겠습니다.

 

인터넷에 찾아보니 WndProc메서드 오버라이드 하는 방법이 나와있는데 전 이 방법으로는 메시지를 가로챌 수 없더군요..

(왜 안되는지 아시는 분은 답글 남겨 주시기 바랍니다..)

음.. 코딩 환경따라 다른지 모르겠습니다.

참고로 제 환경은 Windows XP Pro 이고 .NET FramWork 1.1 Ver 1.1.4322 환경입니다..

 

 

아무튼.. 메시지 필터를 이용해서 메시지를 가로채기 위해서는

윈폼에서 Application.AddMessageFilter(구현한 필터 클래스) 호출하여 가로채는데

다음과 같은 순서로 하면 되겠습니다.

 

1. 메시지를 가로채서 어떻게 처리할 것인지를 구현한다.

즉 IMessageFilter 클래스를 구현하는것을 의미합니다.

 

구체적으로 이런식으로 구현하면 되겠습니다.

 

    public class MyMessageFilter: IMessageFilter

        {

            #region IMessageFilter 멤버

     

            public const int WM_KEYFIRST = 0x100;

            public const int WM_KEYDOWN = 0x100;

            public const int WM_KEYUP = 0x101;

            public const int WM_CHAR = 0x102;

            public const int WM_IME_STARTCOMPOSITION = 0x10D;

            public const int WM_IME_COMPOSITION = 0x10F;

            public const int WM_IME_ENDCOMPOSITION = 0x10E;

            public const int WM_IME_SETCONTEXT = 0x281;

            public const int WM_IME_NOTIFY = 0x282;

            public const int WM_IME_CONTROL = 0x283;

            public const int WM_IME_COMPOSITIONFULL = 0x284;

            public const int WM_IME_SELECT = 0x285;

            public const int WM_IME_CHAR = 0x286;

            public const int WM_IME_KEYDOWN = 0x290;

            public const int WM_IME_KEYUP = 0x291;

            public const int WM_IME_REPORT = 0x0280;

            public const int WM_IME_REQUEST = 0x0288;

            

            public bool PreFilterMessage(ref Message m)

            {

                // TODO:  MyMessageFilter.PreFilterMessage 구현을 추가합니다.

                Form1 fm = (Form1)Form.ActiveForm;

                

                switch(m.Msg)

                {

                    case WM_IME_STARTCOMPOSITION:

                        fm.WriteLine("한글 조합 시작.." + "\t" + m.WParam.ToString() + "\t" + m.LParam.ToString());

                        break;

     

                    case WM_IME_COMPOSITION:

                        fm.WriteLine("한글 입력 중.." + "\t"+ m.WParam.ToString() + "\t" + m.LParam.ToString());

                        break;

     

                    case WM_IME_ENDCOMPOSITION:

                        fm.WriteLine("한글 조합 완료.." + "\t"+ m.WParam.ToString() + "\t" + m.LParam.ToString());

                        break;

     

                    case WM_IME_SETCONTEXT:

                        fm.WriteLine("WM_IME_SETCONTEXT" + "\t"+ m.WParam.ToString() + "\t" + m.LParam.ToString());

                        break;

                    case WM_IME_NOTIFY:

                        fm.WriteLine("WM_IME_NOTIFY" + "\t"+ m.WParam.ToString() + "\t" + m.LParam.ToString());

                        break;

                    case WM_IME_CONTROL:

                        fm.WriteLine("WM_IME_CONTROL" + "\t"+ m.WParam.ToString() + "\t" + m.LParam.ToString());

                        break;

                    case WM_IME_COMPOSITIONFULL:

                        fm.WriteLine("WM_IME_COMPOSITIONFULL" + "\t"+ m.WParam.ToString() + "\t" + m.LParam.ToString());

                        break;

                    case WM_IME_SELECT:

                        fm.WriteLine("WM_IME_SELECT" + "\t"+ m.WParam.ToString() + "\t" + m.LParam.ToString());

                        break;

                    case WM_IME_CHAR:

                        fm.WriteLine("WM_IME_CHAR" + "\t"+ m.WParam.ToString() + "\t" + m.LParam.ToString());

                        break;

                    case WM_IME_KEYDOWN:

                        fm.WriteLine("WM_IME_KEYDOWN" + "\t"+ m.WParam.ToString() + "\t" + m.LParam.ToString());

                        break;

                    case WM_IME_KEYUP:

                        fm.WriteLine("WM_IME_KEYUP" + "\t"+ m.WParam.ToString() + "\t" + m.LParam.ToString());

                        break;

                    case WM_IME_REPORT:

                        fm.WriteLine("WM_IME_REPORT" + "\t"+ m.WParam.ToString() + "\t" + m.LParam.ToString());

                        break;

                    case WM_IME_REQUEST:

                        fm.WriteLine("WM_IME_REQUEST" + "\t"+ m.WParam.ToString() + "\t" + m.LParam.ToString());

                        break;

     

                    case WM_KEYDOWN:

                        fm.WriteLine("WM_KEYDOWN" + "\t"+ m.WParam.ToString() + "\t" + m.LParam.ToString());

                        break;

                    /*

                    case WM_KEYUP:

                        fm.WriteLine("WM_KEYUP" + "\t"+ m.WParam.ToString() + "\t" + m.LParam.ToString());

                        break;

                    */

                    case WM_CHAR:

                        fm.WriteLine("WM_CHAR" + "\t"+ m.WParam.ToString() + "\t" + m.LParam.ToString());

                        break;

                }

                

                return false;

            }

     

            #endregion

        }//end of class

 

 

2. 윈폼 클래스에서 구현한 필터 클래스를 선언합니다.

 

private MyMessageFilter mmf = new MyMessageFilter();

 

 

 

3. AddMessageFilter()로 메시지 필터를 윈폼클래스에 등록합니다.

 

Application.AddMessageFilter(mmf);

 

폼 생성자 메서드에서 등록하면 되겠네요..

 

 

참.. 제 소스에서는

윈폼 클래스에 다음과 같은 메서드를 추가했었죠..

 

        public void WriteLine(string str)

        {

            this.textBox1.Text += str + "\r\n";

        }

 

이로서 한글을 입력할때 어떤 메시지가 어떻게 발생하는 지 대충 알 수 있으리라고 생각됩니다.

출처 : Devpia


출처 : http://www.xdotnet.com/xdotnet/board/BoardRead.aspx?F_Code=14&B_Code=1052&B_Index=1294&B_Page=0

반응형
Posted by blueasa
, |

using System;
using System.Windows.Forms;
using System.Runtime.InteropServices;

namespace QEControls
{
/// <summary>
/// Summary description for FlickerFreeRichEditTextBox.
/// </summary>
public class FlickerFreeRichEditTextBox : RichTextBox
{

// #define WM_PAINT 0x000F

const short WM_PAINT = 0x00f;
const short WM_IME_NOTIFY = 0x0282;
const int IME_CMODE_NATIVE = 0x1;
//const short IMN_SETCONVERSIONMODE = 0x06;
private IntPtr IMN_SETCONVERSIONMODE = new IntPtr(0x06);

public FlickerFreeRichEditTextBox()
{
//
// TODO: Add constructor logic here
//
//SetStyle(ControlStyles.AllPaintingInWmPaint, true);
//SetStyle(ControlStyles.DoubleBuffer , true);
//SetStyle(ControlStyles.UserPaint , true);
_Paint = true;
this.ScrollBars = RichTextBoxScrollBars.Both;
}

[DllImport ("imm32.dll", CharSet=CharSet.Auto)]
public static extern int ImmGetContext (int hWnd);

[DllImport ("imm32.dll", CharSet=CharSet.Auto)]
public static extern int ImmReleaseContext (int hWnd, int hImc);

[DllImport ("imm32.dll", CharSet=CharSet.Auto)]
public static extern int ImmGetConversionStatus (int hImc, out int
fdwConversion, out int fdwSentence);

private bool _isHangulMode = false;
public bool IsHangulMode
{
get { return _isHangulMode; }
}

public bool _Paint = true;
public bool IsPainting
{
get
{
return _Paint;
}
}
protected override void WndProc(ref System.Windows.Forms.Message m)
{
if (m.Msg == WM_PAINT)
{
if (_Paint)
base.WndProc(ref m);
else
m.Result = IntPtr.Zero;
}
else if ( m.Msg == WM_IME_NOTIFY )
{
if ( m.WParam == IMN_SETCONVERSIONMODE )
{
int hImc, dwConversion = 0, dwSentense = 0;
hImc = ImmGetContext(this.Handle.ToInt32());
ImmGetConversionStatus(hImc, out dwConversion, out dwSentense);
if ( (dwConversion & IME_CMODE_NATIVE) == 1 )
{ // 한글모드
//System.Diagnostics.Trace.WriteLine("한글모드");
_isHangulMode = true;
}
else
{
//System.Diagnostics.Trace.WriteLine("English Mode");
_isHangulMode = false;
}
ImmReleaseContext(this.Handle.ToInt32(), hImc);
}
}
else
{
base.WndProc (ref m);
}
}

public void BeginUpdate()
{
_Paint = false;
}

public void EndUpdate()
{
_Paint = true;
}
}
}

출처 : http://www.ms-news.net/f2235/iso-8859-1-b-cmljahrlehrcb3i-oscw-mfrimh6ua7a1ltptnku-5396626.html
반응형
Posted by blueasa
, |