2008년 7월 31일 목요일
서울시민들의 선택... 다시금 시작된 공포의 학창시절...
'우리나라도 이제 고교 경쟁에 불을 빨리 붙여야 할 때가 됬다'고 이야기하셨단다.
http://news.naver.com/main/hotissue/read.nhn?mid=hot&sid1=102&sid2=250&cid=150608&nt=20080731171216&iid=42169&oid=001&aid=0002201017
.
.
.
서울 시민들이 원하는 것은...
중, 고교 학생들의 치열한 생존경쟁을 통한...
암울한 학교 생활을 원한 것이다.
뭐...
공부에 매달리다 보면...
다른 사고는 덜 치겠지?
라는 생각일까?
강남아줌마들의 힘은...
이제는 정권, 부동산, 교육까지...
정말 막강한 힘을 발휘한다.
그렇다..!!!
그들은 최소한 자신들에게 부여된
투표권을 행사하기 위해 최선을 다한것이다.
자신에게 주어진 권리를 버린...
서울시민들이여...
아!!!
촛불시위에 나온것은...
극소수의 서울시민들뿐이란 해석이 성립한다.
그렇다!
서울 시민들은...
아름 다운 학창시절을 선물하기 보다는...
죽을둥 살둥...
매달리는
아름다운(!) 학창시절을 원한다...
정말 대단한
서울시민들!!!
[SA강좌] Part 2-3 소프트웨어 아키텍처 설계 절차와 CBD방법론의 관계
이 절에서는 소프트웨어 아키텍처 설계 절차와 CBD 방법론의 관계를 보여준다.
-
CBD 방법론
그림 Ⅲ-3. CBD 방법론
그림 Ⅲ-3는 기존의 CBD 방법론을 보여준다. 기존 방법론에서는 아키텍처 정의 단계가 있었지만 아키텍처를 설계하는 상세한 지침은 마련되어 있지 않았다.
-
개선된 CBD 방법론
그림 Ⅲ-4. 개선된 CBD 방법론
개선된 CBD 방법론은 기존의 아키텍처 정의 단계를 아키텍처 설계, 아키텍처 평가, 아키텍처 상세화로 세분화 시킨다.
서울시 교육감의 당선과... 2%의 차이점...
40%의 득표율...
약 2%의 차이...
~.~
공당선자가 강남, 서초, 송파의 압도적인 지지를 얻어내었다는 점이 참.. 고무적이다.
뒤집어 생각해보면...
강남, 서초, 송파 이외의 지역은 '교육감'의 자리가 얼마나 중요한지 모른다는 이야기일까?
전체적인 투표율이 15.4%라는 이야기 자체가..
이미...
관심도 없고...
생각도 없는 서울 시민들을 표현한 것일까?
아니면...
정말 먹고 살기 힘들어서 투표를 안한 것일까?
아니면...
어차피... 뽑아봐야 그사람이 그사람이니...
포기한 것일까?
.
.
.
촛불이건...
선거이건...
참여하고...
이야기하고...
그리고...
자신의 주권을 행사하는 시민의식이 더욱더 성장하기를 기원한다.
아직...
우리에게는...
정말 그 2%가 부족한 것일까?
병무청 시스템과 삼성SDS시스템의 결함...
요즘은 한겨례일보로 신문을 변경한 후로는 아침에 신문보면서 막 짜증은 안난다.
오늘은 문득 자그마한 기사로 나온...
'납품한 삼성SDS시스템에 근본적 결함'
http://www.hani.co.kr/arti/society/society_general/301572.html
내용을 읽어보니...
병무청이 운영하는 '공직자 병역사항 조회'코너에서 3만 1천명의 고위 공직자 주민등록번호를 노출시킨 실수아닌 실수를 지적한 기사였다.
2006년 3월 '병무행정 차세대 정보시스템'을 조달청을 통해서... 삼성SDS가 117억원을 들여서 만든 시스템의 일부라고 하는데...
기사내용을 읽어보니... 데이터를 검색하는 키와 비슷하게 주민등록번호를 사용하였고 이를 스크립트에 넣어서 동작하는 방식으로 코딩한 내용이었다는데... ~.~
다음과 같이 결론을 내릴 수 있겠다.
1. 소프트웨어 개발자가 주민등록번호를 외부로 노출시키면서 동작하게 만든 설계를 한 곳에서 이 책임을 지어야 한다. 공공SI의 특성상 노가다맨으로 들어가는 프로그래머에게 무슨 잘못이 있으랴... 이는 전적으로 설계한 사람의 책임이다.
2. 마찬가지로 건설현장과 똑같은 감리시스템을 통해서 시스템을 점검하고 있는데... 이를 알아보지 못한 감리한 회사나 담당자 책임도 똑~~같다. 보통 공공SI의 감리실태를 파악할때에 세부적인 코드까지 보는 경우를 본적이 없다. ~.~ 어차피 문서로만 씨름할뿐...
3. 정부의 웹표준화 방향이나 보안성 표준에도 문제가 있다. 얼마전에 인증서와 관련하여 금결원에서 오픈웹에게 소송 패소를 내린것과 마찬가지로 http://openweb.or.kr/?p=143 보안성에 대해서 IE만 체크한다는... 2MB 스러운 답변만 이야기한다.
4. 이번 문제는 사실 보안성의 문제라기 보다는... 공공SI를 수행하는 수행방식의 문제점으로 인하여 발생한 문제로 보인다.
자... 여기서 이 문제가 보안성의 문제가 아니라 공공SI의 수행상의 문제라고 보는 이유가 무엇인지 이야기 해보겠다.
문제의 핵심...
이번에 발생한 문제는 아주 단순한 거다...
실제 병무청에 들어가서 보니... 프로그램은 매우 단순했다.
원하는 공직자의 이름과 소속단체를 지정한후 그 사람의 데이터를 보는 방식에서
어처구니 없게도 주민등록번호를 사용하였고...
웹에서 이를 스크립트화 할때에 그 번호를 그냥 사용한 것이 문제점인 것이다.
더더군다나... 스크립트의 코드를 IE6에 맞추었다는 삼성SDS의 이야기는 더 웃긴다... ~.~
머, 사업수행계획서에 그렇게 나열하면 자기 책임은 없다고 우기겠지만...
이 문제를 해결할 방법은 없었는가?
아주 간단한 방법들이 많다.
1. 주민등록번호를 암호화하는 방법을 사용하였으면 이런 문제가 발생안했겠죠. ~.~
2. 검색시에 주민등록번호를 사용하지 않았으면 마찬가지로 이문제가 발생안했겠죠...
3. 내부적으로 사용했더라도... 브라우저보안이나 스크립트내부에서 잘 숨겼으면 마찬가지로 안보였겠죠.
하지만... 이번 사건을 보니... 아주 원시적이고 기초적인 보안만 하고 넘어갔다.
자... 그럼 이 문제가 어떻게 발생되었는지 유추해볼까요?
머.. 이건 전적으로 저의 개인적인 생각입니다.
말그대로 믿거나 말거나...
~.~
보통 공공SI프로젝트를 수행하면 대한민국의 모든 SI업체들은 실제 개발자들은 거의 프리렌서나 하청업체의 인력을 사용합니다.
머... 갑,을,병,정... 쭉쭉... 내려가는 전형적인 하청구조이죠.
보나마다... 해당 부분의 작업은 어느 이름모를(?) 개발 하청업체에서 어디선가 구해온 프리랜서가 일을 했겠죠.
머... 당근... 보안성과 관련된 메뉴얼이나 기타 교육을 받기는 커녕...
막판까지 몰아치기 개발을 진행하다가...
결국 설계를 한 사람과 이야기도 없이.
그냥 기능을 구현하려고 하니...
가장 빨리 개발하는 방식은...
'사람'의 '키'인... '주민등록번호'가 있으니...
이를 스크립트로 노출시키고...
이를 통해서 Call하는 방식이 아주 교과서(!)적인 방식이 되겠죠.
머... 누가 뭐라는 사람도 없고.
감독은 커녕 표준이나 보안성에 대한 이야기도 없으니...
그냥 진행했을 것이고...
결국... 대한민국 공공SI의 폐해를 그대로 보여준 대표적인 사례로 남지 않을까 합니다.
~.~
머... 이문제를 들들 볶아봐야...
결국...
똑똑한 '을'인.. 삼성SDS에서 요리조리 피해놓은 문서상에서 왔다리 갔다리..
감리회사인 어떤 회사도 요리조리 왔다리 갔다리...
결국 아무도 책임지지않고...
나중에는...
아마도...
해당 코드는... ~.~
주민등록번호가 아닌...
머 임시테이블을 생성하고...
이를 보여주는 아주 간단한 코드정도로나 바뀔까요?
다만...
이를 유지보수하는 SM업체에서는...
엄청 많은 문서나 대책방안들에 대해서... 골치는 좀 아프겠죠.
.
.
.
하지만...
근본적인 부분은 그대로 남겨두고...
'땜질'하는 전형적인 대한민국 SI의 행태만 나오고 말겠죠.
~.~
2008년 7월 30일 수요일
미셀위... 위성미의 끊임없는 도전...
프로의 세계에서 최고가 되기위해 도전하는 것...
그것이 프로의 자세가 아닌가?
자신이 존재하는 이유를 찾는것...
내가 미셀위의 도전을 좋아하는 이유다.
골프는 남성스포츠이다.
결코 여성 스포츠가 아니기 때문이다.
실제적으로 PGA의 위상과 LPGA의 차이는 엄청나다..
뭐랄까?
메이저리그와 마이너리그?
쉽게 이야기해서.. 상금액수 차이가 7~8배난다.
다만...
우리나라에서 LPGA가 뜬 이유 때문에...
한국의 여성골퍼들이 많이 활동하는 이유도 그때문이다.
하지만...
역시...
골프는 PGA!
당근 골프선수라면...
PGA에 참여하는 선수가 되는 것이 최고의 목표가 아닐까?
마치... K리그에서, J리그나 메이저리그로 도전하듯...
최고의 선수들과...
최고의 리그에서 활동하고픈...
그런것이 프로의 모습이 아닌가 한다.
.
.
.
고로...
여성 선수이지만...
아니...
LPGA에 많은 도전을 해서...
우승을 한다고 하더라도...
PGA에 컷통과하는 모습을 보고...
남성들과 경기를 하는...
그런 미셀위의 모습을 기대한다...
그것이...
프로의 몸가치!
프로의 도전가치가 아닌가 한다.
그녀가 비록 실패한다고 할찌라도...
그녀가 도전하는 동안은...
언제나 아름답다고 생각한다.
.
.
.
이번에도 또 도전한다는 미셀위에게...
쓴소리 하는 LPGA의 여성선수들이 많군요.
머...
신경쓰지 마시고...
계속 도전하시기를!
소비자물가에 대한 착각을 가진 정부...
정부가 기준을 세우면...
알아서...
그 뒤로 줄을 쭈욱 서던 시절이 있었다.
'눈짓'한번에...
알아서 벌벌...
~.~
.
.
.
지금은 그런 시대가 아니다.
더더군다나...
정부가 개입해서 공공요금을 조절하려고 해도...
이곳 저곳에서...
그것과 관련된 잡음만 들린다.
잡으려고 해도 잡을 수 없는 연인관계가 된것은 아닌지?
아니...
오히려...
정부측 인사나 관련집단에서 이야기한 것들이..
오히려 더 영향을 받는다.
환율도 그렇고...
물가도 그렇다.
이번 29일 말기루, 알루미늄등의 관세를 무관세화했다고 하지만...
결론적으로는... ㅡㅡ;
.
.
.
무언가 착각하고 있는 정부측이 아닌가?
더이상의 경제체제는...
관세나... 특정 물품의 동향으로 경제의 흐름을 조절할 수 있는 것이 아닌데...
괜스럽게...
MB물가지수를 만들었다고 자평할 수도 있다는 생각이 든다.
소비자 물가보다..
MB물가지수가 더 올랐으니..
~.~
이것은 또 어찌된 일일까?
'정부에서 신경쓴다'는...
결국...
'친기업'...
엥?
'기업에 이익'을 내는쪽...
그런거는 아니죠?
글쵸?
설마.. ~.~
정말 멋진 VVIP마케팅을 할 수는 없는가?
http://media.daum.net/economic/consumer/view.html?cateid=1007&newsid=20080730153116504&cp=khan
기업의 입장에서는 당근 잘해야할 대상이긴하지만...
그 0.1%를 위한 마케팅이...
소비에 집중되어진 것이 너무 씁쓸하다.
문화적이며...
대중들에게 멋스러운...
그런 VVIP 마케팅을 하는 곳은 없는가?
.
.
.
아니...
정말 대중을 선도하거나...
국내의 0.1%를 선도하는...
그런 예술가나...
진정한 상류층은 생기지 않는 것일까?
어디가 먼저인줄은 모르겠지만...
정말...
멋진 상류층이
대한민국에도 있었으면 좋겠다...
~.~
일확천금 로또의 세금은 올라가도... 부동산 세금이 떨어지는 이유...
1주일간의 환상을 꾼다.
하지만...
강부자들께서는
굳이 로또를 살필요를 못느낀다.
Why?
확률이 없으니까... ~.~
.
.
.
머.. 그렇다...
강부자들은...
로또는 안사기 때문에 그 쪽 세금을 올리는 것이 당연하다고 생각하지 않을까?
그런거 아닐까?
그리고, 한편으로는...
자신들의 재산(?!)인 부동산에 붙는...
세금은 당근... 떨어져야 한다고 생각한다.
Why?!!
부동산이 자신들의 재산증식의 수단이기 때문에...
이곳에 손을 대는 나쁜 넘(!)들을 싫어하는 것 아닌가?
뭐...
결국...
그쪽 세금을 떨어트리기 위한 움직임에 성공했구...
또...
현실이 그러하니까...
ps...
기름값이 올라도 그들은 부담 스럽지 않다.
생각해봐라...
어린아이들이 사먹는 동네 구멍가게의 아이스크림은 언제든지 사줄 수 있지 아니한가?
ㅡㅡ;
대한민국에서 성공한 개발자들이 많이 나왔으면 한다.
과연 몇명이나
성공한 사람들이 몰고다닌다는...
BMW나 벤츠...
이 넘들을 과연 몇명이나 몰고 다닐까?
아!
거기에 조건 하나 덧붙이자면...
대한민국에서 잘나간다는 SKY와 해외 유학파 출신들은 일단 제외하자.
그 분들(!)께서는...
굳이... 개발자라는 것을 내세우지 않아도 되니까...
쩝...
그런데...
그렇다...
정작...
순수하게 자신의 능력으로...
자신이 소프트웨어를 만들고...
소프트웨어 하우스를 오픈하고...
자신만의 영역을 구축하였을 경우에...
그들에게 박수를 보낼 멋진 개발자들은...
또 몇명이나 될까?
.
.
.
아!!!
성공한 개발자들이여..
자신들의 모습을
떳떳하게...
세상에 보여달라...
당신들을 롤모델삼아서...
도전을 시작할 수 많은
프로그래머들에게...
꿈을 꾸게 할 수는 없는가?
성공한 개발자들이...
마니 마니..
나왔으면 좋겠다.
원티드를 본 꿈꾸는자의 끄적임...
설정상의 의학적인 배경이나
물리적인 상식...
.
.
.
잊어버리고...
그냥...
작가의 설정상의 재미에 빠지는 것이 어떨까?
소심하고...
남자답지 못한 한 남자가...
혈통상 킬러의 후계자였으며...
( 심장에 대한 설정은 재미있었음... )
세계를 지배하는 조직과의 미묘한 대응을 통한...
새로운 세계가 우리 주변에 있다니!!!
~.~
요 근래 본...
가장 세련된 액션신들이 아니었을까?
소심한 한 남자가
킬러로 변해가는 성장 드라마에...
음모이론을 적당히 버무리고...
멋진 CG로 만들어진 액션과...
머...
이제는 조금 나이를 먹었기는 하지만...
아직은 매력적인 안젤리나...
.
.
.
아주 멋진 킬링 타임~~
세상을 일탈하는
그런...
세계를 꿈꾸는 즐거움이아닐까?
~.~
스피드레이서를 본 꿈꾸는자...
역시 소재에 따라서 각자의 장단점이 있는듯해보인다.
워쇼스키 형제(자매라고 해야겠지만...)의 스타일은 조금은 무겁고 진중한 이미지가 더 잘어울린다고 해야할까? 가볍게 풀어내는 능력보다는... 해석을 각자 할 수 있게 하는 미스테릭한 스토리 구성이나 화면의 표현에 더욱더 뛰어난 능력을 발휘하게 하는 것 같다.
스피드레이서... 머, 대한민국 사람들에게는 비나 GOD의 멤버( 이름이 기억 안남.. ㅡㅡ; )가 출현한다고 해서 나름 화재가 되었다가... 국내 개봉하면서 아이언맨에게 밟힌(?) 비운의 블록버스터가 되어버린듯...
머... 스피드레이서를 본 꿈꾸는 자의 생각은 그렇다!
장점!!!
1. 디자인적인 측면... 원색을 조금은 유치한듯하게 배치하고, 전체적인 디자인은 클래식하다고 해야하나?
2. 카푸라는 자동차로 할 수 있는 또 다른 액션의 새로운 장르를 개척했다고 해야하나... 자동차와 자동차의 싸움에도 이런 새로운 시도가 있을 수 있다는.. ~.~
3. 나름 미스테릭한 시나리오를 통한 반전... ( 머, 너무 뻔하기는 하지만...그래도 초딩은 큰아들과 재미있게 봄. )
흠.. 생각보다 장점이 별로 없네?
그럼.. 단점!!!
단점!!!
1. 둘째 아들은 중간에 보다가 잠들음.. ( 초딩 1 ).. 어른이 보기에는 좀 유치하고, 너무 애들이 보기에는 지루한... 음? 좀 글치?
2. 어색한 듯한 만화적인 화면 구성이 그렇게 세련되어 보이지 않는다는... 오히려, 원티드의 자동차 액션과 비교하면 무언가... 애들 스러운 느낌이 듬... 이도 저도 아닌듯한 느낌...
총평!!!
나는 별3개쯤 주겠다. ( 5개 만점 )
타임 킬링용으로는 괜찮다.
자동차 경주와 카푸는 아주 볼만했지만... 원티드의 자동차 액션에 비하면 조금은 유치한 느낌...
조금은 실사를 활용했으면 좋았지 않았을까?
내가 감독이었다면?
1. 원색 보다는 조금은 실사에 가까운 색을 활용하였을 듯... 매트릭스의 진중한 부니기에 어울리는 색채와 조금은 펑크 적인 느낌이 들었다면 워쇼스키의 원래 팬과 매트릭스에 열광한 팬들에게도 좋았을 듯.
2. 주인공은 조금 대충(?) 선택한 느낌... 만화 원작의 주인공 느낌으로 갈려고 한것 같은데... 그다지.. ~.~ 그리고, 꼬옥... 조금은 엉성한 예전 캐틱터의 옷복장까지 굳이 따라할 필요가 있었을까?
3. 주인공이 시련을 격는 과정이 너무 엉성... 성공했을때의 감동이 많이 저하됨... ~.~ 좀더 큰 시련을 배치하면 어떠했을까?
머.. 결론적으로...
볼만은 했다는 거.. ~.~
내가 좋아하는 두 형제의 사진 한컷!
나의 사랑스러운 두 형제~~
.
.
.
프로방스 마을에서 찍은 사진중에.. 개인적으로 마음에 들어하는 사진...
수철이는 이렇게 생각할까?
밖에 무엇이 있을까?
고민하지 마렴..
온실은 네가 성장할때 까지만 기다려준단다..
내가 너를 보내고 싶지 않아도..
너는
그 온실을 벋어나...
너의 공간으로 갈것이다.
너무 고민하지 마렴..
네가 만들어갈
너의 시간은..
너의 머릿속에서
이미 완성되어 있을 것이란다..
구글 검색이 잘되는 비법!!
구글검색에 잘 되는 방법에 이런 것이 있다니!!!
이번에 티스토리로 블로그를 옮기면서…
구글 애드센스를 한번 걸어봤는데…
울랄라…
올린지 10분도 안되어서…
블로그 검색에 걸린다.
이런 팁이 있다니…
아무래도 내부에 구글 애드센스와 검색 엔진에 연관성이 많은듯…
하긴… 광고 노출이 잘되는 녀석들을 검색이 잘되게 하는 것이 맞기는 한 것 같다.
[SA강좌] Part 2-2 반복을 통한 소프트웨어 아키텍처 설계 절차
반복을 통한 소프트웨어 아키텍처 설계 절차
그림 Ⅲ-2. 반복을 통한 소프트웨어 아키텍처 설계 절차
그림 Ⅲ-2은 소프트웨어 아키텍처가 프로젝트의 각 단계에서 어떻게 작성되는지를 보여준다. Inception 단계에서는 아키텍처 팀을 구성하고 아키텍처에 대한 개략적인 안을 작성한다. Elaboration 초기 단계에서는 핵심 아키텍처를 설계한다. Elaboration 후반부에서는 추가 요구사항을 받아서 아키텍처를 계속 수정한다. Construction 단계에서는 개발 도중 이슈가 발생하면 아키텍처를 보완한다.
[SA강좌] Part 2-1 소프트웨어 아키텍처 설계
소프트웨어 아키텍처 설계
본 장에서는 소프트웨어 아키텍처를 설계하는 절차와 기법을 제시한다.
소프트웨어 아키텍처 설계 개요
소프트웨어 아키텍처 설계 절차는 그림 Ⅲ-1과 같다.
그림 Ⅲ-1. 소프트웨어 아키텍처 설계 절차
소프트웨어 아키텍처 중 논리적 아키텍처를 구성하기 위하여 업무도메인을 분할하고, 업무도메인의 서브도메인을 파악하여 이들간의 관련성(interface)를 정의하는 데서 시작한다. 정의된 어플리케이션 아키텍처에 맞게 전 도메인 또는 서브도메인에 대한 아키텍처 구조에 맞게 상세설계 및 구현을 실시한다.
그리고, 소프트웨어 아키텍처 설계는 고객의 요구사항에서부터 출발한다. 고객의 요구사항은 요구사항정의단계에서는 인터뷰를 통한 회의록, 인터뷰시트로 파악되며, 분석설계단계에서는 유즈케이스 설계서를 통하여 구체적으로 파악되게 된다. 이러한 고객의 요구사항을 통하여 소프트웨어 아키텍처에 고려해야 할 요소를 파악하는 기술이 필요하다. 이때 요구사항의 우선수위 결정을 위하여 본 어플리케이션 시스템의 중요한 품질요소를 결정하는 게 좋다. 우선순위를 가지는 품질요소를 통하여 요구사항에 대한 작업우선순위를 결정하게 되며, 전체 어플리케이션 아키텍처에 해당 요구사항의 변경이 얼마만큼 영향을 미치는지도 결정하게 된다.
따라서, 기본적인 소프트웨어 아키텍처 설계 방법은 세가지 단계로 구성된다. 간단히 설명하면, 기능기반아키텍처 설계, 아키텍처 평가와 아키텍처 전이로 구성된다.
품질요소기반 소프트웨어 아키텍처 설계 방법은 두 개의 반복적인 설계 프로세스로 구성된다. 내부 반복 프로세스는 소프트웨어 아키텍처의 품질 요구사항의 설계, 평가, 전이로 크게 나눠볼 수 있다. 외부 반복 프로세스는 고객의 요구사항을 품질요소에 따른 선택하는 방법에 대한 활동으로 이루어진다.
반복적 소프트웨어 아키텍처 개발 사이클의 외부 소프트웨어 설계는 요구사항 중 가중 높은 고려대상이 되는 제품에 대한 품질요구사항으로 시작된다. 이는 또한 요구사항들의 내부 반복 프로세스를 진행하게 된다. 외부 반복 프로세스는 모든 요구사항이 어플리케이션 아키텍처에 고려될 때까지 나머지 요구사항을 반복하게 된다. 선택된 요구사항은 그림 4과 같이 소프트웨어 아키텍처 분석/설계 및 개발을 위한 핵심 소프트웨어 아키텍처 개발을 통하여 수행된다. 이 과정을 통하여 소프트웨어 아키텍처의 반복적인 수정의 기본 단위 작업들이 수행된다. 여러 개 요구사항은 반복적 소프트웨어 아키텍처 개발 사이클을 통하여 품질요소의 우선순위 또는 작업의 우선순위에 따라 핵심 소프트웨어 아키텍처 개발을 수행하게 된다.
내부 반복 프로세스는 소프트웨어 아키텍처가 구현되는 기본이 되는 요구사항들로 이루어진다. 내부 반복 프로세스의 초점은 품질요소의 평가와 전이이다. 어플리케이션 아키텍처 설계 방법은 목표, 관계상 설계 과정, 균형과 최적화를 지원하도록 제공된다. 반복적인 방법은 모든 품질요구사항이 만족될 때까지 각각의 품질요구사항을 지원하고, 전이로 사용되는 아키텍처로 반영된다.
완성된 어플리케이션 아키텍처는 업무 서브 도메인별 유즈케이스로 상세설계 또는 구현이 되며, 각 요구사항에 대한 단위 테스팅 수행 전체 시스템의 제품을 완성시키기 위한 반복적인 분석/설계 과정으로 대량생산체계를 수립한다. 이때 수정되는 비 기능적인 요구사항은 품질요소에 따라서 평가되어 어플리케이션 아키텍처를 재 수정과정을 통하여 변경된 어플리케이션 아키텍처에 대한 제품적용을 한다. 따라서, 소프트웨어 아키텍처 설계 방법은 소프트웨어 아키텍처 설계와 관련한 프로세스정의뿐만 아니라, 이러한 아키텍처를 설계하기 위한 소프트웨어 아키텍처 문서(SAD : Software Architecture Document)와 설계적 의사결정물 들로 구성된다.
소프트웨어 아키텍처 설계 방법인 그림 5를 살펴보면, 기본적으로 요구사항 정의를 분류한 기능적 요구사항을 기반으로 해서 출발한다. 비록 소프트웨어 엔지니어가 품질요구사항을 명확하게 정의하지 않으면 시스템은 안정적 또는 재사용될 수 없도록 설계되는 게 일반적이다. 이러한 소프트웨어 아키텍처 설계는 품질 요구사항 측면에서 많이 평가된다. 각각의 품질요소는 소프트웨어 아키텍처가 지녀야 할 정량적 또는 정성적 예상 값으로 평가된다. 아키텍처 전이 단계 동안에는, 아키텍처는 적절한 품질요소를 최적화하는 전이 방법을 선택함으로써 더욱 명확하게 된다. 전이단계는 새로운 버전의 아키텍처 설계 버전을 탄생케 한다. 이러한 요구사항 수집, 평가, 전이하는 반복적인 단계는 아키텍처 설계 또는 제품 릴리스 동안 지속적으로 발생하게 된다.
Chapter 2 – 델파이4 IDE의 내부(Internals of Delphi 4’s IDE)
델파이 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 섹션 사이의 이동과 코드 에디터 내부에서의 탐색 기능의 효율을 높였다.
Chapter 1 - 이것이 델파이4 ! (This is Delphi 4 !)
이것이 델파이 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의 세계로 여행을 떠나 보자 !
델파이4의모든것에 들어있던 팁모음집…
팁모음집
금주가 몇번째 주인지 어떻게 구합니까
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;
델파이4의 모든 것을 집필한 후기…
정지훈님의 저자후기
필자가 델파이를 처음 만난 것이 1996년 가을이다. 델파이를 처음 본 순간 이것이야 말로 내가 바라던 개발 도구임을 직감할 수 있었고, 그 때부터 델피언이 되어 무작정 델마당 모임에 참석했던 기억이 아직도 생생하다.
책
을 쓰려고 마음먹을 당시에는 델파이에 대해서 볼만한 책도 거의 없었고, 더구나 초급자 수준 이상이 되면 볼 수 있는 책은 더더욱
없었다. 그래서, 이번에 집필하는 책은 중급자 이상이 되어도 얻을 수 있는 것이 많은 책이 되어야 한다고 생각하였고, 델파이를
이용해서 할 수 있는 여러 가지 테크닉과 기법들을 소개하고자 노력하였다. 비록 처음에 의도한 바대로 고급스러운 테크닉을 모두
싣지는 못했지만, 최소한 현재 나와있는 델파이 서적 중에서는 다루지 않은 것들을 중심으로 집필하였기 때문에 많은 도움이 될 수
있을 것으로 생각한다.
막상 집필을 끝내고 나기 조금은 색다른 델파이 책이 되버린 것 같지만, 이 책을 보는 모든 사람에게 도움이 되었으면 좋겠다.
프
로그래밍 환경은 언어와 프로그래밍 환경, 컴포넌트 구조 등이 하나로 모여질 때에 강력한 힘을 발휘한다고 생각하며, 그러한
프로그래밍 환경 중의 하나가 델파이라고 생각한다. 델파이는 현재의 시대적인 흐름과 프로그래머의 요구조건에 걸맞는 환경으로 진화한
진보한 툴이다. 이러한 델파이 컴포넌트 구조와 철학에 반해버린 델피언 중의 한사람으로 델파이의 미래에 대한 환상을 꿈꾸곤 한다.
Delphi for Unix/Linux 버전을 볼 수 있다면 얼마나 좋을까? 들리는 소식으로는 꿈만은 아닌 것 같다.
신현묵의 저자후기
델파이1부터 델파이4까지 이제 4개의 버전업을 한 델파이, 처음보았을때 떨리던 가슴을 진정시키던 기억이 아직도 생생하다. 강력한 개발환경, 짜임새있는 VCL, 멋진 인터페이스, 다양한 환경, 간단한 개발, 그리고, 강력한 수행능력. 분명 델파이는 일류(?)개발툴임에 틀림없습니다.
그동안 공부했던 내용과 다른 분들에게 자그마한 지식이라도 나누고 싶어서 이책을 만드는데 참여했습니다. 기존의 델파이책들이 너무 컴포넌트의 나열만으로써 이루어진 책들이 많기 때문에 조금은 색다른 모습의 책으로 책을 쓸려고 했는데 잘되었는지는 모르겠습니다. 처음에 많은 내용을 넣었으면 하는 욕심도 있었지만, 결국에는 지훈님과 계획잡았던 내용을 모두 채우지 못한 것이 아쉽습니다.
쓰고나니 조금은 이상한 델파이 책이 되어버린 것 같지만, 이 책을 보는 모든 사람에게 도움이 되었으면 좋겠습니다. 온라인 상의 좋은 정보는 하이텔의 비주얼툴( go vtool )과, 인터넷의 비주얼 파워툴의 홈페이지(http://www.visualtool.com)와 델마당의 홈페이지(http://www.delmadang.com)에도 들려주기 바란다. 아마 이책이 출판되었을때쯤에는 하이텔의 강좌란과 연계한 서비스도 보여줄 수 있을 것이다.
함께 글을 쓴 정지훈님이 너무 고생이 많으셨다. 공저로 작업한다고 해놓고선 바쁘다는 필계의 제가 쓸 분량을 다 채우지 못해 고생하신 '정지훈님'에게 먼저 감사드리고, 글을 쓰는데 지대한 도움을 준 우리 어부인 '진숙이'에게도 고맙고, 컴퓨터 전원스위치를 눌러 작업하던 파일을 몇번 날려먹은 우리아가 '수철이'에게도 고맙고, 자료를 찾는데 도움을 준 우리 'SPINTech직원들'에게도 감사감사… 그외 비주얼 파워툴의 '델파이 개발자'여러분에게도 감사감사.
꿈꾸는자의 미투데이 - 2008년 7월 29일
- 오늘 티스토리 http://zetlos.tistory.com 으로 옮겼다~~2008-07-29 20:38:17
이 글은 꿈꾸는자님의 2008년 7월 29일의 미투데이 내용입니다.
2008년 7월 29일 화요일
[SA강좌] Part 1 - 소프트웨어 아키텍처 개념에 대한 이해
소프트웨어아키텍트와 관련된 지식이 널리 퍼지기를 기원하며...
만들었던 초안 그대로 오픈합니다.
소프트웨어아키텍트를 꿈꾸는 분들에게 도움이 되었으면 합니다.
나름 괜찮게 만들어진 내용이라서리...
주변 사람들에게 널리 읽혔으면 좋겠다라는 개인적인 바램이 조금 있습니다.
~.~
[SA강좌] Part 1-10 아키텍트의 역할 정의
하나의 목록으로 만들어 봤습니다.
1회 - 소프트웨어 아키텍쳐 개념에 대한 이해.
2회 - 소프트웨어 아키텍쳐 설계를 하는 방법.
3회 - 컴포넌트 설계를 하는 방법과 설명,
4회 - 아키텍쳐에서 개발로의 이행하는 방법은?.
5회 - 소프트웨어 아키텍쳐 산출물 작성법.
6회 - 소프트웨어 아키텍쳐 설계(실전예제)에서 얻어보기.