11.프린터 출력하기

본장에서는 프린터에 문자와 그림을 출력하는 전반적인 방법을 설명합니다. 본장의 내용은 크게 두 항목으로 나누어집니다. MFC에서 프린팅 방법과 SDK함수를 이용한 프린팅 방법입니다. MFC에서는 View의 OnDraw함수에서 글자나 그림을 출력하거나  또는 OnPrint함수에서 글자나 그림을 출력하면 바로 프린터로 인쇄됩니다. 그만큼 프린팅 방법이 쉽습니다. 그러나 프린트를 언제나 View에서 하지 않으며 여러곳에서 프린팅을 할때가 있습니다. 이럴경우에는 SDK함수를 이용하는 것이 편리 합니다. SDK함수를 이용할때는 프린터 DC와 디바이스등 각종 정보를 알고 그에 맞게 설정을 해주어야 합니다. 다소 복잡한 면은 있으나. 상용 프로그램을 작성하고자 할때는 필수적으로 알아야 할것입니다.

대상자: 초급,중급,고급

Chapter 등급: 1 필수, 2 선택

공부방법:

1 항목은 MFC 에서 프린팅 하는 방법입니다. 매우 쉽습니다. 꼭 알아두시기 바랍니다. 2항목은 SDK에 대한 개념이 많지 않은 분들에게는 다소 어려운 항목입니다. 중급자 이상분들은 한번쯤을 알아두는것이 좋을 것입니다. 초급자는 후에 프로그램을 작성할때 View가 아닌 부분에서 프린트 해야 할필요가 있을경우 예제를 보고 응용하시기 바랍니다.

1.MFC 에서의 프린팅

본항목에서는 AppWizard 를 이용하여 프로젝트를 만들었을때 즉 MFC를 이용하는 윈도우 프로그램을 만들경우 이때 인쇄를 하는 내용에 대해서 설명합니다.

<1>OnDraw에서의 프린팅

MFC에서의 인쇄는 무척 간단합니다. OnDraw 안에 출력시킬 데이터를 설정하면 그 내용이 바로 인쇄됩니다. OnDraw 함수 안에 다음과 같이 했을 경우

pDC->TextOut(0,0,"이것은 하나의 테스트입니다.□);

화면의 좌표 0, 0에 □이것은 하나의 테스트입니다.□가 출력되고 마찬가지로 프린터에도 같은 내용의 글자가 출력됩니다. 그런데 우리가 하나 생각해야 할 문제가 있습니다. 화면은 보통 가로 640×480, 800×600, 1024×768 등의 모드를 가지고 있습니다. 즉 화면은 점의 좌표입니다. 또한 화면은 가로가 넓고 세로가 작습니다. 그런데 프린터 용지는 가로가 좁고 세로가 넓습니다. A4 용지의 경우 가로가 보통 21cm이고 세로가 30cm입니다. 이 용지와 화면은 모드 자체가 맞지 않습니다.

화면 모드가 점으로 표시되는 모드를 보통 MM_TEXT라고 합니다. 보통 일반 프로그램에서 프린터를 중히 여기는 데서는 화면 모드를 MM_LOMETRIC 단위로 전환시킵니다. 이것은 가로, 세로 단위가 0.1mm입니다. A4 용지와 맞게 화면 모드를 설정하려면 가로 21, 세로 30의 형으로 화면 모드를 전환시켜야겠지요.

pDC->SetMapMode(MM_LOMETRIC);

//모드 자체를 A4 용지에 맞춤.

pDC->SetWindowExt(2100, 3000);

pDC->SetWindowOrg(0,0);

위와 같은 방법으로 화면 자체를 프린터와 맞추어 놓고 그냥 화면에 데이터를 출력하는 방법을 이용한 다음 그대로 프린터로 출력하면 됩니다.

화면을 프린터 용지에 맞추어서 설정하고 OnDraw 함수를 이용하는 것은 화면과 프린터에 출력하는 모습이 일치할 경우입니다. 만일 화면과 프린터에 출력하는 방법이 서로 다르다면 어떻게 해야 할까요?

이 때는 OnDraw 함수 안에 IsPrinting 함수를 이용하여 분기하는 방법과 또한 OnPrint 함수를 새로 수정하는 방법이 있습니다.

OnDraw 함수 안에 글자 및 이미지를 출력했을 경우 그것이 모두 화면과 프린터에 출력됩니다.

사용자가 화면이 아니라 프린터로 출력하라는 메뉴를 설정하였을 경우 IsPrinting 함수는 TRUE를 리턴합니다. 즉 화면에 출력될 때와 화면에 출력하지 않을 경우를 IsPrinting 함수를 이용하여 분기하면 됩니다. View클래스가 CTestView일경우 IsPrinting함수를 이용하여 분기한 예는 다음과 같습니다.

BOOL CTeseView::OnDraw(CDC* pDC, CSize& rSize)

{

CEx2063Doc* pDoc = GetDocument();

ASSERT_VALID(pDoc);

if(pDC->IsPrinting())//만약 화면이 아니라 프린터이면

{

//이곳에 프린트할 내용을 설정

}

else

{

//이곳에 화면에 출력할 내용을 설정

}

return TRUE;

}

위와 같이 했을 경우 OnDraw 함수가 호출될 때 IsPrinting 함수 안의 내용은 프린터로 출력할 때만, else 안에는 화면에 출력했을 때만 설정됩니다. 만약 화면에는 MM_TEXT 모드로, 프린터에는 MM_LOMETRIC로 출력할 경우라면 다음과 같이 하면 됩니다.

BOOL CTestView::OnDraw(CDC* pDC, CSize& rSize)

{

CEx2063Doc* pDoc = GetDocument();

ASSERT_VALID(pDoc);

if(pDC->IsPrinting())//만약 화면이 아니라 프린터이면

{

//프린터는 MM_LOMETRIC 모드를 사용한다. 가로 0.1mm 세로 0.1mm 세로로

//내려갈수록 음수값

pDC->SetMapMode(MM_LOMETRIC);

pDC->TextOut(0,0,"이것은 테스트입니다.";

pDC->TextOut(0,-100,"이것은 다음 줄입니다.");

}

else//화면 출력 함수

{

pDC->SetMapMode(MM_TEXT);

pDC->TextOut(0,0,"이것은 테스트입니다.");

pDC->TextOut(0,20,"이것은 다음 줄입니다.");

}

return TRUE;

}

위와 같이 하면 화면은 화면대로 또한 프린터는 프린터대로 서로 다른 모드에 서로 정확하게 인쇄할 수가 있습니다.

<2>OnPrint 에서의 인쇄

두 번째 방법으로 OnPrint 함수를 수정하는 방법이 있습니다. Class Wizard를 실행시켜 OnPrint 메시지를 설정하여 OnPrint 함수를 만들면 다음과 같습니다.

void CTestView::OnPrint(CDC* pDC, CPrintInfo* pInfo)

{

// TODO: Add your specialized code here and/or call the base class

CScrollView::OnPrint(pDC, pInfo);

}

위 내용에서 CScrollView::OnPrint 함수가 실행되면 OnDraw 함수가 호출됩니다. 이때 CScrollView::OnPrint 함수를 제거하게 되면 OnDraw 함수가 호출되지 않습니다. 이렇게 되면 OnPrint 함수에서 코딩을 하면 인쇄를 목적으로 내용을 출력할수가 있습니다.

void CEx1091View::OnPrint(CDC* pDC, CPrintInfo* pInfo)

{

// TODO: Add your specialized code here and/or call the base class

}

그리고 그 안에 프린터로 출력할 내용을 넣습니다.

void CTestView::OnPrint(CDC* pDC, CPrintInfo* pInfo)

{

//프린터는 MM_LOMETRIC 모드를 사용한다. 가로 0.1mm, 세로 0.1mm 세로로

//내려갈수록 음수값

pDC->SetMapMode(MM_LOMETRIC);

pDC->TextOut(0,0,"이것은 테스트입니다.");

pDC->TextOut(0,-100,"이것은 다음 줄입니다.");

}

그렇다면 OnDraw 함수를 수정해야 하겠지요.

BOOL CTestView::OnDraw(CDC* pDC, CSize& rSize)

{

CEx2063Doc* pDoc = GetDocument();

ASSERT_VALID(pDoc);

//OnDraw 함수는 화면 출력에만 사용됨.

pDC->SetMapMode(MM_TEXT);

pDC->TextOut(0,0,"이것은 테스트입니다.");

pDC->TextOut(0,20,"이것은 다음 줄입니다.");

return TRUE;

}

위와 같이 수정하면 OnDraw 함수는 화면 출력에만, 프린터로 인쇄할 경우에는 OnPrint 함수가 실행됩니다.

지금까지 설명한 두 가지 방법 중 어느 방법이 좋다 나쁘다는 말할 수 없습니다. 다만 인쇄할 내용이 많다면 OnPrint 함수를 사용하는 것이 좋습니다.

<3>인쇄 페이지 설정

프린트할 때 MFC 함수에서 중간중간 체크하는 여러 함수가 있습니다. □지금 프린터로 프린트 시작이다!□를 먼저 알려 준 다음 □프린터로 프린팅을 한다!□를 알려 주고 다음 □프린트가 끝났다□를 알려 주게 되어 있습니다.

이 때의 함수와 내용은 다음과 같습니다.

OnPreparePrinting : 프린트하기 전에 준비하는 함수

OnBeginPrinting	: 프린터로 프린트 시작

OnPrint	: 프린트하는 도중

OnEndPrinting	: 프린트가 종료

프린트하기 전에 준비하는 OnPreparePrinting 함수는 미리 프린트할 내용을 준비하는 것입니다. 몇 페이지를 프린트할 것인가 하는 것들을 준비하죠.

다음 OnBeginPrinting에서는 프린터 GDI를 설정합니다. 다음  OnPrint가 호출되고 마지막으로 프린트가 종료되면 OnEndPrinting에서 GDI 객체가 해제됩니다.

여기서 우리가 주의깊게 생각할 함수가 OnPreparePrinting입니다. 우리가 프린트할 내용이 1페이지 이상일 경우 몇 페이지를 프린트할 것인가를 설정해 주어야 합니다. 설정을 하지 않으면 프로그램에서는 디폴트(default)값이 1페이지를 설정해 줍니다. 만일 현재 설정할 페이지가 2페이지인데 페이지를 설정하지 않으면 2페이지의 내용은 어떻게 될까요? 물론 출력되지 않습니다. 이 때는 OnPreparePrinting 함수에 다음과 같이 전체 페이지를 설정해 줍니다.

BOOL CTestView::OnPreparePrinting(CPrintInfo* pInfo)

{

pInfo->SetMaxPage(2);

return DoPreparePrinting(pInfo);

}

<4>인쇄 하기 예제 Print1Ex

Print1Ex 프로그램은 여러 Text 배열을 화면에 출력하고 동시에 프린터로 출력하는 예제입니다. 화면 출력에서는 MM_TEXT 모드를 사용하여 출력을 하고 프린터로 출력할 경우에는 MM_LOMETRIC 모드를 사용합니다. 그림 1-11-1는 Print1Ex 의 전체 구조 입니다.

(그림 파일)

(그림 1-11-1)Print1Ex 전체 구조

Print1Ex는 SDI형태로 만든 예제이며 View클래스가 CScrollView로 설정하였습니다. 이렇게 설정한후에 OnDraw에서 IsPrint함수를 이용하여 문자를 출력하는 예제입니다. 화면에 출력할때 (그림 1-11-1의 ②항목)는 세로 크기를 20으로 프린터에 출력할때는 (그림 1-11-1의 ①항목) 세로크기를 60으로 설정하였습니다. MM_TEXT모드에서 일반적으로 프린터출력시 화면보다 약 3배정도가 크기 때문입니다. ⓐ 항목은 프린터 미리보기 항목이며 ⓑ항목은 화면에 출력된 항목입니다. 두항목 모두 정확하게 문자를 출력할수 있습니다. Print1Ex에서 프린트를 할때 화면의 스크롤 사이즈를 설정해 주어야 합니다. 이 이유는 70줄의 문자열이 한 화면에 출력되지 않을수도 있기 때문입니다. 스크롤 사이즈는 보통 OnInitialUpdate 에서 설정합니다. 다음은 70줄의 문자를 출력할수 있도록 스크롤 사이즈를 설정한 CPrint1ExView의 OnInitialUpdate입니다.

void CPrint1ExView::OnInitialUpdate()

{

CScrollView::OnInitialUpdate();

CSize sizeTotal;

//The size of screen is made to be

// 00 pixels for x; 70 pixels for y; and 20 pixels per line.

sizeTotal.cx =100;

sizeTotal.cy=70*20;

SetScrollSizes(MM_TEXT, sizeTotal);

}

Print1Ex는 위에 설정한 OnInitalUpdate함수와 그림 1-11-1의 OnDraw함수외에 더이상 코딩한 부분이 없습니다. Print1Ex의 소스는 생략하겠습니다. 제공되는 CD-ROM을 참조하시기 바랍니다.

<5>맵핑 모드를 달리한 예제 Print2Ex

화면에 출력하는 모드와 프린터로 출력하는 모드를 변경해야 할 필요가 있습니다. Print2Ex는 화면에 출력하는 모드를 MM_TEXT로 하고 프린터로 출력하는 모드를  MM_LOMETRIC으로 설정했습니다. 실질적으로 사용자는 화면의 출력 형태와 프린터 출력 형태가 같다고 느낄 것입니다. 그러나 프로그래머는 다른 모드라는 것을 생각해야 하겠지요.

화면에 꽉차는 이미지 파일, 즉 1024×768 크기의 이미지 파일도 실질적으로 프린트할 경우 종이에 반도 안 되는 경우가 있습니다. 프린터의 GDI와 화면의 GDI의 형태가 다르기 때문이지요.

그림 1-11-2는 Print2Ex의 전체 구조 입니다.

(그림파일)

(그림 1-11-2)Print2Ex의 전체 구조

그림 1-11-2의  ⓐ 항목은 Print2Ex의 화면 출력형태이며  ⓑ항목은 Print2Ex의 프린터 미리보기 상태입니다. 화면 출력은 MM_TEXT모드로 프린터로 추력하는 모드는  MM_LOMETRIC로 설정한 OnDraw함수는 다음과 같습니다.

void CPrint2ExView::OnDraw(CDC* pDC)

{

CPrint2ExDoc* pDoc = GetDocument();

ASSERT_VALID(pDoc);

//프린터로 출력할 경우

if(pDC->IsPrinting())

{

//매핑 모드를 MM_LOMETRIC로 설정한다.

pDC->SetMapMode(MM_LOMETRIC);

CFont Font;

CFont *pOldFont;

//폰트가 가로 100이므로 10mm, 세로 40이므로 4mm의 형태로

//바탕체를 설정한다.

Font.CreateFont(100,40,0,0,0,FALSE,FALSE,0,DEFAULT_CHARSET,OUT_DEFAULT_PRECIS,

CLIP_DEFAULT_PRECIS,DEFAULT_QUALITY,DEFAULT_PITCH,"바탕체");

//폰트를 등록시키고

pOldFont = (CFont *)pDC->SelectObject(&Font);

//글자를 출력한다. mode MM_LOMETRIC이므로

//밑으로 갈수록 음수값이다.

pDC->TextOut(0,0,"이것은 테스트입니다.");

pDC->TextOut(0,-100,"이것은 MM_LOMETRIC 모드로 글자의 가로가 4mm이고 ");

pDC->TextOut(0,-200,"세로의 길이가 10mm인 크기입니다.");

pDC->TextOut(0,-300,"프린트한 후 자로 재 보세요.");

pDC->SelectObject(pOldFont);

Font.DeleteObject();

}

else

{

//MM_TEXT모드

pDC->SetMapMode(MM_TEXT);

CFont Font;

CFont *pOldFont;

//세로 10, 가로 20인 폰트를 만든다.

Font.CreateFont(20,10,0,0,0,FALSE,FALSE,0,DEFAULT_CHARSET,OUT_DEFAULT_PRECIS,

CLIP_DEFAULT_PRECIS,DEFAULT_QUALITY,DEFAULT_PITCH,"바탕체");

pOldFont = (CFont *)pDC->SelectObject(&Font);

//화면에 글자를 출력

pDC->TextOut(0,0,"이것은 테스트입니다.");

pDC->TextOut(0,20,"이것은 MM_TEXT 모드이고 글자의 세로가 20픽셀 ");

pDC->TextOut(0,40,"가로가 10픽셀인 크기입니다.");

pDC->TextOut(0,60,"프린트를 하면 가로가 4mm이고 ");

pDC->TextOut(0,80,"세로가 10mm인 글자로 출력됩니다.");

pDC->SelectObject(pOldFont);

Font.DeleteObject();

}

}

OnDraw에서 InPrinting을 분기점으로 프린터로 출력시에는 MM_LOMETRIC, 화면에 출력시에는 MM_TEXT를 사용했습니다.

화면에 출력할 글자의 폰트에서 첫번째와 두 번째가 세로와 가로의 크기입니다. 먼저 모드를 설정한 다음 그 모드에 맞게 폰트를 만든 것입니다. 사실 화면에서 10×20의 글자는 MM_LOMETRIC에서 4×10과 비슷하게 느껴집니다.

즉 화면에서 보이는 글자와 실질적으로 프린트했을 때 글자의 이미지가 비슷하다고 느끼는 것이죠. 필자는 간단한 에디터를 만들 때 화면 모드를 MM_TEXT으로 사용하고 프린터 모드를 MM_LOMETRIC로, 프린트시에는 MM_TEXT의 크기에서 반으로 설정했습니다. 이 방법 외에도 모드를 알맞게 설정하는 많은 방법이 있습니다. 그러나 실질적으로 프로그램에서 직접 출력하여 서로를 비교해 가는 게 제일 편한 방법 같습니다.

본예제의 소스는 생략합니다. 제공되는 CD-ROM을 참조하시기 바랍니다.

<6>여러 페이지 출력 예제 Print3Ex

Print3Ex 프로그램은 두 페이지 이상의 데이터를 프린터로 출력할 때 사용하는 방법을 설명합니다. 즉 많은 양의 데이터를 페이지를 달리하면서 프린트하는 것이죠.

프로그램의 실행 모습중에 Print Preview 항목을 설정했을 때의 모습은 그림 1-11-3과 같습니다.

(그림 1-11-3)Print3Ex에서 Print Preview항목 선택시

이 프로그램에서는 OnDraw를 사용하지 않고 OnPrint 함수에 프린트할 내용을 기록했습니다.

제일 먼저 OnPreparePrinting 함수에 프린트할 내용이 2페이지라고 설정합니다.

BOOL CEx1093View::OnPreparePrinting(CPrintInfo* pInfo)

{

pInfo->SetMaxPage(2);

return DoPreparePrinting(pInfo);

}

다음 OnPrint 함수를 클래스 위자드를 이용하여 만들어 CScrollView::OnPrin- t(pDC,pInfo);를 삭제합니다. 즉 OnDraw 함수를 호출하는 것을 막자는 이야기이죠.

void CEx1093View::OnPrint(CDC* pDC, CPrintInfo* pInfo)

{

}

여기에서 각 페이지마다 데이터를 출력하면 됩니다.

void CEx1093View::OnPrint(CDC* pDC, CPrintInfo* pInfo)

{

int m_nPage;

//현재 페이지를 받은 다음

m_nPage=pInfo->m_nCurPage;

if(m_nPage==1)//1페이지이면

{

//1페이지일 때 데이터 출력

}

if(m_nPage==2)//2페이지이면

{

//2페이지일 때 데이터 출력

}

:

}

pInfo 안에 있는 pInfo->m_nCurPage에는 현재 출력할 페이지 번호가 설정되어 있습니다. 이 값을 가지고 1페이지일 때는 어떻게 출력, 2페이지일 때는 어떻게 출력하는지 위와 같이 if문을 가지고 해도 되고 스위치문이나 그에 합당한 방법으로 각 페이지마다 알맞게 프린터 객체에 데이터를 출력합니다.

본예제의 소스는 제공되는 CD-ROM  을 참조하시기 바랍니다. 위에서 설명한 내용외에는 코딩한 부분이 없기 때문에 위의 내용만 이해하시면 쉽게 작성할수 있을것입니다.

<7>프린터 DC를 이용한 프린터 출력

CView나 CScrollView일 경우에는 프린터 DC를 내장하고 있어서 프린터로 문자나 그랙픽 출력이 매우 용이하나 FormView일 경우 또는 대화상자일경우에는 내용을 프린팅하는데 지금까지 사용한 방법을 이용할 수가 없습니다. 이때에는 직접 프린터 DC를 이용합니다. 이내용은 다음과 같습니다.

(1)프린터 DC얻기

프린터에 데이터를 출력하기 위해서는 프린터 DC를 얻어야 합니다. GDI를 설명할 때 그래픽을 출력하는 모든 것을 윈도에서는 DC를 이용한다고 설명을 하였습니다. 프린터도 그래픽을 출력하는 것이기 때문에 DC를 이용합니다. 어플리케이션 프로그래머는 단순하게 프린터의 DC를 얻고 얻은 DC에 그래픽 출력함수를 이용하여 출력을 해주면 됩니다. 프린터 DC를 얻는 방법중 가장 쉬운 방법이 CPrintDialog 를 이용하면 됩니다.

CPrintDialog *pDlg = new CPrintDialog(FALSE);

pDlg->DoModal();

HDC hdc= pDlg->GetPrinterDC();

프린터 대화상자를 수행한후에 이 대화상자 클래스의 맴버 함수 GetPrinterDC()함수를 실행하면 HDC형태의 DC를 리턴합니다. 이 DC는 WIN32 SDK 에서 사용하는 구조체입니다. 결국 위와 같이 HDC를 얻는다면 WIN32 SDK함수를 이용하여 그래픽을 출력하는 형태를 갖게 됩니다.

(2)프린터 DC에 출력하기

프린터에 출력을 하면 프린터 관리자에는 현재 어떤 내용이 프린터로 출력되고 있고 어떤 내용이 지금 대기중에 있다는 내용이 나타납니다. 화면에 출력하는 부분과는 달리 프린터로 그래픽이나 문자를 출력할 경우 출력되는 내용에 어떤 제목을 설정해주어야 합니다. 즉 현태 프린터로 보낸 데이터의 정보를 설정해 주어야 한다는 것이지요. 프린터나 모니터가 같은 DC를 이용한다 하여도 모니터는 현재 내용을 계속적으로 화면에 출력할수 있지만 프린터는 이미 데이터를 프린터 메모리에 보내고 그다음 결과는 프린터에 의해서 결정이 되기 때문에 현재 프린터로 보낸 정보를 관리해야 할필요가 있으니까요. 이때 사용하는 구조체가

DOCINFO 입니다.

typedef struct {    /* di */

int     cbSize;

LPCSTR  lpszDocName;

LPCSTR  lpszOutput;

} DOCINFO;

cbSize 는  현재 구조체의 크기를 설정하는 것입니다.

lpszDocName는 현재 정보 구조체의 이름입니다.

lpszOutput 는  출력하는 파일의 이름을 나타냅니다. 이곳에 이름을 설정하면

출력하는 데이터가  파일로 전환 됩니다. NULL로 설정하면 출력하는	곳이 바로 프린터 디바이스가 됩니다.

DOCINFO구조체를 설정하고 이곳에 프린터할 데이터를 정보를 설정합니다.

//프린터로 출력시에 출력하는 정보 설정

DOCINFO di={ sizeof(DOCINFO),"Print1: 테스트",NULL};

위와 같이 한후 프린터에 데이터를 출력하는 방법은 다음과 같은 방법을 이용합니다.

1. 프린터 DC에 프린터 정보를 출력 시작을 알린다.

//프린터 DC에 정보를 출력 시작.

::StartDoc(hdc,&di);

2. 페이지 시작을 알린다.

//페이지 시작을 알린다.

::StartPage(hdc);

3. 프린터 DC에 출력할 데이터를 기록한다.

4. 데이터를 기록한 DC를 제저장한다.

//DC를 최근의 형태로 제저장한다.

::RestoreDC(hdc,-1);

5. 페이지 종료

::EndPage(hdc);

6.정보 출력 종료

::EndDoc(hdc);

위의 6개 방법을 사용하면 간단하게 프린터로 내용을 출력할 수가 있습니다.

<8>프린터 DC를 이용한 프린터 출력 예제 Print4Ex

Print4Ex는 그림1-11-4와 같이 FormView로 데이터를 입력하고 입력된 데이터를 프린터로 출력하고 Print Preview 메뉴 항목을 누르면 현재 프린터될 내용을 화면에 출력하는 예제입니다.

(그림 1-11-4) FormView에서 프린트 예제 Print4Ex

(그림 1-11-5) Print4Ex에서 Print Preview항목 선택시

FormView에서 기본적으로 제공하는 Print와 PrintPreview함수는 제대로 동작을 하지 않습니다. 즉 PrintPreview를 선택하여 보면 출력되는 내용이 아무것도 나타나 있지 않습니다. 물로 OnDraw 함수에서 문자를 출력을 하면 Print Preview로 보면 화면에 데이터가 출력되고 또한 Print 메뉴를 선택하면 데이터가 출력이 됩니다. 본장에서 설명하는 내용의 주된 초점은 MFC의 OnDraw함수를 이용하지 않고 데이터를 출력하는 방법입니다.

Print4Ex는 FormView의 3개의 입력 란에 입력한 데이터를 프린터로 출력하고 Print Preview를 선택하면 우리가 만든 View화면으로 전환 하는 방법을 사용하여 프린터에 출력할 내용을 보여줍니다.

Print4Ex 를 AppWizard로 설정할 때 CPrint4ExView의  Basic Class를 FormView로 설정하여 프로젝트를 만듭니다. FormView로 설정을 하였을 때 생성되는 대화상자 자원 IDD_PRINT4EX_FORM이 바로 CPrint4EXView와 연결되는 자원입니다. 이자원을 그림1-11-6과 같이 변형을 합니다.

(그림 1-11-6) IDD_Print4Ex_FORM의 변경된 내용

IDD_PRINT4EX_FORM의 ID와 CPrint4EXView와 연결되는 변수의 형은 표1과 같습니다.

ID	Print4ExView의 맴버	내 용
IDC_EDIT1	m_strName	이름 입력
IDC_EDIT2	m_strSubject	제목 입력
IDC_EDIT3	m_strContent	내용 입력

(표 1) CPrint4EXView와 IDD_PRINT4EX_FORM와 연결관계

CPrint4ExView안에는 CString형으로 m_strName와 m_strSubject와 m_strContent가 연결되어있습니다. 본 예제는 Print Preview 항목을 이용하기 위해서 다중 View를 이용합니다. 그렇기 때문에 자원에 연결된 데이터의 내용을 그대로 Document에 저장할 필요가 있습니다. View의 맴버와 같은 내용을 도큐먼트 헤더에 설정합니다.

//View에 입력된  데이터 저장 맴버

CString	m_strName;//이름

CString	m_strSubject;//제목

CString	m_strContent;//내용

메뉴에서 Print 항목을 클릭하면 먼저 자원에 입력한 데이터를 UpdateData함수를이용하여 View멤버로 저장을 한다음 다시 View의 데이터를 도큐먼트에 저장을 한후에 도큐먼트에 저장을 한 내용을 프린터로 출력을 합니다.

void CPrint4ExView::OnFilePrint()

{

//화면입력에서 -> View멤버로 데이터 얻기

UpdateData(TRUE);

//View데이터를 도큐먼트에 저장

CPrint4ExDoc *pDoc=(CPrint4ExDoc *)GetDocument();

pDoc->m_strName=m_strName;

pDoc->m_strSubject=m_strSubject;

pDoc->m_strContent=m_strContent;

//프린터 대화상자를 클래스를 설정

CPrintDialog *pDlg = new CPrintDialog(FALSE);

//프린터로 출력시에 출력하는 이름 설정

DOCINFO di={ sizeof(DOCINFO),"Print1: 테스트",NULL};

//대화사상자 실행

if(pDlg->DoModal()==IDCANCEL)

{

delete pDlg;

return;

}

//프린터 DC를 받는다.

HDC hdc= pDlg->GetPrinterDC();

//프린터 DC에 정보를 출력 시작

::StartDoc(hdc,&di);

//페이지 시작을 알린다.

::StartPage(hdc);

//데이터 출력

::TextOut(hdc,0,0,pDoc->m_strName,pDoc->m_strName.GetLength());

::TextOut(hdc,0,40,pDoc->m_strSubject,pDoc->m_strSubject.GetLength());

::TextOut(hdc,0,80,pDoc->m_strContent,pDoc->m_strContent.GetLength());

//DC를 최근의 형태로 제저장한다.

::RestoreDC(hdc,-1);

//페이지 종료를 알린다.

::EndPage(hdc);

//정보출력을 종료 한다.

::EndDoc(hdc);

delete pDlg;

}

함수앞에 ::를 사용한 것은 본함수는 Win32 SDK 라는 것을 알려주는 것입니다. 또는 C언어 함수라는 것을 알려줄때도 위와 같이 사용합니다.

Print4Ex 예제에서 Print Preview메뉴를 선택하면 CFormView에서 CView로 바뀌고 FormView에서 입력한 데이터를 화면에 출력합니다. 즉 한 개의 도큐먼트에 두 개의 View를 사용한 것입니다. 본방법은 전항목의 다중 View 의 방법을 그대로 이용한것입니다. 본 예제에서 CView는 CPrintView로 만들었습니다. CPrintView의 OnDraw함수는 다음과 같습니다.

CPrint4ExDoc* pDoc =(CPrint4ExDoc*) GetDocument();

pDC->TextOut(0,0,pDoc->m_strName);

pDC->TextOut(0,20,pDoc->m_strSubject,pDoc->m_strSubject.GetLength());

pDC->TextOut(0,40,pDoc->m_strContent);

단순하게 도큐먼트의 데이터를 받아서 화면에 출력하기만 합니다.

즉 FormView에서 받은 데이터를 도큐먼트로 넘기고 View를 CView로 전환한다음 도큐먼트에서 데이터를 받아서 화면에 출력하는 것이지요.

프린팅 미리보기를 위와 같은 방법으로 위와 같은 방법으로 만들면 매우 편리합니다.

Print4Ex에서 중요한 내용은 프린터 DC를 이용하여 프린팅 하는 방법과 다중View를 이용하여 프린팅 미리보기를 만든것입니다. 전장의 다중View와 일치함으로 소스를 보면서 내용을 확인해 보시면 알수 있을것입니다.

<9>예제 Print4Ex 소스

(1)메인 프레임 소스

(프로그램 소스시작)

// MainFrm.h : interface of the CMainFrame class

//

/////////////////////////////////////////////////////////////////////////////

#if !defined(AFX_MAINFRM_H__0ECD160B_7614_11D1_8F36_006097AD9619__INCLUDED_)

#define AFX_MAINFRM_H__0ECD160B_7614_11D1_8F36_006097AD9619__INCLUDED_

#if _MSC_VER >= 1000

#pragma once

#endif // _MSC_VER >= 1000

class CMainFrame : public CFrameWnd

{

protected: // create from serialization only

CMainFrame();

DECLARE_DYNCREATE(CMainFrame)

// Attributes

public:

//FormView화면

CPrint4ExView *m_pMainView;

//프린팅 미리 보기 화면

CPrintView *m_pPrintView;

// Operations

public:

void ShowPrintView();

void ShowMainView();

// Overrides

// ClassWizard generated virtual function overrides

//{{AFX_VIRTUAL(CMainFrame)

virtual BOOL PreCreateWindow(CREATESTRUCT& cs);

//}}AFX_VIRTUAL

// Implementation

public:

virtual ~CMainFrame();

#ifdef _DEBUG

virtual void AssertValid() const;

virtual void Dump(CDumpContext& dc) const;

#endif

protected:  // control bar embedded members

CStatusBar  m_wndStatusBar;

CToolBar    m_wndToolBar;

// Generated message map functions

protected:

//{{AFX_MSG(CMainFrame)

afx_msg int OnCreate(LPCREATESTRUCT lpCreateStruct);

// NOTE - the ClassWizard will add and remove member functions here.

//    DO NOT EDIT what you see in these blocks of generated code!

//}}AFX_MSG

DECLARE_MESSAGE_MAP()

};

/////////////////////////////////////////////////////////////////////////////

//{{AFX_INSERT_LOCATION}}

// Microsoft Developer Studio will insert additional declarations immediately before the previous line.

#endif // !defined(AFX_MAINFRM_H__0ECD160B_7614_11D1_8F36_006097AD9619__INCLUDED_)

// MainFrm.cpp : implementation of the CMainFrame class

//

#include "stdafx.h"

#include "Print4Ex.h"

#include "Print4ExDoc.h"

#include "Print4ExView.h"

#include "printview.h"

#include "MainFrm.h"

#ifdef _DEBUG

#define new DEBUG_NEW

#undef THIS_FILE

static char THIS_FILE[] = __FILE__;

#endif

/////////////////////////////////////////////////////////////////////////////

// CMainFrame

IMPLEMENT_DYNCREATE(CMainFrame, CFrameWnd)

BEGIN_MESSAGE_MAP(CMainFrame, CFrameWnd)

//{{AFX_MSG_MAP(CMainFrame)

// NOTE - the ClassWizard will add and remove mapping macros here.

//    DO NOT EDIT what you see in these blocks of generated code !

ON_WM_CREATE()

//}}AFX_MSG_MAP

END_MESSAGE_MAP()

static UINT indicators[] =

{

ID_SEPARATOR,           // status line indicator

ID_INDICATOR_CAPS,

ID_INDICATOR_NUM,

ID_INDICATOR_SCRL,

};

/////////////////////////////////////////////////////////////////////////////

// CMainFrame construction/destruction

CMainFrame::CMainFrame()

{

// TODO: add member initialization code here

m_pPrintView=NULL;

}

CMainFrame::~CMainFrame()

{

}

int CMainFrame::OnCreate(LPCREATESTRUCT lpCreateStruct)

{

if (CFrameWnd::OnCreate(lpCreateStruct) == -1)

return -1;

if (!m_wndToolBar.Create(this) ||

!m_wndToolBar.LoadToolBar(IDR_MAINFRAME))

{

TRACE0("Failed to create toolbar\n");

return -1;      // fail to create

}

if (!m_wndStatusBar.Create(this) ||

!m_wndStatusBar.SetIndicators(indicators,

sizeof(indicators)/sizeof(UINT)))

{

TRACE0("Failed to create status bar\n");

return -1;      // fail to create

}

// TODO: Remove this if you don't want tool tips or a resizeable toolbar

m_wndToolBar.SetBarStyle(m_wndToolBar.GetBarStyle() |

CBRS_TOOLTIPS | CBRS_FLYBY | CBRS_SIZE_DYNAMIC);

// TODO: Delete these three lines if you don't want the toolbar to

//  be dockable

m_wndToolBar.EnableDocking(CBRS_ALIGN_ANY);

EnableDocking(CBRS_ALIGN_ANY);

DockControlBar(&m_wndToolBar);

return 0;

}

BOOL CMainFrame::PreCreateWindow(CREATESTRUCT& cs)

{

// TODO: Modify the Window class or styles here by modifying

//  the CREATESTRUCT cs

return CFrameWnd::PreCreateWindow(cs);

}

/////////////////////////////////////////////////////////////////////////////

// CMainFrame diagnostics

#ifdef _DEBUG

void CMainFrame::AssertValid() const

{

CFrameWnd::AssertValid();

}

void CMainFrame::Dump(CDumpContext& dc) const

{

CFrameWnd::Dump(dc);

}

#endif //_DEBUG

/////////////////////////////////////////////////////////////////////////////

// CMainFrame message handlers

void CMainFrame::ShowPrintView()

{

m_pMainView =(CPrint4ExView *) GetActiveView();

if (m_pPrintView == NULL)

{

m_pPrintView = new CPrintView;

CCreateContext context;

context.m_pCurrentDoc = m_pMainView->GetDocument();

m_pPrintView->Create(NULL, NULL, 0L, CFrameWnd::rectDefault,

this, 2, &context);

m_pPrintView->OnInitialUpdate();

}

SetActiveView(m_pPrintView);

m_pPrintView->ShowWindow(SW_SHOW);

m_pMainView->ShowWindow(SW_HIDE);

m_pPrintView->SetDlgCtrlID(AFX_IDW_PANE_FIRST);

RecalcLayout();

}

void CMainFrame::ShowMainView()

{

SetActiveView(m_pMainView);

m_pPrintView->ShowWindow(SW_HIDE);

m_pMainView->ShowWindow(SW_SHOW);

m_pMainView->SetDlgCtrlID(AFX_IDW_PANE_FIRST);

RecalcLayout();

}

(프로그램 소스끝)

(2)View클래스 소스

(프로그램 소스)

// Print4ExView.h : interface of the CPrint4ExView class

//

/////////////////////////////////////////////////////////////////////////////

#if !defined(AFX_PRINT4EXVIEW_H__0ECD160F_7614_11D1_8F36_006097AD9619__INCLUDED_)

#define AFX_PRINT4EXVIEW_H__0ECD160F_7614_11D1_8F36_006097AD9619__INCLUDED_

#if _MSC_VER >= 1000

#pragma once

#endif // _MSC_VER >= 1000

class CPrint4ExView : public CFormView

{

protected: // create from serialization only

CPrint4ExView();

DECLARE_DYNCREATE(CPrint4ExView)

public:

//{{AFX_DATA(CPrint4ExView)

enum{ IDD = IDD_PRINT4EX_FORM };

CString	m_strName;

CString	m_strSubject;

CString	m_strContent;

//}}AFX_DATA

// Attributes

public:

CPrint4ExDoc* GetDocument();

// Operations

public:

// Overrides

// ClassWizard generated virtual function overrides

//{{AFX_VIRTUAL(CPrint4ExView)

public:

virtual BOOL PreCreateWindow(CREATESTRUCT& cs);

protected:

virtual void DoDataExchange(CDataExchange* pDX);    // DDX/DDV support

virtual BOOL OnPreparePrinting(CPrintInfo* pInfo);

virtual void OnBeginPrinting(CDC* pDC, CPrintInfo* pInfo);

virtual void OnEndPrinting(CDC* pDC, CPrintInfo* pInfo);

virtual void OnPrint(CDC* pDC, CPrintInfo*);

//}}AFX_VIRTUAL

// Implementation

public:

virtual ~CPrint4ExView();

#ifdef _DEBUG

virtual void AssertValid() const;

virtual void Dump(CDumpContext& dc) const;

#endif

protected:

// Generated message map functions

protected:

//{{AFX_MSG(CPrint4ExView)

afx_msg void OnFilePrint();

afx_msg void OnFilePrintPreview();

//}}AFX_MSG

DECLARE_MESSAGE_MAP()

};

#ifndef _DEBUG  // debug version in Print4ExView.cpp

inline CPrint4ExDoc* CPrint4ExView::GetDocument()

{ return (CPrint4ExDoc*)m_pDocument; }

#endif

/////////////////////////////////////////////////////////////////////////////

//{{AFX_INSERT_LOCATION}}

// Microsoft Developer Studio will insert additional declarations immediately before the previous line.

#endif // !defined(AFX_PRINT4EXVIEW_H__0ECD160F_7614_11D1_8F36_006097AD9619__INCLUDED_)

// Print4ExView.cpp : implementation of the CPrint4ExView class

//

#include "stdafx.h"

#include "Print4Ex.h"

#include "Print4ExDoc.h"

#include "Print4ExView.h"

#include "PrintView.h"

#include "MainFrm.h"

#ifdef _DEBUG

#define new DEBUG_NEW

#undef THIS_FILE

static char THIS_FILE[] = __FILE__;

#endif

/////////////////////////////////////////////////////////////////////////////

// CPrint4ExView

IMPLEMENT_DYNCREATE(CPrint4ExView, CFormView)

BEGIN_MESSAGE_MAP(CPrint4ExView, CFormView)

//{{AFX_MSG_MAP(CPrint4ExView)

ON_COMMAND(ID_FILE_PRINT, OnFilePrint)

ON_COMMAND(ID_FILE_PRINT_PREVIEW, OnFilePrintPreview)

//}}AFX_MSG_MAP

// Standard printing commands

END_MESSAGE_MAP()

/////////////////////////////////////////////////////////////////////////////

// CPrint4ExView construction/destruction

CPrint4ExView::CPrint4ExView()

: CFormView(CPrint4ExView::IDD)

{

//{{AFX_DATA_INIT(CPrint4ExView)

m_strName = _T("");

m_strSubject = _T("");

m_strContent = _T("");

//}}AFX_DATA_INIT

// TODO: add construction code here

}

CPrint4ExView::~CPrint4ExView()

{

}

void CPrint4ExView::DoDataExchange(CDataExchange* pDX)

{

CFormView::DoDataExchange(pDX);

//{{AFX_DATA_MAP(CPrint4ExView)

DDX_Text(pDX, IDC_EDIT1, m_strName);

DDX_Text(pDX, IDC_EDIT2, m_strSubject);

DDX_Text(pDX, IDC_EDIT3, m_strContent);

//}}AFX_DATA_MAP

}

BOOL CPrint4ExView::PreCreateWindow(CREATESTRUCT& cs)

{

// TODO: Modify the Window class or styles here by modifying

//  the CREATESTRUCT cs

return CFormView::PreCreateWindow(cs);

}

/////////////////////////////////////////////////////////////////////////////

// CPrint4ExView printing

BOOL CPrint4ExView::OnPreparePrinting(CPrintInfo* pInfo)

{

// default preparation

return DoPreparePrinting(pInfo);

}

void CPrint4ExView::OnBeginPrinting(CDC* /*pDC*/, CPrintInfo* /*pInfo*/)

{

// TODO: add extra initialization before printing

}

void CPrint4ExView::OnEndPrinting(CDC* /*pDC*/, CPrintInfo* /*pInfo*/)

{

// TODO: add cleanup after printing

}

void CPrint4ExView::OnPrint(CDC* pDC, CPrintInfo*)

{

// TODO: add code to print the controls

}

/////////////////////////////////////////////////////////////////////////////

// CPrint4ExView diagnostics

#ifdef _DEBUG

void CPrint4ExView::AssertValid() const

{

CFormView::AssertValid();

}

void CPrint4ExView::Dump(CDumpContext& dc) const

{

CFormView::Dump(dc);

}

CPrint4ExDoc* CPrint4ExView::GetDocument() // non-debug version is inline

{

ASSERT(m_pDocument->IsKindOf(RUNTIME_CLASS(CPrint4ExDoc)));

return (CPrint4ExDoc*)m_pDocument;

}

#endif //_DEBUG

/////////////////////////////////////////////////////////////////////////////

// CPrint4ExView message handlers

void CPrint4ExView::OnFilePrint()

{

//화면입력에서 -> View멤버로 데이터 얻기

UpdateData(TRUE);

//View데이터를 도큐먼트에 저장

CPrint4ExDoc *pDoc=(CPrint4ExDoc *)GetDocument();

pDoc->m_strName=m_strName;

pDoc->m_strSubject=m_strSubject;

pDoc->m_strContent=m_strContent;

//프린터 대화상자를 클래스를 설정

CPrintDialog *pDlg = new CPrintDialog(FALSE);

//프린터로 출력시에 출력하는 이름 설정

DOCINFO di={ sizeof(DOCINFO),"Print1: 테스트",NULL};

//대화사상자 실행

if(pDlg->DoModal()==IDCANCEL)

{

delete pDlg;

return;

}

//프린터 DC를 받는다.

HDC hdc= pDlg->GetPrinterDC();

//프린터 DC에 정보를 출력 시작

::StartDoc(hdc,&di);

//페이지 시작을 알린다.

::StartPage(hdc);

//데이터 출력

::TextOut(hdc,0,0,pDoc->m_strName,pDoc->m_strName.GetLength());

::TextOut(hdc,0,40,pDoc->m_strSubject,pDoc->m_strSubject.GetLength());

::TextOut(hdc,0,80,pDoc->m_strContent,pDoc->m_strContent.GetLength());

//DC를 최근의 형태로 제저장한다.

::RestoreDC(hdc,-1);

//페이지 종료를 알린다.

::EndPage(hdc);

//정보출력을 종료 한다.

::EndDoc(hdc);

delete pDlg;

}

void CPrint4ExView::OnFilePrintPreview()

{

UpdateData(TRUE);

CPrint4ExDoc *pDoc=(CPrint4ExDoc *)GetDocument();

pDoc->m_strName=m_strName;

pDoc->m_strSubject=m_strSubject;

pDoc->m_strContent=m_strContent;

((CMainFrame*)(AfxGetApp()->m_pMainWnd))->ShowPrintView();

}

(프로그램 소스끝)

2.SDK 에서의 인쇄

본항목에서는 SDK에서 프린터 할때 사용하는 SDK함수를 설명합니다. 프린팅을 할때 꼭 View에서 만 이루어 지지 않습니다. 때로는 대화상자에서도 메인프레임에서도 프린팅을 할필요가 있습니다. 이럴경우에는 SDK 함수를 주로 이용합니다. 본항목에서는 SDK함수를 이용하여 프린팅하는 전반적인 내용을 설명합니다.

<1>설정된 프린터수와 이름 얻기

보통 일반적으로 한 대의 컴퓨터에는 한 대의 프린터가 연결되어 있는 경우가 기본입니다. 그러나 LAN을 이용한 환경에서는 여러대의 프린터가 연결될수 있고 때로는 프린터 포트 1,2(LPT1, LPT2)에 두 대가 설치 되었을경우도 있습니다. 프린터에 데이터를 출력하고자 할 경우 최우선적으로 알아내어야 할 것이 프린터가 있나 없느나와 프린터가 몇 개가 설치되어 있으며 어느 프린터에 인쇄를 할것인가입니다. 실제 이것을 아는방법중 가장 무식한 방법은 윈도우디렉토리의  win.ini파일에서 [Devices]항목을 찾아서 이곳에 설정되어 있는 데이터를 읽는것입니다.

[Devices]

HP DeskJet 870 Series=HPRDJC03,\\Sparrow\hp 870k

HP LaserJet 5  XL (KOREA)=HPHXLAA,\\Condor\hp laserjet5

만약 위와 같은 내용이 win.ini파일에 있다면 컴퓨터에 HP DeskJet 870 Series프린터와 HP LaserJet 5 XL (KOREA)라는 프린터가 연결되어 있으며 이프린터는 Sparrow라는 컴퓨터와 Condor이라는 컴퓨터에 연결되어 있고 현재 네트워크 프린터를 사용하고 있다는 것을 알수가 있습니다.

이렇게 하는 방법보다 더 간편한 방법이 EnumPrinters 함수를 사용하는 것입니다.

이함수는 다음과 같습니다.

BOOL EnumPrinters(

DWORD Flags, // 프린터 정보 얻기 위한 명령 플러그

LPTSTR Name, // 프린터 이름

DWORD Level, // 프린터 정보의 특별한 타입

//PRINTER_INFO_1~PRINTER_INFO_5 까지의 정보를 설정하는 버퍼 포인터

LPBYTE pPrinterEnum,

DWORD cbBuf, // pPrinterEnum이 가르키는 포인터의 크기

LPDWORD pcbNeeded, //필요한 바이트의 수

LPDWORD pcReturned // 리턴되는 프린터 정보

);

Flags는 프린터 정보를 얻기 위한 명령 플러그입니다. 이플러그에 설정되는 값은 다음과 같습니다.

PRINTER_ENUM_LOCAL: 연결되어 있는 프린터

PRINTER_ENUM_NAME  : 이름으로 설정된 프린터

PRINTER_ENUM_LOCAL를 설정하면 EnumPrinters는 연결되어 있는 프린터를 순차적으로 돌아가면서 나머지 인자에 설정된 정보에 의한 내용을 수행합니다.

PRINTER_ENUM_NAME:를 설정하면  EnumPrinter는 연결되어 있는 특정 프린터에 대한 정보를 얻습니다.

Name는 프린터 객체 이름을 말합니다. Level은 프린터 정보를 얻고자 할 때 전달하는 구조체에 해당하는 타입을 설정하는데 값은 1,2,4,5로 설정할수 있습니다. 1로 설정되면 PRINTER_INFO_1 구조체의 값이 pPrinterEnum 곳에 설정되고 2일경우에는 PRINTER_INFO_2 가 4일경우에는 PRINTER_INFO_4 5일경우에는 PRINTER_INFO_5의구조체에 정보를 넣어서 설정됩니다. PRINTER_INFO_1 구조체는 프린터 이름을 중심으로 설정되며 PRINTER_INFO_2는 프린터 드라이브 이름과 포트 이름을 중심으로 설정되면 PRINTER_INFO_4 프린터 이름과 서버 이름으로 PRINTER_INFO_5는 프린터 이름과 포트 이름을 중심으로 설정됩니다. 즉 Level에 값을 정하고 pPrinterEnum 에 적당한 구조체를 설정함으로써 정보를 얻을수 있습니다. pcbNeeded  본 정보를 저장하기 위해서 필요한 메모리 정보를 pcReturned 에는 결과 정보가 설정됩니다. 예를 들어서 현재 설정되어 있는 프린터의 수와 필요한 메모리 크기를 얻고자 한다면 다음과 같이 할수 있습니다.

//연결된 프린터의 필요한 데이터 크기와 컴퓨터 수를 얻는다.

EnumPrinters (PRINTER_ENUM_LOCAL,

NULL, 5, (LPBYTE) "", 0, &dwNeeded, &dwReturned) ;

위와 같이 하면 dwNeeded는 PRINTER_INFO_5형태로 저장할 메모리 크기와 dwReturned는 현재 연결된 프린터의 수가 설정이 됩니다.

위와 같이 하여 PRINTER_INFO_5의 구조체 포인터를 만들고 이변수를 dwNeeded만큼 메모리를 할당해 준다음 EnumPrinters함수를 실행시키면 이구조체에 설정되어 있는 프린터 정보를 일련의 배열로 설정합니다.

//필요한 메모리 설정

szInfo=GlobalAlloc(GHND,dwNeeded);

//이메모리를 PRINTER_INFO_5구조체에 할당

printinfo=(LPPRINTER_INFO_5)GlobalLock(szInfo);

//프린터 정보를 얻는다.

EnumPrinters (PRINTER_ENUM_LOCAL,

NULL, 5, (LPBYTE) printinfo, dwNeeded,

&dwNeeded, &dwReturned);

예를 들어서 프린터가 두 개가 연결되어 있다고 가정을 하다면 printinfo에는 첫 번째 프린터 정보가 printinfo+1이 두 번째 프린터 정보가 설정되는 것입니다.

PRINTER_INFO_5구조체의 맴버중에서 pPrinterName 변수가 바로 프린터 이름입니다.

<2>프린터 정보 얻기

프린터로 문자나 그림을 출력하고자 할 경우 프린터 정보를 얻어야 합니다. 즉 가로 출력할 수 있는 픽셀과 세로의 픽셀수 또한 가로의 크기 세로의 크기등을 얻어야 합니다. 이이유는 많은 프린터들이 출력되는 픽셀이 다르기 때문입니다. 픽셀수가 작은 프린터와 픽셀수가 많은 프린터에 같은 픽셀의 크기로 (즉 MM_TEXT 모드로) 출력을 한다면 픽셀수가 작은 프린터에서 글자의 크기는 크게 나올것입니다. 가로 픽셀 및 용지의 가로크기를 얻어서 문자나 그림을 비례적으로 얻기 위해서는 먼저 프린터의 성능이 어떤가의 정보가 필요합니다. 이런 정보를 얻기 위해서는 1차적으로 프린터 DC를 얻어야 합니다. 프린터 DC를 얻을 때 정보를 위한 DC는 CreateIC 함수를 이용합니다.

HDC CreateIC(

LPCTSTR lpszDriver, // 드라이버 이름

LPCTSTR lpszDevice, // 디바이스 이름

LPCTSTR lpszOutput, // 포트 또는 파일명

CONST DEVMODE *lpdvmInit // 설정할 초기 모드값

);

예를 들어서 □HP DeskJet 870 Series□ 라는 프린터의 DC를 얻고자 한다면 다음과 같습니다.

PrintDc=CreateIC(NULL,□HP DeskJet 870 Series□,NULL,NULL);

만약 EnumPrinters함수에 의해서 얻어진 정보 값 printinfo를 이용하여 첫 번째 프린터 DC를 얻고자 한다면 다음과 같이 할수 있습니다.

PrintDc=CreateIC(NULL,printinfo->pPrinterName,NULL,NULL);

이와 같이 하여 프린터 DC를 얻고 난다음 GetDeviceCaps를 이용하여 여러 정보를 얻을수 있습니다. 표2은 GetDevieceCaps에 의해서 얻을수 있는 리스트들입니다.

(표 2) GetDeviceCap의 nIndex리스트

(표시작)

설정값        내용

HORZSIZE 밀리미터의 가로크기

VERTSIZE 밀리미터의 세로크기

HORZRES  수평 픽셀수

VERTRES  수직 픽셀수

LOGPIXELSX  가로방향으로 로직컬 인치당 픽셀수

LOGPIXELSY  세로 방향으로 로직컬 인치당 픽셀수

BITSPIXEL 각픽셀에 대한 컬러 비트수

PLANES  컬러 플레인

NUMBRUSHES 장치에 설정된 브러쉬 수

NUMPENS 장치에 설정된 펜의 수

NUMFONTS  장치에 설정된 폰트의 수

NUMCOLORS  장치의 색상 테이블의 항목수

ASPECTX  선그리기를 윈한 장치 픽셀의 상대적인 폭

ASPECTY  선그리기를 위한 장치 픽셀의 상대적인 높이

ASPECTXY 선그리기를 위한 장치 픽셀의 대각선 크기

CLIPCAPS 장치의 클리핑 특성을 나타내는 플래그

(표끝)

이외에도 많은 정보들이 있습니다. 나머지는 GetDeviceCaps 함수를 도움말에서 찾아서 확인해보시기 바랍니다.

예를 들어서 프린터의 가로 픽셀수를 얻고자 한다면 위에서 얻은 프린터 DC PrintDc와 HORZSIZE를 이용하여 다음과 같이 하여 얻을수 있습니다.

dwInfodata=GetDeviceCaps(PrintDc,HORZSIZE);

워드 프로세서에서는 모든 문자와 크기를 밀리미터 또는 인치 단위로 사용하고 있습니다. 화면에서는 이것이 일정비율로 크게 또는 작게 나와도 상관은 없으나 프린터 할경우에는 이 단위가 정확하게 출력되어야 합니다.이렇게 정확하게 출력하기 위해서는 LOGPIXELSX 플러그 등을 사용하여 정보를 얻고 이정보에 맞게 글자와 그림을 맞추어야 합니다. 이때 GetDeviceCaps는 매우 유용하게 사용됩니다.

<3>프린터 정보 대화상자

프린터에 대한 정보에 대한 공용 대화상자는 PrinterProperties 함수를 이용합니다.이함수의 형은 다음과 같습니다.

BOOL PrinterProperties(

HWND hWnd, // 부모 윈도우

HANDLE hPrinter // 프린터 핸들

);

이함수는 프린터 정보를 알려주는 대화상자를 출력하는 함수입니다. 여기에서 프린터 핸들이라는 인자가 있습니다. 즉 프린터 핸들이 있어야만 이함수를 가동할수 있습니다. 프린터 핸들을 얻기 위해서 OpenPrinter 함수를 사용합니다.

BOOL OpenPrinter(

LPTSTR pPrinterName, //프린터 디바이스 이름

LPHANDLE phPrinter, // 프린터 핸들

LPPRINTER_DEFAULTS pDefault // 구조체 정보 포인터

);

OpenPrinter에 위에서 우리가 얻었던 프린터 드라이버 이름을 설정하면 phPrinter에 핸들이 넘어옵니다. OpenPrinter함수를 이용하여 프린터를 열었다면 ClosePrinter를 실행시켜 프린터를 닫아 주어야 합니다. 다음은 프린터 정보 대화상자를 실행하는 예입니다.

//프린터를 오픈하고

if (OpenPrinter ((printinfo+iPrinterNumber)->pPrinterName, &hPrint, NULL))

{

//대화상자 실행후

PrinterProperties (hwnd, hPrint) ;

//프린터를 닫는다.

ClosePrinter (hPrint) ;

}

위와 같이 했을 때 프린터에 대한 정보를 얻을수 있는 대화상자가 실행됩니다. 이대화상자는 프린터 제조업체가 제공한 드라이버를 설정했을때는 다르게 나타납니다.

<4>비트맵 출력하기

비트맵을 프린터로 출력하는 부분은 DC를 받고 이곳에 간단하게 비트맵을 출력하는 방법으로는 제대로 출력이 안됩니다. 지금까지 비트맵출력에 대한 함수로 BitBlt를 설명했습니다. 이함수를 이용하여 프린터 DC에 출력을 하면 빈종이만 나올것입니다. 이유는 간단합니다. BitBlt는 장치 의존적인 비트맵을 출력할 때 사용하는 함수입니다. 즉 장치 디바이스에 일반적인 기본 팔레트가 설정되어 있고 단순히 비트맵 정보만 가지고 있을경우에 출력하는 함수입니다. 비트맵을 출력하기 위해서는 장치 의존적인 비트맵을 장치 독립적인 비트맵으로 바꾸어야 합니다. 이것을 DIB라고 합니다. 실제 DIB는 비트맵 파일 (확장자가 bmp)인 파일을 로드하고 출력할 때 또는 다른 여러 그래픽 파일을 로드하여 출력할 때 많이 사용합니다.

BitBlt는 화면을 위한 함수이지 프린터를 위한 함수가 아니기 때문에 어떤 장치에서도 출력할수 있는 DIB로 장치독립적인 비트맵을 전환시켜야 합니다. 쉽게 보면 HBITMAP핸들을 이용하여 로드하고 출력한 비트맵을 DIB형태로 전환 해야 한다는 것입니다. DIB 형태는 2개의 구조체와 한 개의 비트맵 정보를 가지고 있는 버퍼로 구성됩니다. 이 2개의 구조체가 BITMAPINFO 와 BITMAPINFOHEADER입니다.

먼저 BITMAPINFOHEADER의 구조체는 다음과 같습니다.

typedef struct tagBITMAPINFOHEADER{ // bmih

DWORD  biSize; //BITMAPINFOHEADER의 크기

LONG   biWidth; // 비트맵의 가로크기

LONG   biHeight; //비트맵의 세로크기

WORD   biPlanes; //비트맵 정보 플랜 보통 1입니다.

WORD   biBitCount //한픽셀당 사용되는 비트수

DWORD  biCompression; //압축유무

DWORD  biSizeImage; //이미지의 크기

LONG   biXPelsPerMeter; //픽셀당 미터 X

LONG   biYPelsPerMeter; //픽셀당 미터 Y

DWORD  biClrUsed; //사용되는 색수

DWORD  biClrImportant; //중요한 색

} BITMAPINFOHEADER;

BITMAPINFOHEADER구조체에서 biBitCount는 현재 비트맵의 색상수를 이야기 합니다. 예를 들어서 비트카운트가 8이면 한 개의 픽셀을 출력하기 위해 8비트가 필요한것이고 이것은 2에 8승의 색을 출력할수 있으므로 256칼라입니다. 비트가 24비트일 경우 이것은 트루 칼라이며 비트가 4일 경우 16칼라 비트가 1일경우는 2칼라 즉 흑백이 됩니다. 만약 100x100의 이미지가 있고 biBitCount가 8이라면 총 필요한 바이트 수는 10000 이되며 투르 칼라일경우에는 30000이 되는 것입니다.

BITMAPINFO 구조체는 다음과 같습니다.

typedef struct tagBITMAPINFO {

BITMAPINFOHEADER    bmiHeader; //위의 구조체 정보

RGBQUAD             bmiColors[1];//칼라 값

} BITMAPINFO;

BITMAPINFO는 위에서 설명한 BITMAPINFOHEADER과 RGBQUAD라는 칼라정보구조체를 배열로 가지고 있습니다. RGBQUAD는 다음과 같습니다.

typedef struct tagRGBQUAD { // rgbq

BYTE    rgbBlue; //청색 정보

BYTE    rgbGreen; //녹색 정보

BYTE    rgbRed; //적색 정보

BYTE    rgbReserved; //예약값 사용하지 않음

} RGBQUAD;

RGBQUAD란 색정보를 가지고 있는 구조체입니다. 컴퓨터에서는 청색 녹색 적색을 3원색으로 색을 표현합니다. 이색값을 가지고 있다는 의미입니다. 예를 들어 16칼라일 경우 BITMAPINFO는 RGBQUAD 16개의 배열을 가지고 있고 256일경우에는 256개의 배열을 가지고 있습니다. 그럼 트루칼라일경우에는 몇 개의 배열을 가지고 있을까요? 정답은 한 개도 가지고 있지 않다입니다. 이이유는 컴퓨터에서 사용하는 색에 기인하기 때문입니다. 컴퓨터에서 사용하는 총색은 적색 256값 청색 256값 녹색 256값을 가지고 있습니다. 이 3개의 조합으로 색을 표현하기 때문에 총나올수 있는 색은 256*256*256의 색입니다. 여기에서 256칼라를 가진 그림은 어떤 색을 가지게 될까요? 그냥 위의 총색중 0번부터 255번까지만 가지게 될까요? 만일 256색으로 그림을 그린다고 할 경우 사용하고 싶은 색이 256번 다음 예를들어 1000번쪽에 있다면 256으로는 이색을 표현하지 못하겠네요? 그렇지 않다는게 바로 RGBQUAD의 필요성을 말해줍니다. 즉 컴퓨터가 사용하는 모든 색중에서 현재 그림에 필요한 색을 256개 추출해서 이색정보를 배열로 저장해 놓고 화면에 출력할 경우 1번이라고 하면 색정보 배열번호 1번에서 RGB값을 얻어다 출력을 하게 하는 것입니다. 이것을 팔레트라고 합니다. 그렇기 때문에 트루칼라는 팔레트가 필요없지만 트루칼라 이하는 색을 가지고 출력하는 그림들은 팔레트가 필요한것입니다 현재 그림에서 사용하는 색의 정보를 얻기 위함이지요.

실제 보면 비트맵을 출력하고자 할 경우 2개의구조체라고 하였으나 단1개의 구조체 즉 BITMAPINFO 로 가능합니다. 이안에 또다른 구조체 BITMAPINFOHEADER 가 있기 때문입니다.

장치 독립적인 비트맵을 출력하기 위해서는 BITMAPINFO에 정보를 설정하고 비트맵을 단지 비트정보만 가지고 있는 버퍼로 만들어서 이 두 개를 가지고 출력하면 됩니다.

<5>BITMAPINFO 정보 만들기

HBITMAP 핸들은 보통 자원에서 비트맵을 얻을 때 사용하는 핸들입니다. 이핸들을 이용하여 다음과 같이하여 비트맵을 얻는 것은 이미 설명하였습니다.

hBitmap=LoadBitmap(hInst,"BITMAP");

리소스에 BITMAP로 등록된 비트맵을 hBitmap에 로드한 형태입니다. 이 비트맵에서 비트맵 정보만 얻고자 할 경우 GetDIBits를 사용합니다.

int GetDIBits(

HDC hdc, // 디바이스 컨텍스트 핸들

HBITMAP hbmp, // 비트맵 핸들

UINT uStartScan, // 비트맵에서 얻고자 하는 첫 번째 줄

UINT cScanLines, // 비트맵에서 얻고자하는 라인수

LPVOID lpvBits, // 비트 정보만 저장하는 포인터

LPBITMAPINFO lpbi, // 비트맵 정보 핸들

UINT uUsage //팔레트수 정보

);

hbmp라는 비트맵 핸들과 BITMAPINFO를 넘겨주면 lpvBits에 장치 독립적인 비트맵에서 사용하는 비트맵 정보 형태로 값이 저장됩니다.

GetDIBits를 사용하기 위해서는 먼저 BITMAPINFO 형이 lpbi에 정보를 넣어서 구조체를 만들어야 합니다. 이구조체를 만드는 예는 다음과 같습니다.

hBitmap=LoadBitmap(((LPCREATESTRUCT)lParam)->hInstance,"BITMAP");

//가로 320 세로 320의 256칼라를 가진 비트맵 정보를 넣을수 있는

//메모리를 만든다.

szDib=GlobalAlloc(GHND,320*320);

//이메모리를 pDib에 락킹시킨다.

pDib=(LPSTR)GlobalLock(szDib);

//bitinfo에 설정할 메모리 핸들을 만든다.

szbitinfo=GlobalAlloc(GHND,sizeof(BITMAPINFOHEADER)+	256*sizeof(RGBQUAD)+sizeof(BITMAPINFO));

//메모리를 bitinfo에 락킹시킨다.

bitinfo=(LPBITMAPINFO)GlobalLock(szbitinfo);

//BITMAPINFO정보를 넣는다.

bitinfo->bmiHeader.biSize=sizeof(BITMAPINFOHEADER);

bitinfo->bmiHeader.biWidth=320;

bitinfo->bmiHeader.biHeight=320;

bitinfo->bmiHeader.biPlanes=1;

bitinfo->bmiHeader.biBitCount=8;

bitinfo->bmiHeader.biCompression=BI_RGB;

bitinfo->bmiHeader.biSizeImage=320*320;

bitinfo->bmiHeader.biXPelsPerMeter= 0;

bitinfo->bmiHeader.biYPelsPerMeter= 0;

bitinfo->bmiHeader.biClrUsed= 0;

bitinfo->bmiHeader.biClrImportant= 0;

//팔레트 값을 넣는다.

for(i=0;i<256;i++)

{

bitinfo->bmiColors[i].rgbRed=(BYTE)i;

bitinfo->bmiColors[i].rgbGreen=(BYTE)i;

bitinfo->bmiColors[i].rgbBlue=(BYTE)i;

}

//GetDIBbits를 사용하여 hBitmap에서 DIB를 만든다.

hdc=GetDC(hwnd);

GetDIBits(hdc,hBitmap,0,320,pDib,bitinfo,DIB_RGB_COLORS);

ReleaseDC(hwnd,hdc);

위의 예는 리소스 자원에설정된 가로 320 세로 320의 256 그레이 칼락값을 가진 비트맵을 DIB로 전환한것입니다. 위와 같이 전환하면 pDib에는 DIB정보가 설정됩니다.

<6>DIB 출력하기

DIB를 출력하고자 할경우에사용하는 대표적인 함수는 2개입니다.SetDIBitsToDevice 와 StretchDIBits입니다.

SetDIBitsToDevice는 비트맵 정보를 그대로 DC에 출력하는 것이고 StretchDIBBits는 비트맵 정보를 확대 또는 축소 하여 출력하는 것입니다.

이함수의 형태는 다음과 같습니다.

int SetDIBitsToDevice(

HDC hdc, // 출력할 DC핸들

int XDest, // 출력할 DC의 시작 x좌표

int YDest, // 출력할 DC의 시작 y좌표

DWORD dwWidth, // DIB의 가로크기

DWORD dwHeight, // DIB의 세로크기

int XSrc, // DIB의 출력 시작 x좌표

int YSrc, // DIB의 출력 시작 y좌표

UINT uStartScan, // 첫 번째 출력 라인

UINT cScanLines, // 총 출력라인수

CONST VOID *lpvBits, // DIB정보를 가지고 있는 버퍼

CONST BITMAPINFO *lpbmi, // BITMAPINFO정보 구조체

UINT fuColorUse // 팔레트 정보

);

XDest는 출력할 DC의 x출력 좌표를 의미하며 YDest는 출력할 DC의  y좌표를 의미합니다. 화면 윈도우에 출력한다고 가정했을 경우 값이 (0,0)일경우는 비트맵이 화면의 좌측 상단부터 출력이 됩니다.(MM_TEXT 모드에서)

dwWidth와 dwHeight는 영상의 가로와 세로의 크기이며 XSrc와 YSrc는 DC에 출력할 DIB의 위치를 의미합니다. 이위치가 (0,0) 일겅우에는 비트맵의 모든 정보가 출력이 되나 (0,10)이라고 한다면 비트맵의 상단 10라인은 출력이 되지 않습니다. 다음 uStartScan는 시작라인을 의미하며 cScnaLines는 총 출력라인수를 의미합니다. 예를 들어 320*320의 영상을 그대로 출력한다고 한다면 시작 라인은 0이되고 출력라인수는 320이 되는 것입니다. fuColorUse는  팔레트 정보로 DIB_PAL_COLORS 일경우에는 16비트 배열 조합의 칼라 테이블로써 로직 팔레트를 의미하며 DIB_RGB_COLORS 는 RGB값의 칼라를 의미합니다. 보통 DIB_RGB_COLORS를 많이 사용합니다.

nt StretchDIBits(

HDC hdc, // 출력 DC

int XDest, // 출력 DC의 시작점 X

int YDest, // 출력 DC의 시작점 Y

int nDestWidth, // 출력 DC에서 가로크기

int nDestHeight, // 출력 DC에서 세로크기

int XSrc, // DIB의 시작점 X

int YSrc, // DIB의 시작점 Y

int nSrcWidth, // DIB의 가로크기

int nSrcHeight, // DIB의 세로크기

CONST VOID *lpBits, // DIB 정보 버퍼

CONST BITMAPINFO *lpBitsInfo, // BITMAPINFO

UINT iUsage, // 팔레트 정보

DWORD dwRop // ROP 코드

);

StretchDIBits는 실제 크기가 nSrcWidth와 nSrcHeight인 DIB를 XDest와 YDest에 nDestWidth와 nDestHeight의 크기로 확대 또는 축소하여 출력하는 함수입니다.

dwRop는 ROP코드입니다. 이값들은 도움말을 참조하시기 바랍니다.

프린터로 출력할 경우 StretchDIBits를 많이 사용합니다. 이유는 화면에 보인것과 달리 프린터에 그림을 출력할 경우 매우 작게 나타나기 때문입니다. 예를 들어 320*320의 크기를 화면에 출력할 경우 보기 좋게 적당히 크게 나오나 프린터로 출력하면 매우 작은 형태로 출력됩니다. 이것을 적당히 변경을 하기 위해서는 StretchDIBits를 사용하게 됩니다. StretchDIBits를 이용하여 프린터에 한 장에전체로 그림을 출력하는 예가 다음과 같습니다.

//프린터 정보 DC를 얻고

iPrintInfo=CreateIC(NULL,printinfo->pPrinterName,NULL,NULL);

//가로와 세로의 픽셀수를 cy와 cx에 얻는다.

cy=GetDeviceCaps(iPrintInfo,VERTRES);

cx=GetDeviceCaps(iPrintInfo,HORZRES);

DeleteDC(iPrintInfo);

//출력 프린터 DC를 만들고

PrintDc=CreateDC(NULL,printinfo->pPrinterName,NULL,NULL);

//인쇄시작

if(StartDoc(PrintDc,&docinfo))

{

//페이지 시작

if(StartPage(PrintDc))

{

//그림을 용지 전에체 출력한다.

StretchDIBits(PrintDc,

0,0,cx,cy,0,0,320,320,pDib,bitinfo,DIB_RGB_COLORS,SRCCOPY);

//페이지 종료

EndPage(PrintDc);

}

//인쇄 종료

EndDoc(PrintDc);

}

DeleteDC(PrintDc);

<7>SDK 함수를 이용한 프린트 예제 SdkPrint

SdkPrint는 지금까지 설명한 SDK함수를 이용하여 프린팅을 하는 예제입니다.

이 예제의 전체 구성도는 그림 1-11-7과 같습니다.

(그림 파일)

(그림 1-11-7)SdkPrint 전체 구성도

그림 1-11-7의 ⓐ항목은 SdkPrint의 기본 형태입니다. 화면에는 자원에 등록된 bmp가 출력되고 이 bmp파일을 메뉴항목에서 □인쇄□ 를 클릭하면 프린터 용지에 출력을 합니다. 설정딘 bmp파일은 가로 640x480크기입니다. 이크기를 MM_TEXT모드로 출력을 하게 되면 프린터 용지 상단에 조그마하게 출력될것입니다. □전체용지□ 메뉴를 클릭하게 되면 ⓐ항목의 화면 그림이 전체 용지에 출력이 됩니다.

메뉴에서 프린터 설정항목을 클릭하면 ⓒ와 같은 대화상자가 출력되고 이대화상자에는 현재 컴퓨터에 연결된 프린터 리스트가 모두나타납니다. 또한 □프린터 속성□을 설정하면 현재 선택한 프린터를 Setup 하는 프린터 셋업 공용 대화상자가 출력되게 되는 것입니다. SdkPrint 예제는 본 항목에서 설명한 모든 내용을 그대로 적용한것입니다. 소스를 보시면서 제작방법을 이해하시기 바랍니다.

(1)CSdkPrintView 소스

(프로그램 소스시작)

// SdkPrintView.h : interface of the CSdkPrintView class

//

/////////////////////////////////////////////////////////////////////////////

#if !defined(AFX_SDKPRINTVIEW_H__037A8E2F_3A87_11D2_8B92_006097AD9DDC__INCLUDED_)

#define AFX_SDKPRINTVIEW_H__037A8E2F_3A87_11D2_8B92_006097AD9DDC__INCLUDED_

#include <winspool.h>

#if _MSC_VER > 1000

#pragma once

#endif // _MSC_VER > 1000

class CSdkPrintView : public CView

{

protected: // create from serialization only

CSdkPrintView();

DECLARE_DYNCREATE(CSdkPrintView)

// Attributes

public:

CSdkPrintDoc* GetDocument();

PRINTER_INFO_5 *printinfo;

DWORD  dwNeeded, dwReturned ;

HANDLE szInfo;

int iPrinterNumber;

HDC PrintDc;

HINSTANCE hInst;

HANDLE szDib;

LPSTR pDib;

LPBITMAPINFO bitinfo;

HANDLE szbitinfo;

HANDLE hPrint;

// Operations

public:

// Overrides

// ClassWizard generated virtual function overrides

//{{AFX_VIRTUAL(CSdkPrintView)

public:

virtual void OnDraw(CDC* pDC);  // overridden to draw this view

virtual BOOL PreCreateWindow(CREATESTRUCT& cs);

protected:

virtual BOOL OnPreparePrinting(CPrintInfo* pInfo);

virtual void OnBeginPrinting(CDC* pDC, CPrintInfo* pInfo);

virtual void OnEndPrinting(CDC* pDC, CPrintInfo* pInfo);

//}}AFX_VIRTUAL

// Implementation

public:

CBitmap m_pBitmap;

virtual ~CSdkPrintView();

#ifdef _DEBUG

virtual void AssertValid() const;

virtual void Dump(CDumpContext& dc) const;

#endif

protected:

// Generated message map functions

protected:

//{{AFX_MSG(CSdkPrintView)

afx_msg void OnPrintsetup();

afx_msg int OnCreate(LPCREATESTRUCT lpCreateStruct);

afx_msg void OnPrintattr();

afx_msg void OnPrint();

afx_msg void OnPrintfull();

//}}AFX_MSG

DECLARE_MESSAGE_MAP()

};

#ifndef _DEBUG  // debug version in SdkPrintView.cpp

inline CSdkPrintDoc* CSdkPrintView::GetDocument()

{ return (CSdkPrintDoc*)m_pDocument; }

#endif

/////////////////////////////////////////////////////////////////////////////

//{{AFX_INSERT_LOCATION}}

// Microsoft Visual C++ will insert additional declarations immediately before the previous line.

#endif // !defined(AFX_SDKPRINTVIEW_H__037A8E2F_3A87_11D2_8B92_006097AD9DDC__INCLUDED_)

// SdkPrintView.cpp : implementation of the CSdkPrintView class

//

#include "stdafx.h"

#include "SdkPrint.h"

#include "SdkPrintDoc.h"

#include "SdkPrintView.h"

#ifdef _DEBUG

#define new DEBUG_NEW

#undef THIS_FILE

static char THIS_FILE[] = __FILE__;

#endif

/////////////////////////////////////////////////////////////////////////////

// CSdkPrintView

IMPLEMENT_DYNCREATE(CSdkPrintView, CView)

BEGIN_MESSAGE_MAP(CSdkPrintView, CView)

//{{AFX_MSG_MAP(CSdkPrintView)

ON_COMMAND(ID_PRINTSETUP, OnPrintsetup)

ON_WM_CREATE()

ON_COMMAND(ID_PRINTATTR, OnPrintattr)

ON_COMMAND(ID_PRINT, OnPrint)

ON_COMMAND(ID_PRINTFULL, OnPrintfull)

//}}AFX_MSG_MAP

// Standard printing commands

ON_COMMAND(ID_FILE_PRINT, CView::OnFilePrint)

ON_COMMAND(ID_FILE_PRINT_DIRECT, CView::OnFilePrint)

ON_COMMAND(ID_FILE_PRINT_PREVIEW, CView::OnFilePrintPreview)

END_MESSAGE_MAP()

/////////////////////////////////////////////////////////////////////////////

// CSdkPrintView construction/destruction

CSdkPrintView::CSdkPrintView()

{

// TODO: add construction code here

}

CSdkPrintView::~CSdkPrintView()

{

}

BOOL CSdkPrintView::PreCreateWindow(CREATESTRUCT& cs)

{

// TODO: Modify the Window class or styles here by modifying

//  the CREATESTRUCT cs

return CView::PreCreateWindow(cs);

}

/////////////////////////////////////////////////////////////////////////////

// CSdkPrintView drawing

void CSdkPrintView::OnDraw(CDC* pDC)

{

CSdkPrintDoc* pDoc = GetDocument();

ASSERT_VALID(pDoc);

SetDIBitsToDevice(pDC->m_hDC,

0,0,640,480,0,0,0,480,pDib,bitinfo,DIB_RGB_COLORS);

}

/////////////////////////////////////////////////////////////////////////////

// CSdkPrintView printing

BOOL CSdkPrintView::OnPreparePrinting(CPrintInfo* pInfo)

{

// default preparation

return DoPreparePrinting(pInfo);

}

void CSdkPrintView::OnBeginPrinting(CDC* /*pDC*/, CPrintInfo* /*pInfo*/)

{

// TODO: add extra initialization before printing

}

void CSdkPrintView::OnEndPrinting(CDC* /*pDC*/, CPrintInfo* /*pInfo*/)

{

// TODO: add cleanup after printing

}

/////////////////////////////////////////////////////////////////////////////

// CSdkPrintView diagnostics

#ifdef _DEBUG

void CSdkPrintView::AssertValid() const

{

CView::AssertValid();

}

void CSdkPrintView::Dump(CDumpContext& dc) const

{

CView::Dump(dc);

}

CSdkPrintDoc* CSdkPrintView::GetDocument() // non-debug version is inline

{

ASSERT(m_pDocument->IsKindOf(RUNTIME_CLASS(CSdkPrintDoc)));

return (CSdkPrintDoc*)m_pDocument;

}

#endif //_DEBUG

/////////////////////////////////////////////////////////////////////////////

// CSdkPrintView message handlers

int CSdkPrintView::OnCreate(LPCREATESTRUCT lpCreateStruct)

{

if (CView::OnCreate(lpCreateStruct) == -1)

return -1;

EnumPrinters (PRINTER_ENUM_LOCAL,

NULL, 5, (LPBYTE) "", 0, &dwNeeded, &dwReturned) ;

szInfo=GlobalAlloc(GHND,dwNeeded);

printinfo=(LPPRINTER_INFO_5)GlobalLock(szInfo);

EnumPrinters (PRINTER_ENUM_LOCAL,

NULL, 5, (LPBYTE) printinfo, dwNeeded,

&dwNeeded, &dwReturned);

m_pBitmap.LoadBitmap(IDB_BITMAP1);

//가로 320 세로 320의 256칼라를 가진 비트맵 정보를 넣을수 있는

//메모리를 만든다.

szDib=GlobalAlloc(GHND,640*480*3);

//이메모리를 pDib에 락킹시킨다.

pDib=(LPSTR)GlobalLock(szDib);

//bitinfo에 설정할 메모리 핸들을 만든다.

szbitinfo=GlobalAlloc(GHND,sizeof(BITMAPINFOHEADER)+ sizeof(BITMAPINFO));

//메모리를 bitinfo에 락킹시킨다.

bitinfo=(LPBITMAPINFO)GlobalLock(szbitinfo);

//BITMAPINFO정보를 넣는다.

bitinfo->bmiHeader.biSize=sizeof(BITMAPINFOHEADER);

bitinfo->bmiHeader.biWidth=640;

bitinfo->bmiHeader.biHeight=480;

bitinfo->bmiHeader.biPlanes=1;

bitinfo->bmiHeader.biBitCount=24;

bitinfo->bmiHeader.biCompression=BI_RGB;

bitinfo->bmiHeader.biSizeImage=640*480*3;

bitinfo->bmiHeader.biXPelsPerMeter= 0;

bitinfo->bmiHeader.biYPelsPerMeter= 0;

bitinfo->bmiHeader.biClrUsed= 0;

bitinfo->bmiHeader.biClrImportant= 0;

iPrinterNumber=0;

HDC hdc;

//GetDIBbits를 사용하여 hBitmap에서 DIB를 만든다.

hdc=::GetDC(this->m_hWnd);

GetDIBits(hdc,(HBITMAP)m_pBitmap,0,480,pDib,bitinfo,DIB_RGB_COLORS);

::ReleaseDC(this->m_hWnd,hdc);

return 0;

}

#include "PrintSetDlg.h"

void CSdkPrintView::OnPrintsetup()

{

//현재 컴퓨터에 연결된 프린터 리스트 를 출력하는 대화상자

CPrintSetDlg *pDlg=new CPrintSetDlg;

pDlg->DoModal();

delete pDlg;

DeleteDC(PrintDc);

PrintDc=CreateIC(NULL,

(printinfo+iPrinterNumber)->pPrinterName,NULL,NULL);

Invalidate(FALSE);

}

void CSdkPrintView::OnPrintattr()

{

//프린터 설정 공요 대화상자 실행

if (OpenPrinter((printinfo+iPrinterNumber)->pPrinterName, &hPrint, NULL))

{

//선택된 항목으로 프린터를 설정한다.

PrinterProperties (this->m_hWnd, hPrint) ;

ClosePrinter (hPrint) ;

}

}

//"인쇄" 항목 선택시

void CSdkPrintView::OnPrint()

{

//프린터에 현재 그림을 프린팅한다.

static DOCINFO docinfo={sizeof(DOCINFO),"Print Exam",NULL};

//프린터 DC를 만든다.

PrintDc=CreateDC(NULL,(printinfo+iPrinterNumber)->pPrinterName,NULL,NULL);

//인쇄 시작

if(StartDoc(PrintDc,&docinfo))

{

//페이지 시작

if(StartPage(PrintDc))

{

//DIB 이미지 프린터로 출력

SetDIBitsToDevice(PrintDc,

0,0,640,480,0,0,0,480,pDib,bitinfo,DIB_RGB_COLORS);

//페이지 끝

EndPage(PrintDc);

}

//인쇄 끝

EndDoc(PrintDc);

}

DeleteDC(PrintDc);

}

//용지 전체에 출력

void CSdkPrintView::OnPrintfull()

{

static DOCINFO docinfo={sizeof(DOCINFO),"Print Exam",NULL};

HDC iPrintInfo;

int cx,cy;

//프린터 정보 DC를 얻고

iPrintInfo=CreateIC(NULL,(printinfo+iPrinterNumber)->pPrinterName,NULL,NULL);

//가로와 세로의 픽셀수를 cy와 cx에 얻는다.

cy=GetDeviceCaps(iPrintInfo,VERTRES);

cx=GetDeviceCaps(iPrintInfo,HORZRES);

DeleteDC(iPrintInfo);

//출력 프린터 DC를 만들고

PrintDc=CreateDC(NULL,(printinfo+iPrinterNumber)->pPrinterName,NULL,NULL);

//인쇄시작

if(StartDoc(PrintDc,&docinfo))

{

//페이지 시작

if(StartPage(PrintDc))

{

//그림을 용지 전에체 출력한다.

StretchDIBits(PrintDc,

0,0,cx,cy,0,0,640,480,pDib,bitinfo,DIB_RGB_COLORS,SRCCOPY);

//페이지 종료

EndPage(PrintDc);

}

//인쇄 종료

EndDoc(PrintDc);

}

DeleteDC(PrintDc);

}

(프로그램 소스끝)

(2)CPrintSetDlg 소스

// PrintSetDlg.cpp : implementation file

//

#include "stdafx.h"

#include "SdkPrint.h"

#include "PrintSetDlg.h"

#include "MainFrm.h"

#include "SdkPrintDoc.h"

#include "SdkPrintView.h"

#ifdef _DEBUG

#define new DEBUG_NEW

#undef THIS_FILE

static char THIS_FILE[] = __FILE__;

#endif

/////////////////////////////////////////////////////////////////////////////

// CPrintSetDlg dialog

CPrintSetDlg::CPrintSetDlg(CWnd* pParent /*=NULL*/)

: CDialog(CPrintSetDlg::IDD, pParent)

{

//{{AFX_DATA_INIT(CPrintSetDlg)

// NOTE: the ClassWizard will add member initialization here

//}}AFX_DATA_INIT

}

void CPrintSetDlg::DoDataExchange(CDataExchange* pDX)

{

CDialog::DoDataExchange(pDX);

//{{AFX_DATA_MAP(CPrintSetDlg)

DDX_Control(pDX, IDC_LIST1, m_listBox);

//}}AFX_DATA_MAP

}

BEGIN_MESSAGE_MAP(CPrintSetDlg, CDialog)

//{{AFX_MSG_MAP(CPrintSetDlg)

//}}AFX_MSG_MAP

END_MESSAGE_MAP()

/////////////////////////////////////////////////////////////////////////////

// CPrintSetDlg message handlers

BOOL CPrintSetDlg::OnInitDialog()

{

CDialog::OnInitDialog();

CMainFrame *pFrame=(CMainFrame *)AfxGetMainWnd();

CSdkPrintView *pView=(CSdkPrintView *)pFrame->GetActiveView();

char temp[160];

//프린터 리스트를 리스트박스에 설정한다.

for(int i=0;i<(int)pView->dwReturned;i++)

{

wsprintf(temp,"%s",(pView->printinfo+i)->pPrinterName);

m_listBox.AddString(temp);

}

return TRUE;  // return TRUE unless you set the focus to a control

// EXCEPTION: OCX Property Pages should return FALSE

}

void CPrintSetDlg::OnOK()

{

int num;

num=m_listBox.GetCurSel();

if(num<0)

{

CDialog::OnOK();

return;

}

CMainFrame *pFrame=(CMainFrame *)AfxGetMainWnd();

CSdkPrintView *pView=(CSdkPrintView *)pFrame->GetActiveView();

pView->iPrinterNumber=num;

CDialog::OnOK();

}

(낙서)

최신 컴퓨터 용어 사전

486 .... PC를 이해하는데 필요한 평균 IQ.

최신기종 .... 당신이 살 수 없는 컴퓨터.

구형 .... 당신의 컴퓨터.

마이크로초(천분의 일초) .... 새로산 최신 기종 컴이 구형이 되는데 걸리는 시간.

컴퓨터 칩 .... 프로그래밍하면서 무지하게 먹어대는, 전분으로된과자의 일종.

노트북 컴퓨터 .... 회사원들로 하여금 집에서나, 휴가때나, 출장중에도 일하도록 고	안된 도구.

디스크 오류 .... 일의 마감시간이 닥쳐오면 일어나는 컴퓨터의 전형적인 반응.

파워 유저 .... 도스에서 디스크를 포맷할 수 있는 사람.

시스템 업데이트 .... 현재의 소프트웨어를 모두 버리는 가장 빠른 방법.

(낙서 끝)