저도 특정 테이블에서 데이터를 가져오는 것이 아니라, 데이터를 재가공한 후, 크리스탈 레포트로 출력하는 형식이었는데,

다음과 같이 진행하였습니다..^^

우선 님이 크리스탈 레포트에 출력하고자 하는 형식의 데이터셋 파일(*.xsd)을 만드세요. 그러면 원래 마법사가 뜨면서 Connection String도 넣어라고 하고, 나오죠? 거기서 취소를 하고 도구상자에서 DataTable을 하나 끌어와서 만듭니다.

그 DataTable을 임의로 MyTable이라고 하기로 하죠.
그리고 ID랑 Name이란 2개의 칼럼을 만들었다고 가정하겠습니다..^^ 그리고 저장을 합니다.

그럼 이 xsd 파일은 크리스탈 리포트 형식(*.rpt) 파일의 기반이 됩니다.
그러면, CrystalReportSource와 CrystalReportViewer를 각각 생성하고, cs와 cv라고 명명했다고 하죠.

그럼 rpt파일은 xsd파일을 이용해서 생성된 것이고, cs는 이 rpt파일을 기반으로 생성됩니다. 이해가 되시나요?^^;;

cv의 보고서 소스는 바로 cs를 선택하시면 되겠죠.. 그럼.. 크리스털리포트뷰어에 ID와 Name으로 구성된 페이지가 나올겁니다..

그럼 이제 내용을 채워야겠죠.. 내용을 채우는 순서는 다음과 같습니다.

1. DataTable 타입의 객체를 CrystalReportSource에 바인딩시킨다.
2. CrystalReportViewer의 ReportSource에 CrystalReportSource를 할당한다.
3. 그리고 CrystralReportViewer를 Refresh한다.

그럼 먼저 DataTable 객체를 선언하고, 정의해보면..

DataTable dataSrc = new DataTable();

dataSrc.Columns.Add("ID");
dataSrc.Columns.Add("Name");

dataSrc.Rows.Add(new string[]{"23", "Michael Jordan"});
dataSrc.Rows.Add(new string[]{"10", "Pele"});

이렇게 하시면 됩니다..^^

그럼 이제 이 객체를 CrystalReportSource에 바인딩시켜야겠죠.
아까 CrystalReportSource를 생성하고, 이름을 cs로 했다고 했으니...

cs.ReportDocument.SetDataSource(dataSrc);
cs.DataBind();

하면 됩니다.. 그리고 CrystalReportViewer의 ReportSource에 cs를 할당하고, 보고서를 새로 그려주면 됩니다.

cv.ReportSource = cs;
cv.RefreshReport();

-끝-

너무 길게 그리고.. 두서없이 쓴 것 같네요..^^; 그럼 즐프하세요.

-------------------------------------------------------------------------------------------
내가 예전에 데브피아에 쓴 답글..
근데, 시간이 흘러.. 갑자기 나도 써야하니.. 기억이 안나서 찾는다고 고생했다..
그래서 내 블로그에 남겨둠..-_- 이 한심한 기억력이란.. 쯧-ㅁ-

크리에이티브 커먼즈 라이센스
Creative Commons License

Posted by 노헝그리

2007/10/02 17:24 2007/10/02 17:24
, ,
Response
55 Trackbacks , 3 Comments
RSS :
http://www.nohungry.net/tt1/rss/response/104

C#에 대한 생각...

근래에 C#으로 5~6개의 프로젝트를 수행하면서 C#은 단지 Java와 C++을 짬뽕시켜놓은 특징없는 언어일뿐이라고 평가절하했던 나의 생각이 많이 바뀌었다.

프로그래머들에게 대체 불가의 언어로 여겨지는 C++과 8~90년대 급격한 성장을 해온 Java의 틈에 끼여 아직 C#이 차지하는 위치는 낮지만, 개인적으로 C#은 무궁무진한 장점을 가진 언어란 생각이 든다.

우선 C#에 대해 소개하자면, 앞서 언급한 것과 같이 C++과 Java를 교묘하게 섞어놓았다.
똑같이 .NET Framework를 기반으로 돌아가는 VB와는 달리, C#은 if, while, for 문이 C++과 정말 닮아있다. 물론, Java와도 정말 닮아있다.

또한, C#은 Java와 유사하게 .. 아니 표절이라고 해야하나?-ㅁ-; Garbage Collection을 지원한다. 따라서 특별한 경우를 제외하곤 프로그래머는 리소스 해제에 대해 신경 쓰지 않아도 된다. (하지만, 성능을 염두에 둔다면 가급적 Garbage Collection이 자주 발생하지 않게 프로그래밍 해야하지만!!)
포인터가 없다! (아니, 그냥 없다고 하면 그렇지만.. 없다고 봐도 무방하다고 하고 싶다.-ㅁ-)

Java와 마찬가지로 primitive type과 object type이 존재한다.
다시말하면, 정수를 다루는 타입이 기본적으로 int와 Integer 2가지가 제공된다. (물론, 역할은 다르지만..)

게다가, C#은 Windows Programming, Web Programming, PDA, Phone 등의 개발에 그대로 적용될 수 있다!

이 모든 것이 다 .NET Framework 때문이다. 따라서, .NET Framework는 Java Virtual Machine이 가지고 한 장점을 고스란히 가지고 있다고 볼 수 있다. (물론, 상이한 점도 존재하지만!)

그리고, Java보다 좋은 점..^^
UI 꾸미기가 마치 VB 만큼이나 쉽다. 고로, 생산성이 좋다! Java는 사실 좋은 툴로 프로그래밍한 기억이 전혀 없어서 그럴 수도 있지만.. 버튼을 생성하고, 이벤트 핸들러를 등록하는 작업이 아직도 악몽같다-_-

그러고보니, 학부 때도 처음에 C/C++ 보다 Java에 더 애착이 갔었던 과거를 생각하면... 난 이상하게도 Managed Code에 잘 이끌리는 것 같다-ㅁ-


물론, 그래도 회사의 주력 제품의 개발 언어가 C++이기 때문에 이 녀석에 대한 공부도 여전히 소홀할 수는 없다. 하지만, 근래에 C#에 대해 많은 수련을 거듭하면서 웹 프로그래밍도 어느 정도 가능하게 되었고.. 프로그래밍에 대한 다양하고 폭 넓은 사고를 할 수 있는 계기가 되고 있다는 생각이 든다.

C#을 공부하면서 드는 생각은..
축구에서도 멀티 플레이어를 강조하는 현대 시대에 더 이상, C/C++ 만 고집해서만은 안되겠다는 생각이 든다. (물론! C/C++이 소프트웨어 개발 분야에서 대체 불가능한 언어란 생각에는 변함이 없다^^)

크리에이티브 커먼즈 라이센스
Creative Commons License

Posted by 노헝그리

2007/08/01 23:47 2007/08/01 23:47
Response
No Trackback , 2 Comments
RSS :
http://www.nohungry.net/tt1/rss/response/98

[C#] 메일 자동 발송 프로그램

 하루에도 많게는 수백통씩 날아들어오는 스팸 메일의 시대에 살면서... 나 또한 그러한 범죄에 악용될 수 있는 프로그램을 만들어버렸다.

예전 아티클에도 나와있지만... 이번에도 회사 업무 차원에서 만들게 되었다. (그렇다고 우리 회사에서 스팸을 보내기 위해 만든 것이 아니다. 병역특례 관련해서 각 대학에 공문을 발송하기 위해 만들었다.)

이전과 달라진 점은...
SMTP를 설정하지 않아도 된다는 점이다. 왜냐하면 IIS를 설치하면 제공되는 ESMTP를 쓰기 때문이다.

따라서, 무료로 제공하는 SMTP를 찾기 위해 헤맬 필요가 없다. 자신 PC의 포트를 통해 발송하기 때문이다. 정확하게 기억은 안나지만.. 아마도 80번 포트?-ㅁ-; (기억이 안나는 이유는 2월쯤인가 만들었었다.)

급하게 부탁받아.. 하루 정도 걸려 만들었기 때문에, 자질구레한 예외는 가볍게(?) 무시해버린 센스를 발휘했다. 그래서, 무슨 버그가 발생할지 알 수 없다.

구현은 그 때와 마찬가지로 C#과 .NET Framework 2.0을 기반으로 했다.

주요기능
- 동일한 내용의 메일을 대량으로 발송
- 메일링 리스트 불러오기 및 저장 가능
- 메일링 리스트 추가, 삭제, 저장, 수정 가능
- 메일 내용 미리보기 기능(HTML로 작성된 메일을 브라우저에서 어떻게 보일까를 위해..)
- 첨부 파일 (용량 제한은 상대방 수신 메일 서버에서 허용하는 범위 만큼만)
- 메일 내용 불러오기 및 저장 가능
- 서명 첨부 가능
- 발송한 메일 로그 확인
[디자인적 측면은 전혀 고려하지 않은 유저 인터페이스]

[메일 내용 미리 보기]

비록 C#으로 구현하였지만.. Visual Studio 2005를 사용하는 사람이라면, C++, Visual Basic으로도 동일하게 구현가능하다.

부끄러워서 풀 소스 공개는 못하더라도.. 주요부분(ESMTP를 이용해 메일을 발신하는 부분 - 몇 줄 되지도 않고, 새로울 것도 없지만.. )은 공개 가능하다.

덧1) 이러한 포스트를 남기는 이유는.. 명색이 컴공 전공자로써.. 전공 얘기가 전무한 것이 부끄러버서 한거라고는 말 못함-ㅁ-

덧2) 회사에서 병역특례(전문연구요원)를 구하고 있음. 전공은 전산쪽 계열이며 가능함. (물론, 프로그래밍 가능자).. 덧붙이면 2007년 8월 졸업자에 한함. 관심있는 분들은 연락바람.
크리에이티브 커먼즈 라이센스
Creative Commons License

Posted by 노헝그리

2007/05/02 18:00 2007/05/02 18:00
, , , , ,
Response
19 Trackbacks , 9 Comments
RSS :
http://www.nohungry.net/tt1/rss/response/78

[C#] Cross Thread Problem

서두는 제외하고, 바로 예를 들어 설명하도록 하겠다. (편의 상 반말로...)

A란 프로그램은 여러 개의 Thread가 돌고 있다. 그 중 Thread T1은 B란 프로그램과 소켓 통신을 위해 사용되는데, T1은 B에서 전송하는 메시지를 처리한다. 그리고 처리된 메시지는 바로 텍스트 박스 컨트롤에 표시된다.

프로그래머는 단순히, 다음과 같이 코드를 썼다.

ThreadFunc T1()
{
    while(1){
           ....
           // B가 보낸 메시지를 받는다.
           int nMessage = GetSocketMessage();
           
          // 메시지를 텍스트 박스에 표기한다.
           txtBoxControl.Text = nMessage.ToString();            
    }
}
    
그랬더니 Cross Thread Problem이란 메시지가 뜨며, 프로그램이 제대로 수행될 수 없다고 나온다. 과연, Cross Thread Problem이란 무엇인가 (물론, 위의 코드가 정확히 Cross Thread Problem을 발생하는 것은 아니다.. 하지만 그럴 가능성을 내재하고 있는 코드라고 할 수 있다.)?!

MSDN에 따르면,
전문적인 프로그램은 응답성 있는 사용자 인터페이스를 유지하기 위해 worker thread들을 사용하게 된다(*hyperthreading 또는 Multiple CPU들의 최대화를 위해서..). 하지만, .NET에서 이 문제는 특별히 쉬운 문제가 아니다, 왜냐면, Windows Forms 컴포넌트들은 thread safe 하지 않기 때문이다(특별히 번역할 말이 없어서-_-.. Thread들에 대해 안전하지 않다 정도의 뉘앙스일까나..?).

.NET의 어떤 버젼에서는 thread들 내부에 GUI 컴포넌트의 함수를 호출하려고 할 경우, 예외를 발생시킬 수 있다. 하지만, 종종 내가 의도한 바와 다른 이상한 결과를 내는 것으로 끝날 수도 있다(예외는 발생 안했지만, 내가 의도한 결과와 다르게 나올 수 있다는 말이다).

해결 방법은?!
만약, 다른 thread로부터 GUI 컴포넌트를 호출하고 싶다면, 직접적으로(directly) 호출할 수는 없다. 대신에 컨트롤 클래스로부터 상속받은 invoke 함수를 통해 간접적으로(indirectly) 실행하고자 하는 컴포넌트의 함수를 호출할 수 있다.

다른 invoke 함수와는 달리, 컨트롤 클래스의 invoke 함수는 데이터 corruption을 피해 호출을 동기화할 수 있도록 보장해준다.

컨트롤의 invoke 함수를 호출하기 위해 필요한 것은 invoke 함수의 인자로써 호출하고자 하는 함수를 delegate로 작성해서 넘겨야 한다. 그리고 invoke 함수의 인자로 넘어가는 함수에 필요한 인자는 object 배열로 넘겨야 한다.

예를 통해서 살펴보자!
예제 프로그램은 다른 프로그램에서 소켓을 통해 날려주는 탭 컨트롤의 인덱스를 받아, 현재 프로그램의 탭을 변경하는(그러니까 탭 화면을 바꾸는) 기능을 포함하고 있다.

즉, 다른 프로그램에서 전송하는 메시지를 처리하는 함수가 Thread로 동작하고 있고, 이 Thread 내부에서 탭 컨트롤의 탭을 변경하는 상황이 발생하기 때문에, Cross Thread 문제가 발생하였다(참고로 말하면, 각 탭에도 탭에 어떠한 데이터를 표현하기 위한 다른 Thread들도 동작하고 있기 때문에, Cross Thread 문제가 매우 발생하기 쉬운 구조다.)

예제 코드를 보면!
우선 WaitMessage()란 함수는 다른 프로그램에서 Socket을 통해 전송하는 메시지를 처리하기 위한 Thread 함수다. 이 때 받아들이는 메시지는 현재 프로그램의 탭 컨트롤의 인덱스이다. 이 Thread 내부에서 탭 컨트롤의 탭을 변경하기 위해 바로, SelectTab() 함수를 호출할 경우, Cross Thread 문제로 인한 Exception이 발생한다.

DoWork()는 이러한 문제를 회피하기 위한 함수다. 자세한 내용은 아래 코드를 보면서 얘기하자.
                                           ....

  DoWork() 함수는 앞서 WaitMessage() 함수에서 다른 프로그램으로부터 전송받은 탭 인덱스를 파라미터로 받아 현재 프로그램의 탭을 변경하는 역할을 수행한다. 또한, DoWork() 함수는 앞서 언급한 Cross Thread 문제를 회피하기 위해 컨트롤 클래스의 Invoke 함수를 사용하는데, Invoke 함수를 사용하기 위해서는 필연적으로 delegate를 선언해야 한다(delegate에 대한 상세한 내용은 다른 기술 문서를 참조하기 바란다.)

예제에선 ChangeTab이란 delegate를 선언하고, DoWork() 함수에서 사용한다.
DoWork() 함수에선 탭 컨트롤의 InvokeRequired 속성을 체크해 true일 경우, Invoke() 함수를 사용한다.
앞서 선언한 delegate의 파라미터로 탭 컨트롤의 SelectTab() 함수를 넘기고, Invoke() 함수에는 delegate와 SelectTab() 함수에 필요한 인자(탭 인덱스)를 함께 파라미터로 넘긴다.



결론
지금까지 간략하게 Cross Thread Problem에 대해 기술해보았다. 보다 깊은 내용보다는 왜 문제가 발생하고, 어떻게 해결하느냐에 대한 기술만 해놓았기 때문에, 보다 자세한 내용을 알고 싶다면, MSDN을 참조하기 바란다.


덧, hyperthreading에 대한 보다 자세한 내용은 http://blog.naver.com/subellia1?Redirect=Log&logNo=100011680762의 article을 참조하기 바란다.

크리에이티브 커먼즈 라이센스
Creative Commons License

Posted by 노헝그리

2006/10/20 17:35 2006/10/20 17:35
,
Response
No Trackback , 2 Comments
RSS :
http://www.nohungry.net/tt1/rss/response/39

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

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

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



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

프로그램의 버젼 정보



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

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



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

UpdateCheck.h


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


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

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

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

UpdateCheck 사용


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

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

다운로드 : http://www.nohungry.net/Data/AutoUpdateChecker.zip
참조: http://www.codeproject.com/cpp/updatecheck.asp
크리에이티브 커먼즈 라이센스
Creative Commons License

Posted by 노헝그리

2006/09/21 10:34 2006/09/21 10:34
,
Response
No Trackback , 3 Comments
RSS :
http://www.nohungry.net/tt1/rss/response/34

C++ Platform SDK Function에서 제공하는 ShellExecute와 동일한 동작을 하는 녀석이 C#에도 있다.
물론, C#에서도 ShellExecute를 가져와서 쓸 수도 있지만..

사용법은 다음과 같당.

// 실행시키고자 하는 프로세스의 주소를 넘긴다.
System.Diagnostics.ProcessStartInfo process =
new System.Diagnostics.ProcessStartInfo(@"D:\SmartMailService.exe");          

// 프로세스의 실행 방식을 설정한다.
// Verb는 프로세스의 동작 방식을 가리킨다.

process.UseShellExecute = true;
process.Verb = "open";

// 프로세스를 실행한다.
System.Diagnostics.Process.Start(process);  

       

크리에이티브 커먼즈 라이센스
Creative Commons License

Posted by 노헝그리

2006/09/20 09:57 2006/09/20 09:57
Response
No Trackback , 5 Comments
RSS :
http://www.nohungry.net/tt1/rss/response/33


블로그 이미지

뽐뿌가 없으면 블로그도 없다.

- 노헝그리

Archives

Calendar

«   2009/01   »
        1 2 3
4 5 6 7 8 9 10
11 12 13 14 15 16 17
18 19 20 21 22 23 24
25 26 27 28 29 30 31

Site Stats

Total hits:
129883
Today:
65
Yesterday:
93