브런치


그동안 관심을 가지고 지켜보던...
Morfik이 그동안의 몇가지 문제점들을 나름 처리하고선
새로운 모습으로 나타났다.

http://www.morfik.com

이 개발툴은 델파이를 기본적인 개발툴로 하고서는 개발된
RAD 방식의 AJAX개발툴이었다.

설치형태를 봐도 나름 깔끔한 형태로 바뀌었지만...
한편으로는..

그러므로 장점이 하나 손상되기도 했다.

먼저 그동안의 Morfik 1의 가장 큰 문제점이었던..
한글 처리부터 살표보자.


데이터 처리를 위한 테이블의 생성과 데이터 입출력에서 문제가 없다.
정말 깔끔하게 처리된 느낌이다.


폼 디자인 부분에 있어서도...
정말 깔끔하게 잘동작한다.

웹의 RAD툴의 나름대로의 정석을 만들려고 하는듯.

Subform개념으로 형성된 모습은...

웹UI의 특징을 잘 살리면서...
직관적인 RAD툴의 장점을 나름 뛰어나게 살리고 있다.

델파이나 비주얼베이직과 같은 툴에 익숙한
C/S개발자들에게 커다란 개념전환없이
개발툴을 사용할 수 있게 해준다.


다만, Demo 버전이라서 가진 단점이 몇개 초기에 발견되었는데.
그중 가장 큰것은 '데이터베이스'에 연결할 수 없다는 점과...


웹UI를 3개이상 만들지 못한다는 점...
더더군다나...
기본적으로 생성되는 메인의 경우 3개가 기본이기 때문에...

실제 업무에서 사용될 형태를 만들기에는 어려워보인다.

하지만...

말그대로의 Demo이기 때문에...
기능에 대한 테스트를 목적으로 하기에는 나름 충분하다고 생각한다.

아 그리고... 델파이의 Visual Component와 VB의 비주얼 컴포넌트처럼..
Morfik 특유의 '컨트롤 컴포넌트'를 등록시키는 부분이 새롭게 깔끔하게 정리되었다.

아마도...

이 부분이 RAD툴이 가지는 가장 큰 장점이 될것인데...
이 부분들을 얼마나 효과적으로 사용할 수 있을 지가 관건이다.

향후 새롭게 지원되는 툴들을 위함이리라...

.
.
.

다른 부분들에 대해서는...
깔끔한 지원...

웹UI를 기반으로한 델파이나 비주얼 베이직 사용자들을 흡수하기 위한 좋은 대안툴로 보인다.

다만...

Morfik 1에서는 내부 시스템들이 상당수 오픈되어진
델파이의 철학을 계승하고 있어서...
시스템에 다양한 각도의 델파이 컴포넌트들을 변형하여 탑재가 가능했는데..

Morfik2에서는 그런부분들이 많이 봉쇄되었다..

특히나...
메뉴의 한글화 라던지..
( 이 부분은.. 지금 막 설치한지 1시간도 지나지 않았기 때문에... 다른 방법이 있는지도 모르겠다. )

.
.
.

좌우당간...

웹UI를 제작하는 가장 빠른 방법의 개발툴로써
그 위상을 차지할 것인지?

서버사이드의 기반을...
윈도우즈 기반이 아닌 영역까지 활동영역을 높인것인지...
그것들이 정말 궁금하다.

관심이 있으신분은...

네이버 Morfik 까페로 오시죠~

http://cafe.naver.com/morfik
신고
by 꿈꾸는자의 생각의파편들 2008.11.19 16:41

Canon | Canon EOS 350D DIGITAL | Normal program | Pattern | 1/60sec | F/5.6 | 0.00 EV | 55.0mm | ISO-400 | Flash fired, auto mode, red-eye reduction mode | 2008:11:01 13:33:20

2008년 델파이 연합 세미나 2008에 큰 아들 녀석과 같이 참석했네요.
~.~

아들녀석 손잡고.. 세미나에 참석하다니...
정말 색다른 경험이며...

큰 녀석에게 멋진 모습을 보여준 정말 좋은 기회였었네요.

10년후에...
이 곳에 다시금 성장한 모습으로...
나타날 수 있을까요?

~.~
신고
by 꿈꾸는자의 생각의파편들 2008.11.03 09:35
2008년 11월 1일... 열린 델파이 연합세미나 2008. ~.~

Canon | Canon EOS 350D DIGITAL | Normal program | Pattern | 1/60sec | F/4.5 | 0.00 EV | 35.0mm | ISO-400 | Flash fired, auto mode, red-eye reduction mode | 2008:11:01 13:34:39

머.. 세미나를 후원하는 Embarcadero ~.~

Canon | Canon EOS 350D DIGITAL | Normal program | Pattern | 1/60sec | F/4.5 | 0.00 EV | 33.0mm | ISO-400 | Flash fired, auto mode, red-eye reduction mode | 2008:11:01 13:34:48

그리고...
유일하게 걸려있는 델마당... 그리고, 발표 순서... ~.~

Canon | Canon EOS 350D DIGITAL | Normal program | Pattern | 1/60sec | F/5.6 | 0.00 EV | 47.0mm | ISO-400 | Flash fired, auto mode, red-eye reduction mode | 2008:11:01 13:36:49

오! 배너도 걸려있었네요.. ~.~

Canon | Canon EOS 350D DIGITAL | Normal program | Pattern | 1/60sec | F/4.0 | 0.00 EV | 25.0mm | ISO-400 | Flash fired, auto mode, red-eye reduction mode | 2008:11:01 13:32:12

고생하신 스탭진 여러분들...

Canon | Canon EOS 350D DIGITAL | Normal program | Pattern | 1/60sec | F/4.5 | 0.00 EV | 35.0mm | ISO-400 | Flash fired, auto mode, red-eye reduction mode | 2008:11:01 13:32:20

사회를 봐주신 조무영님.. ~.~

Canon | Canon EOS 350D DIGITAL | Normal program | Pattern | 1/60sec | F/5.6 | 0.00 EV | 55.0mm | ISO-400 | Flash fired, auto mode, red-eye reduction mode | 2008:11:01 13:32:52

중간중간... 팁발표를 해주신 이정욱님...

Canon | Canon EOS 350D DIGITAL | Normal program | Pattern | 1/60sec | F/4.0 | 0.00 EV | 18.0mm | ISO-400 | Flash fired, auto mode, red-eye reduction mode | 2008:11:01 13:33:09

자리를 꽉꽉 매운~~ 200여명이 오셨다죠?

Canon | Canon EOS 350D DIGITAL | Normal program | Pattern | 1/60sec | F/5.0 | 0.00 EV | 39.0mm | ISO-400 | Flash fired, auto mode, red-eye reduction mode | 2008:11:01 13:34:07

강의 중이신 이정욱님...

Canon | Canon EOS 350D DIGITAL | Normal program | Pattern | 1/60sec | F/5.6 | 0.00 EV | 55.0mm | ISO-400 | Flash fired, auto mode, red-eye reduction mode | 2008:11:01 13:36:56

포스를 보여주시는 esniper님.. ~.~

Canon | Canon EOS 350D DIGITAL | Normal program | Pattern | 1/60sec | F/5.6 | 0.00 EV | 55.0mm | ISO-400 | Flash fired, auto mode, red-eye reduction mode | 2008:11:01 13:43:00

이정욱님의 발표내용~

Canon | Canon EOS 350D DIGITAL | Normal program | Pattern | 1/60sec | F/4.0 | 0.00 EV | 25.0mm | ISO-400 | Flash fired, auto mode, red-eye reduction mode | 2008:11:01 13:45:07

안영재님과... 김영대님.. ~.~

Canon | Canon EOS 350D DIGITAL | Normal program | Pattern | 1/60sec | F/4.0 | 0.00 EV | 22.0mm | ISO-400 | Flash fired, auto mode, red-eye reduction mode | 2008:11:01 13:49:49

현재.. 델마당 회장이신 사천왕 김제성님과 엠바카데로 한국대표이신 박범용 대표...

Canon | Canon EOS 350D DIGITAL | Normal program | Pattern | 1/60sec | F/5.6 | 0.00 EV | 55.0mm | ISO-400 | Flash fired, auto mode, red-eye reduction mode | 2008:11:01 13:56:02

esniper( 박병익 )님의 발표내용~

Canon | Canon EOS 350D DIGITAL | Normal program | Pattern | 1/60sec | F/5.6 | 0.00 EV | 55.0mm | ISO-400 | Flash fired, auto mode, red-eye reduction mode | 2008:11:01 14:15:39

그리고 한컷 더...

Canon | Canon EOS 350D DIGITAL | Normal program | Pattern | 1/60sec | F/5.6 | 0.00 EV | 55.0mm | ISO-400 | Flash fired, auto mode, red-eye reduction mode | 2008:11:01 15:20:40

안영제님의 발표사진 한컷~

Canon | Canon EOS 350D DIGITAL | Normal program | Pattern | 1/60sec | F/5.0 | 0.00 EV | 39.0mm | ISO-400 | Flash fired, auto mode, red-eye reduction mode | 2008:11:01 13:39:22

이런 확인서를 발급해주더군요...
파란색 도장으로...
사천왕님이 꾸욱 결제.. ㅋㅋ

Canon | Canon EOS 350D DIGITAL | Normal program | Pattern | 1/60sec | F/5.6 | 0.00 EV | 55.0mm | ISO-400 | Flash fired, auto mode, red-eye reduction mode | 2008:11:01 15:20:54

마지막으로...
안영제님의 사진 한컷 더~~

신고
by 꿈꾸는자의 생각의파편들 2008.11.03 09:11


건국대학교 - 새천년기념관...


요거는...
건대입구를 기준으로...

~.~
신고
by 꿈꾸는자의 생각의파편들 2008.10.31 17:49

델파이 커뮤니티 연합세미나의 모든 내용이 확정되었습니다.
아래는 델파이 커뮤니티연합에서 제공하는 세미나 정보입니다.

--------------------------------------------------------------

주  최 : 델파이 커뮤니티 연합
후  원 : Embarcadero Technologies

날  짜 : 2008년 11월 1일(토)
시  간 : 오전 10시부터 오후 6시까지 (오전 9시30분 입장)
장  소 : 건국대학교 새천년관 국제회의실
교통편 : 지하철 2호선 건대입구역 3번출구, 지하철7호선 어린이대공원역 3번출구

참가비 : 온라인 등록 2만원, 현장 등록 3만원

온라인등록 : http://www.delmadang.com/seminar/main.asp

온라인등록기간 : 10/9 ~ 10/27 (조기 마감될 수 있습니다)

세  션 :

  ● Delphi 2009 [Malcolm Groves]
  ● Reverse engineering [박병익]
  ● ToolsAPI를 사용한 델파이 기능 확장하기 [안영제]
  ● Software architecture [신현묵]
  ● Delphi 개발자가 알아두면 좋은 팁 10 가지 [이정욱]

경품 및 기념품 :
  ● 사전등록자 전원에게 다이어리 증정(2만원 상당)
  ● 추첨을 통해 Delphi 2009 professional 증정 (2명)

기  타 :
  ※ 참가확인증을 발급해드립니다.
  ※ 점심식사는 제공되지 않습니다.
  ※ 주차권은 별도로 제공되지 않습니다.
     주차요금은 4시간에 2천원, 종일에 5천원입니다.
     (행사참여 도장 찍어가셔야 합니다)
  ※ 다이어리 디자인은 샘플 이미지와 다소 차이가 있을 수 있습니다.

 

* 추가 소식 *

1.기념품 추가 (델파이 2009 제품가이드)

  참가자 전원에게 델파이 2009 제품가이드가 제공됩니다.
  90 page 분량으로, 
  델파이 2009 의 주요 기능과 달라진 점에 대해 중요한 부분을 전반적으로 훑어볼 수 있습니다.
  예) 비스타 지원 관련 내용
  부록 : 델파이 2009 에서의 유니코드 사용 방법

2.학생 무료

  코드기어에서 학생 참가자의 참가비를 지원하기로 하였습니다.
  학생증과 주민등록증을 지참하시면 무료로 세미나에 참가하실 수 있습니다.
  사전등록을 하신 경우에는 환불해드립니다.

그럼 많은 성원 부탁드리겠습니다.

신고
by 꿈꾸는자의 생각의파편들 2008.10.23 19:59

델파이 4 IDE의 내부 (Internals of Delphi 4's IDE)

이번 장에서는 델파이의 통합개발 환경에 대하여 알아보도록 한다. IDE(Integrated Development Environment)는 어플리케이션을 설계하고, 실행시키고, 테스트할 수 있도록 해주는 환경을 말하는 것으로, 프로그램을 쉽게 개발할 수 있도록 도와주는 기능을 한다. 과거에는 개발자가 통합개발 환경이 없이 텍스트 에디터로 소스를 편집해서, 컴파일러로 컴파일 하고, 전용 디버거로 디버깅을 했었지만 볼랜드에서 터보 C를 내놓으면서 처음으로 통합된 개발 환경을 지원하게 되었다.

그 후, 통합개발 환경은 MS에 의해서도 지원되면서 개발자에게는 점점 더 편리한 환경으로 변모해가고 있는데 델파이 3까지는 다소 부족한 면이 많다고 느껴왔던 통합개발 환경이 델파이 4에서는 많이 향상되어 '역시 볼랜드' 라는 탄성이 나오게 하였다.

그럼 델파이 4의 통합개발 환경에 대해서 알아보는 시간을 가지도록 하자.

메인 윈도우

델파이를 실행시켜서, 프로그램이 모두 로딩되고 나면 다음과 같은 그림이 나타나게 된다.

전체적인 IDE의 형태는 메인 윈도우와 오브젝트 인스펙터, 그리고 코드 에디터와 모듈 탐색기와 폼 디자이너로 구성되어 있다. 일단 처음 실행하면 메인 윈도우와 오브젝트 인스펙터, 폼 디자이너가 보이게 된다. 델파이의 메인 윈도우는 크게 나누어 메뉴바(Menubar), 스피드바(Speedbar), 컴포넌트 팔레트(Component Palette)로 이루어진다.

델파이 4의 IDE에서 델파이 3와 바뀐 점을 든다면, 기본적으로 이런 윈도우 들이 도킹을 지원한다는 것이다. MS 오피스 97에서부터 채용된 이런 형태의 툴바는 이제는 거의 표준이 되어간다는 느낌이다. 오피스 97과 마찬가지로 델파이 4의 메뉴바, 스피드바, 컴포넌트 팔레트도 마음대로 위치를 이동시킬 수도 있고, floating 윈도우로 나타나게 할 수도 있다.

스피드바 (Speedbar)

스피드바는 가장 자주 사용되는 기능들을 쉽고 빠르게 사용할 수 있도록 하기 위해 설계 되었다. 기본적으로 가장 자주 사용될 것으로 예상되는 기능을 모아 놓은 것으로, 이들 기능은 델파이의 메뉴바를 통해 메뉴를 직접 선택하여 사용할 수도 있다. 이들 각각에 대해서는 나중에 주요 메뉴를 설명할 때 자세히 기술하도록 하겠다.

컴포넌트 팔레트 (Component Palette)

컴포넌트 팔레트는 VCL(Visual Component Library)에 포함되어 있는 구성요소를 가리킨다. 이들 항목들은 개발자가 원하는 데로 그룹을 형성할 수도 있지만, 기본적으로는 기능별로 구성되어 있다. 이들 그룹은 페이지 탭의 형태로 나뉘어있다.

개발자는 컴포넌트 팔레트에서 사용하고자 하는 컴포넌트를 클릭해서 선택한 후, 이를 폼에 위치시키거나 더블 클릭하여 폼에 컴포넌트를 추가할 수 있다.

폼 디자이너 (Form Designer)

기본적으로 거의 모든 델파이 어플리케이션은 폼으로 구성된다. 델파이에서 폼은 다른 델파이의 컴포넌트 들을 위치시킬 수 있는 장소로 사용된다.

개발자는 마우스를 가지고 폼의 위치와 크기 등을 마음대로 조절할 수 있으며, 컴포넌트를 폼에 올려 놓고 자신에 입맛에 맞도록 디자인할 수 있게 된다.

오브젝트 인스펙터 (Object Inspector)

오브젝트 인스펙터는 각 컴포넌트의 속성을 변경시키거나, 객체가 반응을 하게 되는 이벤트를 조정하는데 매우 편리한 인터페이스를 제공하고 있다. 오브젝트 인스펙터를 잘 살펴보면, 속성(Properties) 탭과 이벤트(Event) 탭으로 구성되어 있음을 알 수 있다.

속성 탭에서는 객체의 프로퍼티를 살펴보거나 이를 마음대로 수정할 수 있는 기능을 제공하고 있다. 속성 이름의 옆에 + 기호가 나타나는 것은 그 아래에 하위 속성들이 있음을 나타낸다.

예를 들어, 폼을 선택한 다음에 오브젝트 인스펙터에서 Font 속성을 살펴보면 그 옆에 + 기호가 있음을 볼 수 있다. 그리고 Font 속성을 더블 클릭하거나 + 기호를 클릭하면 글꼴에 대한 Color, Height, Name 등의 하위 속성들이 나타나는 것을 볼 수 있다. 이러한 형식은 객체의 속성을 변경시키는데 매우 간단하면서 효과적인 방법을 제공하고 있다.

이벤트 탭에서는 개발자가 선택한 객체에 반응할 수 있는 이벤트를 선택하여, 이 이벤트가 발생할 때 어떤 동작을 취하라고 지정하는 것이 가능하다. 예를 들어, 어플리케이션에서 윈도우를 닫을 때에 어떤 작업을 실행하고자 한다면, 폼의 OnClose 이벤트를 사용하면 된다.

코드 에디터 (Code Editor)와 모듈 탐색기 (Module Explorer)

델파이 4 IDE에서 가장 많은 변화가 있었던 부분을 꼽으라면 코드 에디터와 모듈 탐색기를 들 수 있다. 먼저 폼 뒤에 숨어 있는 코드 에디터를 살짝 클릭하면 다음과 같이 모듈 탐색기와 코드 에디터가 붙어서 나타나는 것을 볼 수 있다.

모듈 탐색기는 클래스의 생성을 자동화하고, 보다 쉽게 유닛 파일 들을 탐색할 수 있는 기능을 제공한다. 디폴트로 모듈 탐색기는 코드 에디터의 좌측에 도킹되어 있다.

모듈 탐색기를 닫으려면, 코드 에디터에서 떼어낸 후 우상부 코너를 클릭한다. 이를 다시 열고자 할 때에는 View|Module Explorer 메뉴를 선택하면 된다.

모듈 탐색기는 유닛에 정의된 모든 데이터 형과 클래스, 프로퍼티, 메소드, 전역 변수와 전역 루틴 등을 보여주는 트리 다이어그램 (tree diagram)을 포함하고 있다. 또한, 여기에는 uses 절에 들어있는 다른 유닛의 내용도 찾아볼 수 있게 되어 있다. 트리 뷰의 노드를 확장하거나 축소하며 뒤져볼 수 있다.

모듈 탐색기와 코드 에디터 사이를 토글하려면, Ctrl+Shift+E 키를 누르거나 또는 우측 버튼을 클릭하고 View Editor 메뉴를 선택한다.

모듈 탐색기는 점진적 검색(incremental searching)을 지원한다. 클래스, 프로퍼티, 메소드, 변수, 루틴 등을 검색하려면 단지 그 이름 만을 적어넣으면 된다. 모듈 탐색기에서 아이템을 선택하면 커서가 코드 에디터에서 연관된 부분으로 이동해 가며, 코드 에디터에서 커서를 이동하면 모듈 탐색기에 적절한 아이템으로 하이라이트된 부분이 옮겨 진다.

또한, 모듈 탐색기의 클래스 완료(class completion), 모듈 탐색 (module navigation) 등의 기능을 이용하면 반복적인 코딩 작업을 자동화할 수 있다.

  • 클래스 완료 (Class completion)

델파이 4의 클래스 완료 기능을 이용하면 새로운 클래스의 뼈대를 자동을 만들어 낼 수 있으므로 코딩에 필요한 노력을 많이 줄일 수 있다.

유닛의 interface 섹션의 클래스 선언부에 커서를 위치시키고, Ctrl+Shift+C 키를 누른다. 이렇게 하면, 델파이는 자동으로 프로퍼티에 해당되는 private read, write 필드에 해당되는 부분의 코드를 생성하고, implementation 섹션에 모든 클래스 메소드에 대한 뼈대 코드를 생성한다.

예를 들어, 다음의 코드를 interface 섹션에 작성했다고 하자.

type

TMyButton = class(TButton)

property Size: Integer;

procedure DoSomething;

end;

여기에 커서를 위치시키고, Ctrl+Shift+C 키를 누르면 interface 섹션에는 다음과 같은 코드가 생성된다.

type

TMyButton = class(TButton)

property Size: Integer read FSize write SetSize;

private

FButtonSize: Integer;

procedure SetSize(const Value: Integer);

그리고, implementation 섹션에는 다음과 같은 코드가 생성된다.

{ TMyButton }

procedure TMyButton.DoSomething;

begin

end;

procedure TMyButton.SetSize(const Value: Integer);

begin

FSize := Value;

end;

클래스 완료 기능은 implementation 섹션에 정의된 메소드에 대한 interface 선언부를 작성하게 할 수도 있다. 방법은 마찬가지로 implementation 섹션의 메소드 정의부에 커서를 위치시키고 Ctrl+Shift+C 키를 누르면 된다.

  • 모듈 탐색 (Module navigation)

델파이 4는 유닛 파일에서 Ctrl+Shift 키와 각종 방향키를 누르면 쉽게 모듈 전체를 탐색할 수 있는 모듈 탐색 기능을 제공한다. 일단 유닛의 interface섹션의 특정 메소드나 전역 프로시저의 prototype에 커서를 위치시키고, Ctrl+Shift+Up 또는 Ctrl+Shift+Down 키를 누르면 그 프로시저나 함수의 구현 부분으로 이동한다. 마찬가지로 구현 부분에서 이들 키를 누르면 interface 섹션의 선언부로 이동하는 토클 키로 작동한다.

  • 코드 브라우저 (Code browser)

코드 에디터에서 Ctrl 키를 누르면서 마우스를 특정 클래스, 변수, 프로퍼티, 메소드 등의 여러가지 identifier 이름 위로 지나가게 하면 마우스 포인터가 손모양으로 변하면서 포인터 위치의 identifier가 하이라이트 되면서 밑줄이 쳐진다. 이를 클릭하면, 코드 에디터는 그 identifier의 선언부로 위치를 옮겨간다. 이때 유닛의 interface 섹션에 선언된 메소드나 루틴의 선언부를 찾으려할 때에는 모듈 탐색 기능을 이용해서 Ctrl+Shift+Arrow 키를 이용하면 된다.

메뉴바 (Menubar)

델파이 환경에서 명령을 실행시키는 방법은 기본적으로 메뉴바의 메뉴를 이용하는 방법과 스피드바를 이용하는 방법, 그리고 마우스의 오른쪽 버튼을 클릭하면 나오는 스피드 메뉴를 선택하는 3가지 방법이 있다.

여기에서 델파이 4에서 제공되는 모든 메뉴에 대한 설명을 하는 것은 지면 낭비일 뿐이므로, 델파이의 도움말 파일을 참고하기 바라며 주요 메뉴에 대해서만 설명하도록 하겠다.

  • File 메뉴

File 풀다운 메뉴에는 프로젝트와 소스 코드 파일에 대한 여러가지 작업 명령들을 포함하고 있다. 프로젝트와 관련이 있는 명령은 New, New Application, Open, Reopen, Save Project As, Save All, Close All 등이 있다. 이것들 외에도 프로젝트에 대해서는 Project 풀다운 메뉴가 특별히 따로 만들어져 있다. 소스코드 파일에 관계되는 명령은 New, New Form, Open, Reopen, Save, Save As, Close, Print이다. 대부분의 명령들이 직관적으로 금방 알 수 있으므로 설명은 생략하고, 몇 가지 명령에 대한 것만 더 알아보도록 하자.

Reopen 메뉴 명령은 최근에 작업했던 프로젝트나 소스 코드 파일을 열 때 사용하는 것으로 오피스 등의 제품을 사용할 때 보는 history와 비슷한 역할을 한다.

New 명령은 Object Repository에 저장되어 있는 아이템을 재사용할 때 사용하는 메뉴로, New Items 대화 상자를 열게 된다. 여기에는 델파이의 각종 위저드를 불러내거나 새로운 어플리케이션의 형태와 기존의 폼을 상속하는 폼, 쓰레드나 DLL, 델파이 컴포넌트와 각종 액티브X와 관련된 아이템 들을 만들어낼 수 있다. Object Repository에 대한 내용은 나중에 따로 설명하도록 하겠다.

Print 명령은 소스 코드나 폼을 인쇄할 수 있는 명령이다.

  • Edit 메뉴

Edit 풀다운 메뉴에는 Undo와 Redo, Cut, Copy, Paste와 같이 전형적인 명령들과 폼이나 코드 에디터 윈도우를 위한 몇 가지 특별한 명령들이 포함되어 있다.

이런 명령들은 윈도우 어플리케이션에서 흔히 쓰이는 것들이기 때문에 몇 번만 직접 사용해보면 어떤 기능을 하는지 쉽게 알 수 있을 것이다.

그 밖에 폼에 관련된 많은 명령어 들이 있다. 폼을 위한 명령어 들은 폼의 스피드 메뉴 (마우스 오른쪽 버튼을 클릭할 때 나타나는 팝업 메뉴)에도 나타나는 것들로 컨트롤을 그리드에 맞추어 정렬하게 하거나, 컨트롤의 앞뒤로 보내는 메뉴, 여러 개의 컨트롤 들을 정렬하거나, 탭 순서를 설정하는 등의 메뉴가 포함된다. 이들 각각에 대한 설명은 도움말을 참고하기 바란다.

참고로 Lock Control 명령의 경우 스피드 메뉴에 나타나지 않는데, 이 명령은 폼 위에서 컴포넌트의 위치가 잘못해서 바뀌지 않도록 하는 역할을 한다. 예를 들어, 어떤 컴포넌트를 더블 클릭하려 했는데 잘못해서 그만 위치를 옮겨 버릴 수도 있는데, 이럴 경우 폼에는 Undo 기능이 없으므로 상당히 곤란할 경우가 있다. 이럴 때에는 폼을 일단 디자인해서 더 이상 바뀔 것이 없다면 그 다음에 컨트롤을 잠궈두면 이런 실수를 막을 수 있다.

  • Search 메뉴

Search 메뉴에는 기본적인 Search(찾기)와 Replace(바꾸기) 명령과 여러 개의 파일에서 찾기를 할 수 있는 Find in Files 명령이 있다. 또한, 찾고자 하는 문자열을 하나씩 적어나가면서 매칭되는 소스 코드를 찾아주는 Incremental Search 명령도 있다.

Find in Files 명령은 찾기를 원하는 문자열을 라디오 버튼을 체크 함에 따라 프로젝트의 소스 파일들과 또는 모든 열려있는 파일들, 또는 특정 디렉토리 안의 모든 파일들 중에서 찾을 수 있도록 해 준다. 검색 결과는 코드 에디터 윈도우 밑에 있는 메시지 영역에 표시되며, 표시된 내용을 더블 클릭하면 그 파일의 내용이 있는 곳으로 코드 에디터가 옮겨가게 된다.

Incremental Search 기능은 상당히 편리하게 사용할 수 있는데, 이 명령의 단축키인 Ctrl+E는 외워두었다가 써먹으면 좋을 것이다. 이 명령은 일단 단축키를 누르고 나서 찾고자 하는 문자열을 찍어나가면, 여기에 맞는 부분으로 계속 이동해 나간다.

Find Error 명령은 컴파일러 에러가 아닌 특정한 런타임 에러를 찾을 때 쓰이는 명령으로 어떤 단독 실행 프로그램을 실행시키는데 심각한 에러에 부딪히게 되면, 델파이는 어떤 내부 주소를 가리키는 숫자를 표시하게 된다. 즉, 컴파일된 코드의 논리적 주소를 표시하는 것인데, 이 값을 Find Error 대화 상자에 입력하면 델파이가 프로그램을 다시 컴파일해서 지정한 주소를 찾아준다. 만약 이 주소를 찾게 되면, 델파이 코드 에디터에 해당 소스 코드 라인을 찾아서 표시한다. 그런데, 에러가 소스 코드에 있는 것이 아니라 라이브러리나 시스템 코드의 문제로 발생하는 경우도 있다. 이런 경우에는 Find Error 명령으로 오류를 발견할 수 없게 된다.

Browse Symbol 명령은 컴파일된 프로그램에서 정의한 모든 심볼들을 살펴볼 수 있도록 하는 명령으로 Object Browser를 불러서 이를 표시해 준다.

  • View 메뉴

View 풀다운 메뉴에는 델파이 환경의 각 윈도우들을 표시하기 위해 사용된다. 델파이 환경의 윈도우라면 프로젝트 관리자(Project Manager), 정지점(Breakpoint) 리스트, 모듈 탐색기와 컴포넌트 리스트 등 여러가지가 있게 되는데, 이들 각각은 직접 실행해보면 어떤 윈도우를 가리키는 것인지 알 수 있을 것이다.

프로젝트 관리자와 정지점에 대한 부분은 델파이 4에서 많이 바뀐 부분의 하나인데 프로젝트 관리자는 조금 뒤에 설명할 것이다.

View 메뉴에는 이렇게 서로 다른 윈도우를 표시하기 위한 명령들 이외에 여러가지 명령들이 포함되어 있다. Toggle Form/Unit 메뉴는 작업하고 있는 폼과 그 폼의 소스 코드 사이를 토글해주는 명령으로, 상당히 자주 쓰이게 되므로 이 명령의 단축키인 F12는 외워두기 바란다. 또한, 편리한 명령으로는 New Edit Window 가 있는데, 이 명령을 선택하면 델파이가 두번째 코드 에디터 윈도우를 열어 준다. 에디터 화면을 두 개 만들어 놓으면 서로 다른 파일을 각각 보이게 해 놓을 수 있고, 한 파일의 서로 다른 부분을 보이게 할 수도 있기 때문에 대단히 편리하다.

마지막 Toolbars 메뉴는 델파이 4에서 추가된 명령으로 서브 메뉴를 살펴보면, 델파이 4의 여러 툴바를 보이게 하거나, 숨기게 할 수 있다.

  • Project 메뉴

Project 풀다운 메뉴는 프로젝트를 관리하고 컴파일하는 명령들을 가지고 있다. Add to Project와 Remove from Project 명령은 폼이나 파스칼 소스 코드 유닛을 프로젝트에 추가하거나 제거할 때 사용된다.

Import Type Library 명령은 타입 라이브러리를 읽어올 때 사용하는 것으로 이 책의 후반부에서 자세히 다루게 되므로 설명을 생략하겠다. Add to Repository는 폼을 Object Repository에 등록하고자 할 때 사용하는 명령으로 자주 사용되는 폼의 모양을 디자인하고, 이를 계속 재사용할 때 유용하다. View Source 명령은 프로젝트의 소스를 보여준다.

델파이 4에서는 프로젝트와 관련된 부분이 많이 향상되었으며, 여기에 관련된 명령들이 Project 풀다운 메뉴에 많이 추가 되었다. 이들을 설명하기 위해서 프로젝트 관리자의 변화된 부분에 대해서 조금 더 알아보도록 하자.

델파이 4의 프로젝트 관리자는 프로젝트 그룹에서 여러 개의 프로젝트 들을 쉽게 관리할 수 있게 해 준다. 프로젝트 그룹은 상호연관성이 있는 프로젝트 들 (DLL과 이를 사용하는 어플리케이션, 멀티-tiered 어플리케이션에서 각각의 tier 등)을 유기적으로 관리하는데 편리하게 사용할 수 있다.

프로젝트 관리자를 이용하면 연관된 모든 프로젝트의 파일 들을 볼 수 있으며, 이들을 디스플레이 하고, 파일을 추가 삭제하고 컴파일하는 등의 여러가지 조작을 할 수 있다. 또한, 이들을 한꺼번에 컴파일 할 수도 있다.

프로젝트 관리자의 메인 화면을 살펴보면 프로젝트 그룹이나 프로젝트에 속해있는 모든 파일 들을 트리의 형태로 관찰할 수 있다. 여기에서 트리의 루트는 프로젝트 그룹이며, 프로젝트 그룹에는 각각의 프로젝트를 나타내는 아이콘을 포함하고 있다. 프로젝트의 종류는 DLL, EXE, 패키지 또는 리소스 등일 수 있다. 프로젝트가 프로젝트 그룹의 일부이면, 프로젝트 관리자는 프로젝트 그룹에 있는 모든 프로젝트 들에 대한 정보를 제공한다. 우측의 파일 뷰에는 프로젝트 내의 모든 소스 파일(.pas, .rc 파일 등)과 이진 객체 파일 (.res, .lib, .obj 파일 등)을 들을 보여 준다.

각각의 프로젝트 파일은 .dpr 확장자를 가지고 있다. 프로젝트 관리자를 이용해서 파일을 추가, 제거하면 델파이는 프로젝트 파일을 자동으로 업데이트 해 준다. 프로젝트 그룹 파일은 .bpg 확장자를 가지고 있으며, 프로젝트 그룹에 프로젝트를 추가, 삭제 할 때마다 내용이 바뀌게 된다.

델파이 4의 프로젝트 관리자의 실제 모습은 다음과 같다.

Create New Target과 Open New Target 명령은 델파이 4에서 새롭게 추가된 것으로 새로운 어플리케이션이나 DLL, 패키지 등의 아이템을 프로젝트 그룹에 추가할 때 사용한다.

또한, 델파이 4에서는 복수 프로젝트를 관리할 수 있는 프로젝트 관리자에 부합하여, 컴파일과 관련된 명령 들이 많이 추가되었다. Compile, Build, Syntax Check 등의 기존 명령 말고도 Make 명령이 추가 되었는데, 이 명령들의 뒤에는 대상이 되는 프로젝트의 이름이 같이 디스플레이된다. 또한, 프로젝트 그룹에 있는 모든 프로젝트를 한꺼번에 컴파일할 때 사용할 수 있는 Complie All Projects, Build All Projects 명령이 추가되었다.

Information 명령도 프로젝트 그룹안에서 컴파일된 특정 프로젝트에 대한 정보를 보여주어야 하므로, Information for [프로젝트 이름]의 형태로 바뀌었다.

Web Deploy, Web Deploy options 명령은 액티브X 폼과 컨트롤에 대한 것으로 이 책의 후반부에서 자세히 다루게 될 것이다.

프로젝트 메뉴의 가장 마지막 명령은 Options 메뉴이다. 여기에서는 컴파일러와 링커 옵션, 어플리케이션 객체의 여러가지 옵션을 설정할 수 있다.

  • Run 메뉴

Run 메뉴는 주로 디버깅에 관련된 내용을 많이 담고 있다. 델파이 환경에서 Run 명령을 선택하면 작성된 어플리케이션은 델파이의 내장 디버거 내에서 실행된다. 물론 이 기능을 환경 옵션에서 해제할 수도 있다. 어쨌든 Run 명령은 델파이를 사용할 때 가장 자주 사용하게 되는 명령이므로 F9 단축키는 외워두는 것이 좋을 것이다.

Parameters 명령은 커맨드 라인을 실행시키려고 하는 프로그램에 전달하고, DLL을 디버그 할 때에는 실행 파일의 이름을 제공하기 위해 파라미터를 설정할 수 있게 한다. 이 명령도 델파이 4에서 향상된 것 중에 하나인데, 기존의 파라미터 설정 탭에 원격으로 디버깅을 할 수 있게 하기 위해 호스트 어플리케이션과 원격지 패스 등을 설정할 수 있도록 변경되었다.

Run 풀다운 메뉴에서 디버깅에 관련된 명령 이외에는 액티브X 개발에 관련된 명령이 몇 가지 있다. Register ActiveX Server와 UnRegister ActiveX Server 명령은 현재 프로젝트에 의해 정의되어 있는 액티브X 컨트롤에 대한 윈도우 레지스트리 정보를 추가하거나 삭제하는 역할을 한다. 또한, Install MTS Objects 메뉴를 통해 마이크로소프트 트랜잭션 서버를 지원하는 객체를 설치할 수 있다.

  • Component 메뉴

Component 메뉴의 명령들은 컴포넌트를 작성하고 이것들을 패키지에 넣거나 패키지를 델파이에 설치하는데 주로 사용된다. New Components 명령은 간단한 컴포넌트 위저드를 호출하여 컴포넌트를 새로 작성하는데 도움을 주며, Install Components, Import ActiveX Library, Install Packages 명령은 새로운 델파이 컴포넌트, 패키지 또는 액티브X 컨트롤을 환경에 추가하여 사용할 수 있도록 해준다. 이들에 대한 더욱 자세한 내용은 제 4부에서 다루게 된다.

Create Component Template 명령은 하나 이상의 컴포넌트를 폼에서 선택하고 이 명령을 호출하면 새로운 컴포넌트의 이름, 팔레트에서의 페이지, 아이콘을 입력하는 대화 상자 등이 나타나는데 이를 이용해 새로운 컴포넌트 템플릿을 구성할 수 있게 해준다.

  • Database 메뉴

Database 풀다운 메뉴에는 Database Form Wizard, SQL Explorer, SQL Monitor 등의 데이터베이스 관련 도구를 호출할 수 있는 메뉴가 모여 있다. 이들을 선택하면 데이터베이스 도구들이 실행되는데, 여기에 대한 자세한 내용은 13장의 내용을 참고하기 바란다.

  • Tools 메뉴

Tools 풀다운 메뉴는 외부 프로그램과 툴들을 실행시키기 좋게 모아놓은 것과 델파이 개발 환경의 옵션을 설정하는 명령, Object Repository의 초기화를 위한 명령이 포함되어 있다.

Environment Options 대화 상자에는 포괄적인 환경 설정, 패키지와 라이브러리 설정, 많은 에디터 옵션, 컴포넌트 팔레트 설정, Object Browser 설정, 코드 인사이트 설정 등을 할 수 있는 많은 페이지가 있다. 이들 각각에 대한 것은 도움말을 참고하기 바란다.

또한, Configure Tools 명령을 이용하면 자신이 자주 쓰는 외부의 도구를 등록했다가 쉽게 불러쓸 수 있다. 여기서 간단히 메모장(Notepad)을 등록해 보도록 하자.

Configure Tools 명령을 선택하면 대화 상자가 나타나는데, 여기서 Add 버튼을 클릭하면 등록할 도구의 속성을 설정할 수 있는 대화 상자가 보인다. 속성을 다음과 같이 설정하도록 하자.

Browse 버튼을 클릭해서 추가하고자 하는 도구의 실행 파일을 선택하고, 이 도구가 메뉴에 나타나게 될 타이틀과 작업 디렉토리를 설정하고 OK를 선택하면 Tools 메뉴에 메모장이 추가되며, 이를 선택하면 메모장이 실행된다.

  • 그 밖에도 Workgroup과 Help 메뉴가 있는데, Workgroup 메뉴에는 델파이의 버전 컨트롤 프로그램인 PVCS를 실행시키는 명령이 포함되어 있으며 Help 메뉴에서는 도움말을 불러올 수 있다.

객체 저장소 (Object Repository)

델파이 1.0의 Gallery는 템플릿의 저장과 폼 위저드의 기능으로 사용되었다. Gallery는 델파이 2.0 이후부터 객체 저장소로 바뀌게 되었다. Tools 메뉴에서 Repository를 선택하면 다음과 같은 대화상자가 나타나게 된다.

페이지 리스트 박스에는 Forms, Dialogs, Projects, Data Modules, Object Repository의 5가지 선택 항목이 나타난다. 이 대화상자를 사용하면 선택 항목을 편집하거나 새로운 폼이나 프로젝트를 생성할 때 사용되는 기본 값을 변경시킬 수도 있다. 여기서는 개발자 자신의 페이지를 생성하거나 Object Repository 대화 상자에서 저장소(Repository)로 추가시킬 수 있다.

이러한 객체 저장소의 기능은 델파이에서 코드의 재사용 기능을 더욱 강력하게 만들어 주고 있다. 대부분의 가장 일반적으로 사용되는 기능들은 이미 기본적으로 제공되고 있지만, 개발자 자신의 것들을 생성하여 추가하면 그 활용도는 훨씬 높을 것이다.

델파이에서 File|New메뉴를 선택했을 경우에 델파이는 객체 저장소를 연다. 객체 저장소의 여러 페이지 중에서 New 페이지와 ActiveX 페이지에는 여러 가지 형태의 새로운 아이템을 만들 수 있도록 한다.

다음 그림의 객체 저장소 대화 상자 밑에 있는 라디오 버튼을 눌러서 기존의 아이템을 복사할 것인지, 아니면 상속할 것인지, 그대로 사용할 것인지를 지정하게 되는데 위저드의 경우 처럼 이런 내용을 선택할 수 없는 경우에는 라디오 버튼의 기능이 비활성화 상태로 나타난다.

객체 저장소에 제공되는 기본 아이템에 대해 모두 설명하는 것은 지면 관계상 생략하도록 하고, 델파이 4에서 새롭게 제공되는 것이 어떤 것들이 있는지 알아보도록 하자. 델파이 4에서는 객체 저장소에 새로운 위저드를 많이 지원하는데, 여기에는 다음과 같은 것들이 있다. 이들 각각에 대한 자세한 내용은 해당되는 장을 참고하기 바란다.

  • CORBA Data Module Wizard:

데이터 모듈이 CORBA를 지원하도록 해주는 위저드이다.

  • MTS Data Module Wizard:

데이터 모듈이 마이크로소프트 트랜잭션 서버를 지원하도록 하는 위저드이다.

  • Project Group: 새로운 프로젝트 그룹을 생성한다.
  • Resource DLL Wizard:

세계화를 위해서 필요한 위저드로 문자열을 여러 나라의 언어로 지정할 수 있는 쉬운 방법을 제공하며, 하나의 프로젝트를 여러 나라 버전으로 저장 관리할 수 있게 해준다.

  • Service Wizard: 윈도우 NT 서비스를 생성해주는 위저드이다.
  • Service Application Wizard: 윈도우 NT 서비스 어플리케이션을 생성해준다.
  • COM object Wizard: COM 객체를 생성해주는 위저드이다.
  • MTS Automation Object Wizard: MTS 자동화 객체를 자동으로 생성해준다.

정 리

이번 장에서는 델파이 4의 IDE에 대해서 간단하게 알아보았다. 더욱 자세하게 설명할 수도 있겠으나, 이 책에서는 주로 다른 책에서는 다루지 못한 여러 가지 테크닉 들을 많이 소개하려고 하기 때문에 단순히 도움말을 찾아보면 알 수 있는 내용들은 되도록 생략하였다. 더 자세한 사항은 도움말을 직접 참고하기 바란다.

델파이 4는 그동안 개발자들이 불편해하던 많은 부분을 해결한 멋진 IDE를 제공하고 있다. 복수로 프로젝트를 관리할 수 있게 되었고, 모듈 탐색기를 통해 interface 섹션과 implementation 섹션 사이의 이동과 코드 에디터 내부에서의 탐색 기능의 효율을 높였다.

신고
by 꿈꾸는자의 생각의파편들 2008.07.30 09:21

이것이 델파이 4 ! (This Is Delphi 4 !)

델파이 4는 현재 사용할 수 있는 가장 유연하면서도 강력한 개발 도구이다. 델파이 4는 비주얼 인터페이스 디자인과 강력한 객체지향 언어로서의 특징을 가지고 있는 오브젝트 파스칼 언어를 통합하고 있다. 개발자는 이를 이용하여 빠르면서도 직관적이고, 견고한 Win32 어플리케이션을 쉽게 개발할 수 있다.

이번 장에서는 델파이 4에서 새롭게 선보이는 여러 가지 기능과 특징 들을 소개한다. 처음으로 델파이를 접하는 사람들에게는 다소 어려운 내용이 될 수도 있으나, 대부분의 내용이 나중에 다시 자세히 언급될 것이므로 그냥 한 번 읽어두는 것도 좋을 것이다.

흔히 차를 새로 홍보할 때 보면, 그 기능은 잘 몰라도 각종 기술 이름을 들먹여가며 '이 차에는 이런, 저런 기능을 추가했습니다. ' 라는 문구를 많이 보게 되는데, 이번 장의 내용이 그렇다고 보면 된다.

몰라보게 좋아진 IDE

델파이 4에서 가장 향상된 점을 들라고 하면, 그동안 항상 비슷하게 유지되던 IDE의 모습이 상당히 많이 바뀐 점이다. 과거로부터 바라왔던 부분들이 반영되어 편리한 개발 환경이 되었다. 보다 자세한 사항은 다음 장에서 다루게 된다.

  • Form 디자이너에 기본적인 마우스 좌표지원

    델파이 4의 폼 디자이너에서는 컨트롤의 위치를 표시하는 힌트 윈도우를 이용하여 좌표를 표시해주는 기능이 추가되었다.

  • 윈도우 98의 듀얼 모니터 기능 지원

    윈도우 98의 듀얼 모니터 기능을 이용하여 코드 에디터를 여러 개의 모니터로 나누어 사용하거나, 실행 파일을 따로 보는 것 등이 가능해졌다.

  • 프로젝트 관리자 (Project Manager)

과거의 단일 프로젝트 그룹 방식에서 여러 개의 프로젝트를 동시에 관리할 수 있는 프로젝트 관리자를 지원한다.

이를 이용해서 멀티-tiered 어플리케이션의 각각의 어플리케이션 또는 DLL과 이를 사용하는 어플리케이션과 같이 서로 관계 있는 프로젝트 들을 동시에 관리하며 개발이 가능하다

  • 클래스 완료 (class completion), 모듈 탐색 (module navigation), 코드 브라우저 (code browser)를 포함한 모듈 탐색기 (Module Explorer)

새로운 모듈 탐색기는 클래스를 만드는 여러 과정을 자동화하여 클래스의 생성 과정을 쉽게 만들었다. Interface 섹션에서 메소드의 prototype을 기록하고, 모듈 탐색기에게 skeleton code를 작성하도록 하면, implementation 섹션에 기본 코드가 생성된다. 유닛 파일에서 interface, implementation 섹션 사이에서 객체를 탐색할 수 있는 기능도 포함되어 있다.

  • 도킹 툴 윈도우 (Dockable tool windows)

IDE의 각 윈도우가 오피스 97과 같이 도킹이 가능한 형태로 바뀌었다. 각각의 툴 윈도우를 drag-and-drop 만으로 원하는 위치에 둘 수 있다. 모듈 탐색기와 프로젝트 매니저 역시 도킹이 가능하다.

오브젝트 파스칼의 확장

델파이 4는 오브젝트 파스칼에 여러가지 언어적인 확장을 가져왔다. 여기에는 다음과 같은 것들이 있다.

  • 동적 배열
  • 메소드 오버로딩
  • 디폴트 파라미터
  • 64비트 정수형
  • 32비트 unsigned 정수형
  • 실수형의 변화
  • 인터페이스 구현 방식에 대리자(delegation) 허용

이들에 대한 자세한 내용은 4, 5, 7장의 내용을 참고하기 바란다.

디버깅 기능의 강화

델파이 4는 C++ 빌더 3에서 볼 수 있었던 여러 가지 디버깅 기능이 새로 추가되었다. 새로운 인스펙터와 CPU 윈도우, 모듈 윈도우와 이벤트 로그를 이용하여 보다 편리한 디버깅 환경을 제공한다. 또한, 원격 어플리케이션에 대한 디버깅과 다중 프로세스 디버깅을 지원하므로 멀티-tiered 어플리케이션의 개발이 용이하다.

추가된 CPU 윈도우 화면은 다음과 같다.

향상된 VCL

델파이 4에서는 VCL의 구조가 다소 향상되었다. 변경된 부분만 나열하면 다음과 같은 것들이 있다.

  • 액션 리스트(Action Lists)는 메뉴나 각종 버튼에 의한 사용자 명령을 중앙에서 집중하여 관리할 수 있도록 해준다.
  • 윈도우 NT에 대한 프로그램을 개발할 때 서비스 프로그램으로 활용할 수 있도록 TServiceApplication, TService 클래스를 제공한다. 또한, New items 대화상자에는 여기에 대한 위저드를 2가지 제공하고 있다.
  • TControl과 TWinControl이 도킹을 지원하도록 변경되었으며, TControl에는 윈도우의 크기를 변경하지 못하게 설정할 수 있는 기능이 추가 되었다.    
  • Ini 파일에 대한 지원도 확대되었다. 레지스트리와 ini 파일을 동시에 지원하는 TRegistryIniFile 클래스, 그리고 Ini 파일의 변화를 메모리에 캐쉬했다가 저장하는 TMemIniFile 클래스가 추가되었다.
  • TParams 클래스의 유닛 위치가 dbtables에서 db로 바뀌었는데, 이는 TClientDataSet 클래스에 파라미터를 지원하게 하기 위한 것이다. 그리고, 스크롤 바가 좌측에 있다거나 텍스트를 우측에서 좌측으로 표현하는 등의 세계화에 걸맞는 프로퍼티가 추가되었다.
  • 기본적인 TObject 클래스에 BeforeDestruction, AfterConstruction 이라는 2개의 새로운 protected 메소드가 추가되었다. BeforeDestruction은 객체가 destructor를 호출하기 직전에 호출되며, AfterConstruction은 객체가 constructor를 호출한 직후에 호출된다. TObject를 상속한 클래스들은 이들 메소드를 override하여 constructor나 destructor에서 일어나면 안되는 작업이 일어나지 않게 한다. 예를 들어, 폼의 경우 이들 메소드를 오버라이드하여 OnCreate, OnDestroy 이벤트를 발생시키는데, 이것이 중요한 이유는 컴포넌트가 델파이 뿐만 아니라 C++ 빌더에서도 사용될 수도 있기 때문이다. 즉, 오브젝트 파스칼과 C++의 constructor, destructor의 행동에 차이가 있기 때문에 이 문제를 해결하기 위한 것이다.
  • 윈도우 98을 지원하는 새로운 컨트롤이 추가되었다. 여기에는 TControlBar, TPageScroller, TComboBoxEx, TMonthCalendar, TFlatScrollbars등의 컴포넌트가 있다.

클라이언트 데이터 세트의 향상

델파이 4에서는 BDE를 사용하지 않고도 여러가지로 활용할 수 있는 클라이언트 데이터 세트 컴포넌트가 보다 강화되어 그 효용성이 더욱 높아졌다.

TClientDataSet 컴포넌트는 BDE를 사용하지 않고, DBClient.DLL 파일 만을 사용해서 데이터베이스의 기능을 활용할 수 있게 해준다. 클라이언트 데이터 세트를 사용할 때에는 데이터베이스 연결이 필요하지 않으므로 TDatabase 컴포넌트도 사용하지 않는다.

클라이언트 데이터 세트는 데이터에 접근, 편집, 탐색, 데이터 제한과 필터링 기능까지 제공하고 있다.

멀티-tiered 어플리케이션 지원의 강화

델파이 4에서는 멀티-tiered 어플리케이션에 대한 지원이 더욱 강력해졌다. 여기에는 다음과 같은 것들이 있다.

  • Refresh/resync 지원
  • 데이터 패킷에 대한 지원
  • 중첩된 테이블을 이용한 마스터/디테일 관계 지원
  • 브로커 커넥션의 후킹
  • 클라이언트 데이터 세트에서 파라미터를 어플리케이션 서버에 넘기거나 사용자 정의 정보를 데이터 패킷에 저장할 수 있다.
  • 쉬운 서버 인터페이스 호출
  • TDataSetProvider라는 새로운 클래스를 통한 데이터 세트 지원
  • 어플리케이션 서버에 접속하는데 필요한 다양한 연결 컴포넌트
  • 서버 소켓의 콜백 지원과 NT 서비스 지원
  • Midas의 OLE Server지원

데이터베이스 기능 향상

테이블 컴포넌트가 폼 디자이너에서 테이블을 생성, 이름 변경, 삭제할 수 있도록 향상되었다. 테이블 컴포넌트를 디자이너에서 선택하고, 오른쪽 버튼을 클릭한다. 여기에서 적당한 메뉴를 선택하면 된다.

또한 새로운 BDE 엔진은 액세스 97과 오라클 8, 인포믹스 9.0, 인터페이스 5.1을 지원한다. 또한, 델파이 4에서는 SQL을 확장하여 오라클 8의 새로운 확장성을 지원하게 되었다. 즉, ADTs(Abstract Data Types), 배열, 참조, 중첩된 테이블 등을 지원한다. 이를 위해 새로운 TField 데이터 형인 TADTField, TReferenceField, TArrayField를 지원한다. 또한, ADTs와 중첩된 테이블을 보여주기 위해 Grid 컴포넌트를 향상시켰다. 또한, 기존의 Visual Query builder에 새로운 쿼리 기능을 추가한 SQL builder를 제공한다.

그리고, 객체지향 데이터베이스 모델을 지원한다.

마이크로소프트 트랜잭션 서버(MTS) 지원

MTS는 DCOM 어플리케이션의 트랜잭션 서비스와 보안, 리소스 관리를 하는 견고한 런타임 한경이다. 델파이 4는 MTS 자동화 위저드를 제공하여 MTS 자동화 객체를 생성할 수 있으며, 이를 이용해 MTS 환경의 여러가지 잇점을 사용할 수 있다. 또한 MTS 서버 객체 위저드를 이용하면 서버 객체를 쉽게 생성할 수 있다. MTS는 COM 클라이언트와 서버를 생성하고, 이를 구현하는데 편리한 많은 서비스를 제공한다. MTS 컴포넌트는 많은 하위 레벨 서비스를 제공하는데, 여기에는 다음과 같은 것들이 있다.

  • 동시에 많은 사용자들이 사용할 수 있는 서버 어플리케이션을 만들기 위해 프로세스나 쓰레드, 데이터베이스 연결 등의 시스템 리소스를 관리한다.
  • 트랙잰션을 자동으로 시작하고, 이를 관리한다.
  • 필요할 때 서버 컴포넌트를 생성, 실행, 삭제한다.
  • 보안을 제공하기 때문에, 인증된 사용자만 어플리케이션에 접근할 수 있다.

MTS는 어플리케이션의 비즈니스 로직을 MTS 자동화 객체나, MTS 원격 데이터 모듈에

구현한다. 컴포넌트를 DLL에 구현하면, DLL은 MTS 런타임 환경으로 설치된다. 델파이에서 MTS 클라이언트는 독립적인 어플리케이션으로 사용되거나 또는 액티브 폼일 수 있다. COM 클라이언트는 어느 것이나 MTS 런타임 환경에서 동작할 수 있다.

액티브X/COM 지원의 강화와 CORBA의 지원

델파이 4는 기존의 COM에 대한 지원을 한층 강화하였다. COM에 대한 강화된 지원 내용을 열거하면 다음과 같은 것들이 있다.

  • COM 객체를 생성해주는 COM 객체 위저드가 추가 되었다.
  • 타입 라이브러리 에디터를 이용해서 IDL에 호환되는 타입 라이브러리 소스를 생성할 수도 있고, 델파이 3에서 문제가 되던 것들을 해결하였다. TypeLib2 규격을 지원한다.
  • VB 데이터 인터페이스를 지원한다.

자세한 내용은 제 5부의 내용들을 참고하기 바란다.

델파이 4에서는 COM 이외에 산업 표준으로 자리잡고 있는 CORBA를 지원하게 되었다. CORBA에 대한 지원 사항을 나열하면 다음과 같은 것들이 있다.

  • CORBA에서 JAVA의 IDL을 지원
  • CORBA 데이터 모듈 위저드 제공
  • CORBA 커넥션 컴포넌트의 제공
  • One-Step CORBA 지원

새로운 인터넷 컴포넌트의 지원

델파이 4에서는 인터넷 컴포넌트가 매우 많이 늘어났다. 우선, 델파이 3에서는 ocx 파일로 제공되던 인터넷 컴포넌트 들이, Net Master에서 제공하는 native 컴포넌트로 제공된다. Net Master의 인터넷 컴포넌트에는 다음과 같은 것들이 있다.

  • TNMDayTime, TNMTime, TNMEcho, TNMFinger, TNMMsg, TNMMsgServ
  • TNMFTP, TNMHTTP, TNMNNTP, TNMSMTP, TNMPOP3, TNMUDP
  • TNMUUProcessor, TNMStrm, TNMStrmServ, TNMPowersock
  • TNMGeneralServer, TNMURL

그 밖의 변화

그 밖에도 델파이 4에서는 다음과 같은 여러 가지 기능이 추가되었다.

  • RC 리소스 스트링 테이블 에디터 (Resource String Table Editor) 지원
  • DFM에디터 추가
  • 리소스 프로젝트 (Resource Project) DLL 위저드 지원
  • OpenHelp로 온라인 Help 시스템

정 리

이번 장에서는 델파이 4에서 새롭게 달라진 내용에 대해서 알아보았다. 자세한 내용에 대한 설명은 앞으로 이 책을 읽어가다 보면 알 수 있게 될 것이다.

델파이 4는 지금까지의 델파이의 여러가지 단점을 보강한 명품이며, 가장 최근의 개발 기법을 활용할 수 있는 여러가지 도구를 지원한다.

그러면, 델파이 4의 세계로 여행을 떠나 보자 !

신고
by 꿈꾸는자의 생각의파편들 2008.07.30 09:19

팁모음집

금주가 몇번째 주인지 어떻게 구합니까

function kcIsLeapYear( nYear: Integer ): Boolean; // 윤년을 계산하는 함수

begin

Result := (nYear mod 4 = 0) and ((nYear mod 100 <> 0) or (nYear mod 400 = 0));

end;

function kcMonthDays( nMonth, nYear: Integer ): Integer; // 한달에 몇일이 있는지를 계산하는 함수

const

DaysPerMonth: array[1..12] of Integer = (31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31);

begin

Result := DaysPerMonth[nMonth];

if (nMonth = 2) and kcIsLeapYear(nYear) then Inc(Result);

end;

function kcWeekOfYear( dDate: TDateTime ): Integer; // 위의 두 함수를 써서 몇번째 주인지 계산하는 함수

var

X, nDayCount: Integer;

nMonth, nDay, nYear: Word;

begin

nDayCount := 0;

deCodeDate( dDate, nYear, nMonth, nDay );

For X := 1 to ( nMonth - 1 ) do

nDayCount := nDayCount + kcMonthDays( X, nYear );

nDayCount := nDayCount + nDay;

Result := ( ( nDayCount div 7 ) + 1 );

end;

긴 파일명 사용하기

function fileLongName(const aFile: String): String;

var

aInfo: TSHFileInfo;

begin

if SHGetFileInfo(PChar(aFile),0,aInfo,Sizeof(aInfo),SHGFI_DISPLAYNAME)<>0 then

Result:=StrPas(aInfo.szDisplayName)

else

Result:=aFile;

end;

네트워크 검색

connections or persistent (won't normally get here):}

r:=WNetOpenEnum(ListType,ResourceType,RESOURCEUSAGE_CONTAINER, nil,hEnum);

{ Couldn't enumerate through this container; just make a note of it and continue on: }

if r<>NO_ERROR then

begin

AddShareString(TopContainerIndex,'');

WNetCloseEnum(hEnum);

Exit;

end;

{ We got a valid enumeration handle; walk the resources: }

while (1=1) do

begin

EntryCount:=1;

NetResLen:=SizeOf(NetRes);

r:=WNetEnumResource(hEnum,EntryCount,@NetRes,NetResLen);

case r of

0: begin

{ Yet another container to enumerate; call this function recursively to handle it: }

if (NetRes[0].dwUsage=RESOURCEUSAGE_CONTAINER) or (NetRes[0].dwUsage=10) then

DoEnumerationContainer(NetRes[0])

else

case NetRes[0].dwDisplayType of

{ Top level type: }

RESOURCEDISPLAYTYPE_GENERIC,

RESOURCEDISPLAYTYPE_DOMAIN,

RESOURCEDISPLAYTYPE_SERVER: AddContainer(NetRes[0]);

{ Share: }

RESOURCEDISPLAYTYPE_SHARE: AddShare(TopContainerIndex,NetRes[0]);

end;

end;

ERROR_NO_MORE_ITEMS: Break;

else begin

MessageDlg('Error #'+IntToStr(r)+' Walking Resources.',mtError,[mbOK],0);

Break;

end;

end;

end;

{ Close enumeration handle: }

WNetCloseEnum(hEnum);

end;

procedure TfrmMain.FormShow(Sender: TObject);

begin

DoEnumeration;

end;

// Add item to tree view; indicate that it is a container:

procedure TfrmMain.AddContainer(NetRes: TNetResource);

var

ItemName: String;

begin

ItemName:=Trim(String(NetRes.lpRemoteName));

if Trim(String(NetRes.lpComment))<>'' then

begin

if ItemName<>'' then ItemName:=ItemName+' ';

ItemName:=ItemName+'('+String(NetRes.lpComment)+')';

end;

tvResources.Items.Add(tvResources.Selected,ItemName);

end;

// Add child item to container denoted as current top:

procedure TfrmMain.AddShare(TopContainerIndex: Integer; NetRes:TNetResource);

var

ItemName: String;

begin

ItemName:=Trim(String(NetRes.lpRemoteName));

if Trim(String(NetRes.lpComment))<>'' then

begin

if ItemName<>'' then ItemName:=ItemName+' ';

ItemName:=ItemName+'('+String(NetRes.lpComment)+')';

end;

tvResources.Items.AddChild(tvResources.Items[TopContainerIndex],ItemName);

end;

{ Add child item to container denoted as current top;

this just adds a string for purposes such as being unable to enumerate a container. That is, the container's shares are not accessible to us.}

procedure TfrmMain.AddShareString(TopContainerIndex: Integer;ItemName: String);

begin

tvResources.Items.AddChild(tvResources.Items[TopContainerIndex],ItemName);

end;

{ Add a connection to the tree view.

Mostly used for persistent and currently connected resources to be displayed.}

procedure TfrmMain.AddConnection(NetRes: TNetResource);

var

ItemName: String;

begin

ItemName:=Trim(String(NetRes.lpLocalName));

if Trim(String(NetRes.lpRemoteName))<>'' then

begin

if ItemName<>'' then ItemName:=ItemName+' ';

ItemName:=ItemName+'-> '+Trim(String(NetRes.lpRemoteName));

end;

tvResources.Items.Add(tvResources.Selected,ItemName);

end;

// Expand all containers in the tree view:

procedure TfrmMain.mniExpandAllClick(Sender: TObject);

begin

tvResources.FullExpand;

end;

// Collapse all containers in the tree view:

procedure TfrmMain.mniCollapseAllClick(Sender: TObject);

begin

tvResources.FullCollapse;

end;

// Allow saving of tree view to a file:

procedure TfrmMain.mniSaveToFileClick(Sender: TObject);

begin

if dlgSave.Execute then

tvResources.SaveToFile(dlgSave.FileName);

end;

// Allow loading of tree view from a file:

procedure TfrmMain.mniLoadFromFileClick(Sender: TObject);

begin

if dlgOpen.Execute then

tvResources.LoadFromFile(dlgOpen.FileName);

end;

// Rebrowse:

procedure TfrmMain.btnOKClick(Sender: TObject);

begin

DoEnumeration;

end;

end.

네트워크 드라이브 등록하기

procedure TStartForm.NetBtnClick(Sender: TObject);

var

OldDrives: TStringList;

i: Integer;

begin

OldDrives := TStringList.Create;

OldDrives.Assign(Drivebox.Items); // Remember old drive list

// Show the connection dialog

if WNetConnectionDialog(Handle, RESOURCETYPE_DISK) = NO_ERROR then

begin

DriveBox.TextCase := tcLowerCase; // Refresh the drive list box

for i := 0 to DriveBox.Items.Count - 1 do

begin

if Olddrives.IndexOf(Drivebox.Items[i]) = -1 then

begin // Find new Drive letter

DriveBox.ItemIndex := i; // Updates the drive list box to new drive letter

DriveBox.Drive := DriveBox.Text[1]; // Cascades the update to connected directory lists, etc

end;

end;

DriveBox.SetFocus;

end;

다른 윈도우에서 선택된 문자열 복사하기

procedure TForm1.WMHotkey(Var msg: TWMHotkey);

var

hOtherWin,

hFocusWin: THandle;

OtherThreadID, ProcessID: DWORD;

begin

hOtherWin := GetForegroundWindow;

if hOtherWin = 0 then

Exit;

OtherThreadID := GetWindowThreadProcessID( hOtherWin, @ProcessID );

if AttachThreadInput( GetCurrentThreadID, OtherThreadID, True ) then

begin

hFocusWin := GetFocus;

if hFocusWin <> 0 then

try

SendMessage( hFocusWin, WM_COPY, 0, 0 );

finally

AttachThreadInput( GetCurrentThreadID, OtherThreadID, False );

end;

end;

Memo1.Lines.Add( Clipboard.AsText );

if IsIconIC( Application.Handle ) then

Application.Restore;

end;

다른 Application에 Data전달하기

WM_COPYDATA-다른 Application에 Data전달

unit other_ap;

{다른 Application을 찾아서 WM_COPYDATA로 DATA를 전달 }

interface

uses

Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs, StdCtrls;

const WM_COPYDATA = $004A;

type

Tform1 = class(TForm)

Button1: TButton;

Memo1: TMemo;

procedure Button1Click(Sender: TObject);

private

{ Private declarations }

procedure WMCopyData(var m : TMessage); message WM_COPYDATA;

public

{ Public declarations }

end;

var

form1: Tform1;

implementation

{$R *.DFM}

type

PCopyDataStruct = ^TCopyDataStruct;

TCopyDataStruct = record

dwData: LongInt;

cbData: LongInt;

lpData: Pointer;

end;

type

PRecToPass = ^TRecToPass;

TRecToPass = packed record

s : string[255];

i : integer;

end;

procedure TForm1.WMCopyData(var m : TMessage);

begin

Memo1.Lines.Add(PRecToPass(PCopyDataStruct(m.LParam)^.lpData)^.s);

Memo1.Lines.Add(IntToStr(PRecToPass(PCopyDataStruct(m.LParam)^.lpData)^.i));

end;

procedure Tform1.Button1Click(Sender: TObject);

var

h : THandle;

cd : TCopyDataStruct;

rec : TRecToPass;

begin

if Form1.Caption = 'My App' then

begin

h := FindWindow(nil, 'My Other App');

rec.s := 'Hello World - From My App';

rec.i := 1;

end

else

begin

h := FindWindow(nil, 'My App');

rec.s := 'Hello World - From My Other App';

rec.i := 2;

end;

cd.dwData := 0;

cd.cbData := sizeof(rec);

cd.lpData := @rec;

if h <> 0 then

SendMessage(h, WM_CopyData, Form1.Handle, LongInt(@cd));

end;

end.

델파이 중복실행방지

 unit PrevInst;

 interface

 uses

  WinTypes, WinProcs, SysUtils;

 type

  PHWND = ^HWND;

  function EnumFunc(Wnd:HWND; TargetWindow:PHWND): bool; export;

  procedure GotoPreviousInstance;

 implementation

  function EnumFunc(Wnd:HWND; TargetWindow:PHWND): bool;

  var

    ClassName : array[0..30] of char;

  begin

    Result := true;

    if GetWindowWord(Wnd,GWW_HINSTANCE) = hPrevInst then

    begin

      GetClassName(Wnd,ClassName,30);

      if StrIComp(ClassName,'TApplication') = 0 then

      begin

        TargetWindow^ := Wnd;

        Result := false;

      end;

    end;

  end;

  procedure GotoPreviousInstance;

  var

    PrevInstWnd : HWND;

  begin

    PrevInstWnd := 0;

    EnumWindows(@EnumFunc,longint(@PrevInstWnd));

    if PrevInstWnd <> 0 then

      if IsIconic(PrevInstWnd) then

        ShowWindow(PrevInstWnd, SW_RESTORE)

      else

        BringWindowToTop(PrevInstWnd);

  end;

end.

  이러한 유닛을 프로젝트에 추가 하신후 DPR 소스의 BEGIN - END를 다음과 같이

  수정해 주세요

begin

  if hPrevInst <> 0 then

    GotoPreviousInstance

  else

  begin

    Application.CreateForm(MyForm, MyForm);

    Application.Run;

  end;

end.

델파이에서 한글 토글하기

델파이 2.0이하에서는

ims.pas를 이용하여 한영토글을 구현했는데,

3.0이상 에서는 한영토글에 대한 간단한 답에 있더군요.

TEdit에 ImsMode 프라퍼티를 이용합니다.

edit1.ImeMode:=imHangul; //한글모드

edit2.ImeMode:=imAlpha; //영문모드

입력이 한글이 많을 경우,

입력 초기모드를 한글모드로 바꿔준다면,

사용자의 한/영키를 누르는 것을 없애줄 수 있겠지요.

델파이에서 자동으로 한글입력모드로 변경시키는 소스

uses절에 Imm을 추가하세요

그런다음 아래 프로시저를 작성하여 OnEnter 이벤트에서

한글을 on하시구요 OnExit 이벤트에서 off하세요

procedure TForm1.SetHangeulMode(SetHangeul: Boolean);

var

  tMode : HIMC;

begin

  tMode := ImmGetContext(handle);

  if SetHangeul then  // 한글모드로

    ImmSetConversionStatus(tMode, IME_CMODE_HANGEUL,      IME_CMODE_HANGEUL)

  else                // 영문모드로

    ImmSetConversionStatus(tMode, IME_CMODE_ALPHANUMERIC,

IME_CMODE_ALPHANUMERIC);

end;

델파이에서 폼을 사정없이 뜯어내는 방법의 소스

var

WindowRgn,HoleRgn : HRgn;

begin

WindowRgn := 0;

GetWindowRgn(handle, WindowRgn);

DeleteObject(WindowRgn);

WindowRgn := CreateRectRgn(0,0,Width,Height);

HoleRgn := CreateRectRgn(16,25,126,236);

CombineRgn(WindowRgn, WindowRgn, HoleRgn, RGN_DIFF);

SetWindowRgn(handle, WindowRgn, TRUE);

DeleteObject(HoleRgn);

end;

델파이에서의 키값

아래에 가상키 값 리스트입니다....

vk_LButton = $01;

vk_RButton = $02;

vk_Cancel = $03;

vk_MButton = $04; { NOT contiguous with L & RBUTTON }

vk_Back = $08;

vk_Tab = $09;

vk_Clear = $0C;

vk_Return = $0D;

vk_Shift = $10;

vk_Control = $11;

vk_Menu = $12;

vk_Pause = $13;

vk_Capital = $14;

vk_Escape = $1B;

vk_Space = $20;

vk_Prior = $21;

vk_Next = $22;

vk_End = $23;

vk_Home = $24;

vk_Left = $25;

vk_Up = $26;

vk_Right = $27;

vk_Down = $28;

vk_Select = $29;

vk_Print = $2A;

vk_Execute = $2B;

vk_SnapShot = $2C;

{ vk_Copy = $2C not used by keyboards }

vk_Insert = $2D;

vk_Delete = $2E;

vk_Help = $2F;

{ vk_A thru vk_Z are the same as their ASCII equivalents: 'A' thru 'Z' }

{ vk_0 thru vk_9 are the same as their ASCII equivalents: '0' thru '9' }

vk_NumPad0 = $60;

vk_NumPad1 = $61;

vk_NumPad2 = $62;

vk_NumPad3 = $63;

vk_NumPad4 = $64;

vk_NumPad5 = $65;

vk_NumPad6 = $66;

vk_NumPad7 = $67;

vk_NumPad8 = $68;

vk_NumPad9 = $69;

vk_Multiply = $6A;

vk_Add = $6B;

vk_Separator = $6C;

vk_Subtract = $6D;

vk_Decimal = $6E;

vk_Divide = $6F;

vk_F1 = $70;

vk_F2 = $71;

vk_F3 = $72;

vk_F4 = $73;

vk_F5 = $74;

vk_F6 = $75;

vk_F7 = $76;

vk_F8 = $77;

vk_F9 = $78;

vk_F10 = $79;

vk_F11 = $7A;

vk_F12 = $7B;

vk_F13 = $7C;

vk_F14 = $7D;

vk_F15 = $7E;

vk_F16 = $7F;

vk_F17 = $80;

vk_F18 = $81;

vk_F19 = $82;

vk_F20 = $83;

vk_F21 = $84;

vk_F22 = $85;

vk_F23 = $86;

vk_F24 = $87;

vk_NumLock = $90;

vk_Scroll = $91;

디렉토리에 관련된 함수

function GetCurrentDir: string; // 현재의 Directory

function ExtractFileDir(const FileName: string): string;

// Directory 만 Return .Filename 빼고

function ExtractFileName(const FileName: string): string;

// 화일 이름만 Return

동작중인 프로그램 죽이기

unit Unit1;

interface

uses

Windows, Messages, SysUtils, Classes, Graphics, Controls,

Forms, Dialogs, StdCtrls, TlHelp32;

type

TForm1 = class(TForm)

ListBox1: TListBox;

B_Search: TButton;

B_Terminate: TButton;

procedure B_SearchClick(Sender: TObject);

procedure B_TerminateClick(Sender: TObject);

private

{ Private declarations }

public

{ Public declarations }

end;

var

Form1: TForm1;

implementation

{$R *.DFM}

// kernel32.dll을 사용하여 현재 떠있는 process를 읽어온다

procedure Process32List(Slist: TStrings);

var

Process32: TProcessEntry32;

SHandle: THandle; // the handle of the Windows object

Next: BOOL;

begin

Process32.dwSize := SizeOf(TProcessEntry32);

SHandle := CreateToolHelp32Snapshot(TH32CS_SNAPPROCESS, 0);

if Process32First(SHandle, Process32) then

begin

// 실행화일명과 process object 저장

Slist.AddObject(Process32.szExeFile, TObject(Process32.th32ProcessID));

repeat

Next := Process32Next(SHandle, Process32);

if Next then

Slist.AddObject(Process32.szExeFile, TObject(Process32.th32ProcessID));

until not Next;

end;

CloseHandle(SHandle); // closes an open object handle

end;

procedure TForm1.B_SearchClick(Sender: TObject);

begin

// 현재 실행중인 process를 검색

ListBox1.Items.Clear;

Process32List(ListBox1.Items);

end;

procedure TForm1.B_TerminateClick(Sender: TObject);

var

hProcess: THandle;

ProcId: DWORD;

TermSucc: BOOL;

begin

// 현재 실행중인 process를 kill

if ListBox1.ItemIndex < 0 then System.Exit;

ProcId := DWORD(ListBox1.Items.Objects[ListBox1.ItemIndex]);

// 존재하는 process object의 handle을 return한다

hProcess := OpenProcess(PROCESS_ALL_ACCESS, TRUE, ProcId);

if hProcess = NULL then

ShowMessage('OpenProcess error !');

// 명시한 process를 강제 종료시킨다

TermSucc := TerminateProcess(hProcess, 0);

if TermSucc = FALSE then

ShowMessage('TerminateProcess error !')

else

ShowMessage(Format('Process# %x terminated successfully !', [ProcId]));

end;

end.

레지스트리를 이용한 모뎀찾기

WRegistry := TRegistry.Create;

with Wregistry do

begin

rootkey := HKEY_LOCAL_MACHINE;

if OpenKey

('\System\CurrentControlSet\Services\Class\Modem\0000',False) then

Showmessage ('모뎀이 있습니다.');

...

free..

end;

마우스의 Enter/Exit Event사용하기

TForm1 = class(TForm)

Image1 : TImage;

private

m_orgProc : TWndMethod;

procedure ImageProc ( var Msg : TMessage ) ;

public

procedure FormCreate(Sender: TObject);

procedure FormDestroy(Sender: TObject);

end;

:

:

procedure TForm1.FormCreate(Sender:TObject);

begin

m_orgProc := Image1.WindowProc;

Image1.WindowProc := ImageProc;

end;

procedure TForm1.FormDestroy(Sender:TObject);

begin

Image1.WindowProc := m_orgProc;

end;

procedure TForm1.ImageProc( var Msg : TMessage );

begin

case Msg.Msg of

CM_MOUSELEAVE:

begin

// 여기서 콘트롤에 마우스가 들어왔을 때를 처리합니다.

end;

CM_MOUSEENTER:

begin

// 여기서 콘트롤로부터 마우스가 벗어날때 부분을 처리합니다.

end;

end;

m_orgProc(Msg);

end;

end;

마우스의 범위 제한하기

다음 예제는 폼에 2개의 버튼을 두고 첫번째 버튼을 누르면 마우스가 폼 밖으로 못나가게 하고, 두번째 버튼을 누르면 원래대로 바꿔주는 프로그램입니다...

procedure TForm1.Button1Click(Sender: TObject);

var

Rect : TRect;

begin

Rect := BoundsRect;

InflateRect(Rect, 0, 0);

ClipCursor(@Rect);

end;

procedure TForm1.Button2Click(Sender: TObject);

begin

ClipCursor(nil);

end;

Message박스에 두줄출력하기

MessageDlg('문자열' + chr(13) + '문자열', mtInformation,[mbOK], 0);

참고 : 윈도우에서는 3줄까지 가능함. 3줄 이상의 문자열은 자동으로 정렬하지

않으니 개발자가 주의해야 함.

바탕화면 바꾸기

  GetMem( ThePChar , 255 );

  StrPCopy( ThePChar , 'wallpaper.bmp');

  SystemParametersInfo( SPI_SETDESKWALLPAPER , 0 ,

                        ThePChar , SPIF_SENDWININICHANGE );

  Freemem( ThePChar , 255 );

브라우저 동작하기

UrlMon 유닛으로 선언되고 있다 HlinkNavigateString Win32 API 을(를) 씁니다.

호출 예:

HlinkNavigateString(Nil,'http://www.borland.co.jp/');

만약 액티브 폼의 중(안)에서 불러내고 싶는 경우에는 이하와 같이 지정합니다:

HlinkNavigateString(ComObject,'http://www.borland.co.jp/');

ShellApi 유닛으로 선언되고 있다 ShellExecute 을(를) 쓰는 것도 가능합니다.

ShellExecute(0, 'open', 'http://www.borland.co.jp/', nil, nil, SW_SHOW)

사용자가 조합키를 누른것처럼 처리하는 방법

다음 소스를 참고하기 바랍니다. 중요한 부분은 조합키중 키와 키, 키와 같이 홀드(hold) 상태인 키를 확인해서 키값을 포스팅해 주는 것입니다.

완전하다면 더할나위 없이 좋겠지만, 그냥 자신의 프로그램에 덧붙여 사용하거나 외부 참조로 사용해도 무방할 것입니다.

procedure PostKeyEx( hWindow: HWnd; key: Word; Const shift: TShiftState; Specialkey: Boolean );

type

TBuffers = Array [0..1] of TKeyboardState;

var

pKeyBuffers : ^TBuffers;

lparam: LongInt;

begin

if IsWindow( hWindow ) then

begin

pKeyBuffers := nil;

lparam := MakeLong( 0, MapVirtualKey( key, 0 ) );

if Specialkey then

lparam := lparam or $1000000;

New( pKeyBuffers );

try

GetKeyboardState( pKeyBuffers^[1] );

FillChar( pKeyBuffers^[0],Sizeof( TKeyboardState ), 0 );

if ssShift In shift then

pKeyBuffers^[0][VK_SHIFT] := $80;

if ssAlt In shift then

begin

pKeyBuffers^[0][VK_MENU] := $80;

lparam := lparam or $20000000;

end;

if ssCtrl in shift then

pKeyBuffers^[0][VK_CONTROL] := $80;

if ssLeft in shift then

pKeyBuffers^[0][VK_LBUTTON] := $80;

If ssRight in shift then

pKeyBuffers^[0][VK_RBUTTON] := $80;

if ssMiddle in shift then

pKeyBuffers^[0][VK_MBUTTON] := $80;

SetKeyboardState( pKeyBuffers^[0] );

if ssAlt in shift then

begin

PostMessage( hWindow, WM_SYSKEYDOWN, key, lparam);

PostMessage( hWindow, WM_SYSKEYUP, key, lparam or $C0000000);

end

else

begin

PostMessage( hWindow, WM_KEYDOWN, key, lparam);

PostMessage( hWindow, WM_KEYUP, key, lparam or $C0000000);

end;

Application.ProcessMessages;

SetKeyboardState( pKeyBuffers^[1] );

finally

if pKeyBuffers <> nil then

Dispose( pKeyBuffers );

end;

end;

end; { PostKeyEx }

procedure TForm1.SpeedButton2Click(Sender: TObject);

Var

W: HWnd;

begin

W := Memo1.Handle;

PostKeyEx( W, VK_END, [ssCtrl, ssShift], False );

// 전체 선택

PostKeyEx( W, Ord('C'), [ssCtrl], False );

// 클립보드로 복사

PostKeyEx( W, Ord('C'), [ssShift], False );

// "C"로 치환

PostKeyEx( W, VK_RETURN, [], False );

// 엔터키(새라인)

PostKeyEx( W, VK_END, [], False );

// 라인의 끝으로

PostKeyEx( W, Ord('V'), [ssCtrl], False );

// 붙여넣기

end;

시스템 About사용하기

ShellAbout(Self.Handle,

PChar(Application.Title),

'http://home.t-online.de/home/mirbir.st/'#13#10'mailto:mirbir.st@t-online.de',

Application.Icon.Handle);

Self.Handle은 현재 동작중인 Application의 실행영역을 리턴하는 것이고....

PChar( Application.Title )은 Title의 Caption을 전달하는 것..

'문서영역'은 이 곳에서 만들었다는 표시...

Application.Icon.Handle은 About에서 보일 Icon의 값을 전달하는 방법

시스템 Image를 사용하는 TListView

procedure TDirTreeView.FindAllSubDirectories(pNode: TCTreeNode; ItsTheFirstPass: Boolean);

var

srch: TSearchRec;

DOSerr: integer;

NewText: String;

NewPath: string;

tNode: TCTreeNode;

cNode: TCTreeNode;

ImagesHandleNeeded : boolean;

cCursor: HCursor;

NewList: TStringList;

i: integer;

tpath: string;

function TheImage(FileID: string; Flags: DWord; IconNeeded: Boolean): Integer;

var

SHFileInfo: TSHFileInfo;

begin

Result := SHGetFileInfo(pchar(FileID), 0,

SHFileInfo, SizeOf(SHFileInfo),

Flags);

if IconNeeded then

Result := SHFileInfo.iIcon;

end;

function ItHasChildren(const fPath: string): Boolean;

var

srch: TSearchrec;

found: boolean;

DOSerr: integer;

begin

chdir(fPath);

Found := false;

DOSerr := FindFirst('*.*',faDirectory,srch);

while (DOSerr=0) and not(Found) do

begin

found := ((srch.attr and faDirectory)=faDirectory)

and ((srch.name<>'.')

and (srch.name<>'..'));

if not(found) then

DOSerr := FindNext(srch);

end;

sysutils.FindClose(srch);

chdir('..');

Result := Found;

end;

begin

tNode := TopItem;

cCursor := Screen.cursor;

Screen.cursor := crHourGlass;

Items.BeginUpdate;

SortType := stNone;

tpath := uppercase(fCurrentPath);

NewList := TStringList.Create;

getdir(0,NewPath);

if (NewPath[length(NewPath)]<>'\') then

NewPath := NewPath + '\';

ImagesHandleNeeded := ItsTheFirstPass;

DOSerr := FindFirst('*.*',faDirectory,srch);

while DOSerr=0 do

begin

if ((srch.attr and faDirectory)=faDirectory) and

((srch.name<>'.') and (srch.name<>'..')) then

begin

NewText := lowercase(srch.name);

NewText[1] := Upcase(NewText[1]);

NewList.AddObject(NewText, pointer(NewStr(NewPath+NewText)));

end;

DOSerr := FindNext(srch);

end;

sysutils.FindClose(srch);

NewList.Sorted := true;

with NewList do

for i := 0 to Count-1 do

begin

cNode := Items.AddChildObject(pNode,Strings[i], PString(Objects[i]));

with cNode do

begin

NewText := PString(Data)^;

HasChildren := ItHasChildren(NewText);

if ImagesHandleNeeded then

begin

Images.Handle := TheImage(NewText, SHGFI_SYSICONINDEX or SHGFI_SMALLICON, false);

ImagesHandleNeeded := false;

end;

ImageIndex := TheImage(NewText, SHGFI_SYSICONINDEX or SHGFI_SMALLICON, true);

SelectedIndex := TheImage(NewText, SHGFI_SYSICONINDEX or SHGFI_SMALLICON or SHGFI_OPENICON, True);

if AnsiCompareText(NewText,fCurrentPath)=0 then

begin

Expanded := true;

StateIndex := SelectedIndex;

Self.Selected := cNode;

end

else

if (pos(uppercase(NewText),tPath)=1) then

begin

Expanded := true;

tNode := cNode;

end;

end;

end;

NewList.Free;

Items.EndUpdate;

if Assigned(tNode) then

TopItem := tNode;

Screen.cursor := cCursor;

end;

실행하기

function fileExec(const aCmdLine: String; aHide, aWait: Boolean): Boolean;

var

StartupInfo : TStartupInfo;

ProcessInfo : TProcessInformation;

begin

{setup the startup information for the application }

FillChar(StartupInfo, SizeOf(TStartupInfo), 0);

with StartupInfo do

begin

cb:= SizeOf(TStartupInfo);

dwFlags:= STARTF_USESHOWWINDOW or STARTF_FORCEONFEEDBACK;

if aHide then wShowWindow:= SW_HIDE

else wShowWindow:= SW_SHOWNORMAL;

end;

Result := CreateProcess(nil,PChar(aCmdLine), nil, nil, False,

NORMAL_PRIORITY_CLASS, nil, nil, StartupInfo, ProcessInfo);

if aWait then

if Result then

begin

WaitForInputIdle(ProcessInfo.hProcess, INFINITE);

WaitForSingleObject(ProcessInfo.hProcess, INFINITE);

end;

end;

function fileRedirectExec(const aCmdLine: String; Strings: TStrings): Boolean;

var

StartupInfo : TStartupInfo;

ProcessInfo : TProcessInformation;

aOutput : Integer;

aFile : String;

begin

Strings.Clear;

{ Create temp. file for output }

aFile:=FileTemp('.tmp');

aOutput:=FileCreate(aFile);

try

{setup the startup information for the application }

FillChar(StartupInfo, SizeOf(TStartupInfo), 0);

with StartupInfo do

begin

cb:= SizeOf(TStartupInfo);

dwFlags:= STARTF_USESHOWWINDOW or STARTF_FORCEONFEEDBACK or

STARTF_USESTDHANDLES;

wShowWindow:= SW_HIDE;

hStdInput:= INVALID_HANDLE_VALUE;

hStdOutput:= aOutput;

hStdError:= INVALID_HANDLE_VALUE;

end;

Result := CreateProcess(nil,PChar(aCmdLine), nil, nil, False,

NORMAL_PRIORITY_CLASS, nil, nil, StartupInfo, ProcessInfo);

if Result then

begin

WaitForInputIdle(ProcessInfo.hProcess, INFINITE);

WaitForSingleObject(ProcessInfo.hProcess, INFINITE);

end;

finally

FileClose(aOutput);

Strings.LoadFromFile(aFile);

DeleteFile(aFile);

end;

end;

외부 Application의Window크기 조절하기

SHOWWINDOW-외부 Application의 Window 크기 조절

아래 소스는 현재 active된 window의 list를 구한 후 그중 하나를 선택하여 Minimized, Maximized 하는 예제입니다.

procedure GetAllWindowsProc(WinHandle: HWND; Slist: TStrings);

var

P: array[0..256] of Char; {title bar를 저장 할 buffer}

begin

P[0] := #0;

GetWindowText(WinHandle, P, 255); {window's title bar를 알아낸다}

if (P[0] <> #0) then

if IsWindowVisible(WinHandle) then {invisible한 window는 제외}

Slist.AddObject(P, TObject(WinHandle)); {window의 handle 저장}

end;

procedure GetAllWindows(Slist: TStrings);

var

WinHandle: HWND;

Begin

WinHandle := FindWindow(nil, nil);

GetAllWindowsProc(WinHandle, Slist);

while (WinHandle <> 0) do {Top level의 window부터 순차적으로 handle을 구한다}

begin

WinHandle := GetWindow(WinHandle, GW_HWNDNEXT);

GetAllWindowsProc(WinHandle, Slist);

end;

end;

procedure TForm1.B_SearchClick(Sender: TObject);

begin

ListBox1.Items.Clear;

GetAllWindows(ListBox1.Items);

end;

procedure TForm1.B_MaximizeClick(Sender: TObject);

begin

if ListBox1.ItemIndex < 0 then

System.Exit;

{선택한 window를 maximize}

ShowWindow(HWND(ListBox1.Items.Objects[ListBox1.ItemIndex]), SW_MAXIMIZE);

end;

procedure TForm1.B_minimizeClick(Sender: TObject);

begin

if ListBox1.ItemIndex < 0 then

System.Exit;

{선택한 window를 minimize}

ShowWindow(HWND(ListBox1.Items.Objects[ListBox1.ItemIndex]), SW_MINIMIZE);

end;

워크그룹의 호스트네임 읽어내기

program ShowSelf;

{$apptype console}

uses Windows, Winsock, SysUtils;

function HostIPFromHostEnt( const HostEnt: PHostEnt ): String;

begin

Assert( HostEnt <> nil );

// first four bytes are the host address

Result := Format( '%d.%d.%d.%d', [Byte(HostEnt^.h_addr^[0]), Byte(HostEnt^.h_addr^[1]),

Byte(HostEnt^.h_addr^[2]), Byte(HostEnt^.h_addr^[3])] );

end;

var

r: Integer;

WSAData: TWSAData;

HostName: array[0..255] of Char;

HostEnt: PHostEnt;

begin

// initialize winsock

r := WSAStartup( MakeLong( 1, 1 ), WSAData );

if r <> 0 then

RaiseLastWin32Error;

try

Writeln( 'Initialized winsock successfully...' );

// get the host name (this is the current machine)

FillChar( HostName, sizeof(HostName), #0 );

r := gethostname( HostName, sizeof(HostName) );

if r <> 0 then

RaiseLastWin32Error;

Writeln( 'Host name is ', HostName );

// get host entry (address is contained within)

HostEnt := gethostbyname( HostName );

if not Assigned(HostEnt) then

RaiseLastWin32Error;

Writeln( 'Got host info...' );

// dump out the host ip address

Writeln( 'Host address: ', HostIPFromHostEnt( HostEnt ) );

finally

WSACleanup;

end;

end.

윈도우시작메뉴 히스트로에 문서 등록하기

윈도우즈 시작메뉴에 있는 문서 히스토리에 자기가 생성한

화일을 등록할 수 있는 함수가 있습니다.

먼저 다음과 같은 프로시져를 프로그램에 넣어 주세요.

use ShellAPI, ShlObj;

procedure AddToStartDocument(FilePath: string)

begin

SHAddToRecentDocs(SHARD_PATH, PChar(FilePath));

end;

자 이제 이 함수를 사용해 봅시다. 우린 파라미터로 문서의

경로를 넘겨주면 됩니다.

예)

AddToStartDocument(C:\Test.txt);

=>책에 이렇게 나와 있는데, 미스 프린팅 같군요.

-> 요렇게 해 주세요. AddToStartDocument('C:\Test.txt');

윈도우 배경그림바꾸기

Window 배경그림 바꾸기

procedure ChangeIt;

var

Reg: TRegIniFile;

begin

Reg := TRegIniFile.Create('Control Panel');

Reg.WriteString('desktop','Wallpaper','c:\windows\kim.bmp');

Reg.WriteString('desktop', 'TileWallpaper', '1');

Reg.Free;

SystemParametersInfo(SPI_SETDESKWALLPAPER,0,nil,SPIF_SENDWININICHANGE);

end;

Status에 색깔 넣기

Status bar에 색깔 넣기

StatusBar Font의 색을 바꾸는 방법은 직접 그려주는 수 밖에 없습니다. 익히 아시겠지만 StatusBar의 Item이라 할 수 있는 TStatusPanel에는 Style이란게 있습니다. 이 값은 psText나 psOwnerDraw란 값을 갖는데 psOwnerDraw일때에는 해당 Panel을 그릴 때마다 OnDrawPanel event가 호출됩니다. 이때에 원하는 색으로 직접 그려주시면 됩니다. psOwnerDraw일때는 그려주지 않게되면 Text값을 갖고 있다 하더라도 전혀 나오질 않으므로, 반드시 위에 말한 event에서 그려주셔야 합니다.

다음에 예제를 보여드립니다.

procedure TfmMain.m_statusBarDrawPanel(StatusBar:

TStatusBar; Panel: TStatusPanel; const Rect: TRect);

begin

with StatusBar.Canvas do begin

case Panel.ID of

0 : Font.Color := clBlue;

2 : if Panel.Text = '한글' then Font.Color := clRed

else Font.Color := clBlue;

end;

FillRect(Rect);

TextOut(Rect.Left+2,Rect.Top+2,Panel.Text);

end;

end;

위에 ID란 property를 사용했는데요, 이것은 index와는 약간 차이가 있습니다. index propery와 같이 부여되긴 하지만, item이 추가, 삭제, 삽입되더라도 ID의 값은 변하질 않습니다.

다시말해 한번 부여된 ID는 다시 사용되지 않습니다.

TreeView 프린트하기

TreeView and Print

paintTo can be made to work, you just have to scale the printer.canvas in the ratio of screen to printer resolution.

procedure TForm1.Button2Click(Sender: TObject);

begin

Printer.BeginDoc;

try

printer.canvas.moveto(100,100);

SetMapMode( printer.canvas.handle, MM_ANISOTROPIC );

SetWindowExtEx(printer.canvas.handle,

GetDeviceCaps(canvas.handle, LOGPIXELSX),

GetDeviceCaps(canvas.handle, LOGPIXELSY),

Nil);

SetViewportExtEx(printer.canvas.handle,

GetDeviceCaps(printer.canvas.handle, LOGPIXELSX),

GetDeviceCaps(printer.canvas.handle, LOGPIXELSY),

Nil);

treeview1.PaintTo( printer.canvas.handle, 100, 100 );

finally

printer.enddoc;

end;

end;

신고
by 꿈꾸는자의 생각의파편들 2008.07.30 09:06

정지훈님의 저자후기

필자가 델파이를 처음 만난 것이 1996년 가을이다. 델파이를 처음 본 순간 이것이야 말로 내가 바라던 개발 도구임을 직감할 수 있었고, 그 때부터 델피언이 되어 무작정 델마당 모임에 참석했던 기억이 아직도 생생하다.

책 을 쓰려고 마음먹을 당시에는 델파이에 대해서 볼만한 책도 거의 없었고, 더구나 초급자 수준 이상이 되면 볼 수 있는 책은 더더욱 없었다. 그래서, 이번에 집필하는 책은 중급자 이상이 되어도 얻을 수 있는 것이 많은 책이 되어야 한다고 생각하였고, 델파이를 이용해서 할 수 있는 여러 가지 테크닉과 기법들을 소개하고자 노력하였다. 비록 처음에 의도한 바대로 고급스러운 테크닉을 모두 싣지는 못했지만, 최소한 현재 나와있는 델파이 서적 중에서는 다루지 않은 것들을 중심으로 집필하였기 때문에 많은 도움이 될 수 있을 것으로 생각한다.

막상 집필을 끝내고 나기 조금은 색다른 델파이 책이 되버린 것 같지만, 이 책을 보는 모든 사람에게 도움이 되었으면 좋겠다.

프 로그래밍 환경은 언어와 프로그래밍 환경, 컴포넌트 구조 등이 하나로 모여질 때에 강력한 힘을 발휘한다고 생각하며, 그러한 프로그래밍 환경 중의 하나가 델파이라고 생각한다. 델파이는 현재의 시대적인 흐름과 프로그래머의 요구조건에 걸맞는 환경으로 진화한 진보한 툴이다. 이러한 델파이 컴포넌트 구조와 철학에 반해버린 델피언 중의 한사람으로 델파이의 미래에 대한 환상을 꿈꾸곤 한다. Delphi for Unix/Linux 버전을 볼 수 있다면 얼마나 좋을까? 들리는 소식으로는 꿈만은 아닌 것 같다.


신현묵의 저자후기

델파이1부터 델파이4까지 이제 4개의 버전업을 한 델파이, 처음보았을때 떨리던 가슴을 진정시키던 기억이 아직도 생생하다. 강력한 개발환경, 짜임새있는 VCL, 멋진 인터페이스, 다양한 환경, 간단한 개발, 그리고, 강력한 수행능력. 분명 델파이는 일류(?)개발툴임에 틀림없습니다.

그동안 공부했던 내용과 다른 분들에게 자그마한 지식이라도 나누고 싶어서 이책을 만드는데 참여했습니다. 기존의 델파이책들이 너무 컴포넌트의 나열만으로써 이루어진 책들이 많기 때문에 조금은 색다른 모습의 책으로 책을 쓸려고 했는데 잘되었는지는 모르겠습니다. 처음에 많은 내용을 넣었으면 하는 욕심도 있었지만, 결국에는 지훈님과 계획잡았던 내용을 모두 채우지 못한 것이 아쉽습니다.

쓰고나니 조금은 이상한 델파이 책이 되어버린 것 같지만, 이 책을 보는 모든 사람에게 도움이 되었으면 좋겠습니다. 온라인 상의 좋은 정보는 하이텔의 비주얼툴( go vtool )과, 인터넷의 비주얼 파워툴의 홈페이지(http://www.visualtool.com)와 델마당의 홈페이지(http://www.delmadang.com)에도 들려주기 바란다. 아마 이책이 출판되었을때쯤에는 하이텔의 강좌란과 연계한 서비스도 보여줄 수 있을 것이다.

함께 글을 쓴 정지훈님이 너무 고생이 많으셨다. 공저로 작업한다고 해놓고선 바쁘다는 필계의 제가 쓸 분량을 다 채우지 못해 고생하신 '정지훈님'에게 먼저 감사드리고, 글을 쓰는데 지대한 도움을 준 우리 어부인 '진숙이'에게도 고맙고, 컴퓨터 전원스위치를 눌러 작업하던 파일을 몇번 날려먹은 우리아가 '수철이'에게도 고맙고, 자료를 찾는데 도움을 준 우리 'SPINTech직원들'에게도 감사감사… 그외 비주얼 파워툴의 '델파이 개발자'여러분에게도 감사감사.

신고
by 꿈꾸는자의 생각의파편들 2008.07.30 09:04

책의 저작권 기간이 5년이라는 희소식!!!
예전에 집필했던 책을…
조금은 올드하지만…
많은 분들에게 읽힐 수 있도록

오픈할 수 있을 듯 하네요.

좀더 자세한 것은 알아보겠지만..
조만간…

좋은 소식으로 올릴 수 있을 듯.!!!

신고
by 꿈꾸는자의 생각의파편들 2008.07.29 14:48
| 1 |