2015년 3월 7일 토요일

PRINTING ARCHITECTURE


지금 내가 맡고 있는 제품은 프린트 보안...
수 많은 보안 영역 중에 프린트 보안은 인기도 없고 관심도 없다.
그렇다고 기술적으로 배울게 없는 것은 아니다.
프린트 보안 S/W의 요구사항은 대체적으로 아래와 같을 것이다.
      
      1. 인쇄물에 회사 로고를 넣어줘 
            => 워터마크
      2. 누가 언제 무엇을 인쇄 했는지 관리자가 알 수 있게 해줘
            => 인쇄 로깅
요구사항은 단순 하지만 기능을 구현하려면 알아야 할 것들이
한 두 가지가 아니다. 그 중 첫 번째로 알아야 할 것은 인쇄 프로세스가 되겠다.
오늘은 인쇄 프로세스에 대해 공부해 보자.




이 주제에 대해 구글링을 조금 해보신 분들이라면 알겠지만 제대로된 자료가 많이 없다.
그래서 책을 찾아 봤는데... 인쇄에 대해 깊이 있게 설명하고 있는 책은 많지 않다... 

하지만! GDI로 가장 유명한 책인 Windows Graphics Programming Win32 GDI and DirectDraw을 선택하고, 2.4 Printing Architecture 챕터를 공부해 보기로 한다. 


책을 처음 보기 때문에... 아래 글 수준은 책을 번역하는 정도가 될 것 같다. 








2.4 PRINTING ARCHITECTURE

Win32 GDI API는 어느 DC에나 그리기를 할 수 있다. 라인을 그리거나, 커브, 비트맵,
텍스트 등등. 하지만 프린터는 특별한 취급이 필요한 그래픽 장치이다.
아래는 프린터가 다른 그래픽 장치와 다른 몇 가지 이유이다.
  • 사용자는 한번에 한 페이지 만을 인쇄하지 않는다.
    전체 문서를 인쇄거나, 인쇄 품질을 변경한다던지, 용지 크기,
    양면, 한 면에 여러 페이지 인쇄(N-UP), 여러 매 수 인쇄 등등..
    GDI는 문서의 한 페이지 영역을 조정하기 위해 프린터에 특화된
    API를 제공하고, 전체 인쇄 설정을 DEVMODE 구조체로 제공한다.
  • 프린터(300~2400 dpi)는 모니터(75~120 dpi)보다 더 큰 해상도를 사용한다.
    이 말은 더 많은 데이터가 처리되어야 하고, 페이지를 한번에 렌더링 하기
    위한 메모리가 충분하지 않다는 것이다. GDI 엔진은 EMF 스풀링을 통하여
    프린터 드라이버가 한번에 작은 데이터(small band)를 받을 수 있도록 허용한다.
  • 프린터는 보통 느리고 여러 사람과 공유된다.
    또한 PC에 바로 연결되지 않을 수 있다. Windows OS는 수준 높은 spooler를
    제공하는데, spooler는 애플리케이션이 공유된 인쇄를 가능한 빨리 마칠
    수 있도록 보장하고, 여러 job들이 하나의 프린터를 공유할 수 있고,
    여러 사람들이 프린터를네트워크로 공유할 수 있다.
  • 프린터는 다른 언어로 말한다.
    HP 프린터의 PCL, 엡손 프린터의 ESC/P, PostScript 프린터를 위한 Postscript
    플로터를 위한 HPGL. 바로 이 점이 모두 래스터 기반인 디스플레이 카드와
    완벽히 다른 점이다. Microsoft는 하드웨어 제작사들에게 그들의 H/W 요구
    사항을 커스터마이징 할 수 있는 "범용적인" 드라이버를 몇 가지 제공한다.  
Windows NT/2000의 인쇄 아키텍쳐의 중심은 print spooler와 프린터 드라이버다.
애플리케이션은 gdi dll에 노출되어 있는 API를 호출함으로써 프린트잡을 시작
한다. 그러면 GDI와 spooler 그리고 프린터 드라이버는 프린트잡을 핸들링하고
레이저 프린터나 잉크젯 프린터, 플로터, 팩스 등의 다양한 실제 기기에 데이터를
보내게 된다.
'그리기 명령'은 GDI API 호출을 통해 GDI가 받는다. 이것은 보통 enhanced metafile
(EMF)로 저장되어 있다. EMF 파일과 현재 인쇄 설정이 저장된 또 다른 파일이 
스풀러 시스템 서비스 프로세스(spools.exe)에 의해 보내진다.
이 시점에 애플리케이션은 문서의 인쇄가 완료된다. Spooler가 실제로 문서를 인쇄할
동안 사용자는 애플리케이션에서 다른 작업을 자유롭게 할 수 있다.
(** 이 두 개의 파일은 .SPL과 .SHD 파일이다. .SPL파일에는 실제 기기로 보내는 
인쇄 데이터이고, .SHD파일은 인쇄 설정이 저장되어 있다.)

첫번째로, spooler는 프린트잡을 printer provider에게 보낼 경로가 필요하다.
printer provider는 실제 프린터를 핸들링한다. 이 프린터가 local printer provider
(localspl.dll)에 의해 핸들링되는 로컬 프린터일 수도 있고, 
Windows network printer provider(win32spl.dll)에 의해 핸들링되는 윈도우즈 네트워크
프린터일 수도 있다. 만약 원격 장치라면 OS 네트워크 서비스가 스풀 파일을 원격
장치에 전송한다. 그 후 로컬 머신처럼 프린트잡이 spooler에게 들어간다.



마지막으로, local print provider는 print processor가 보낸 프린트잡을 얻는다.
Print processor는 스풀 파일의 포맷을 검사(check)한다. EMF 파일인 경우 각 
페이지를 GDI로  play back 한다. Play back 이라는 것은 GDI 명령들을 DDI
(device driver interface)에 의해 정의된 '그리기 요소(점,선,면)'로 변환하고,
이 '그리기 요소'를 프린터 드라이버에 보내는 것이다. 프린터 드라이버는 '그리기 
요소'를 프린터 언어로 쓰여진 raw data로 렌더링 하는데, 그 언어는 PCL, ESC/P,
Postscript 등이 될 수 있다. Raw data는 스풀러의 print processor가 다시 보낸다.

Print processor가 raw data를 보게되면 프린터로 전송될 준비가 된 것이고,
이때 print processor는 raw data를 language monitor로 보낸다. Language 
monitor는 data를 port monitor에 보낸다. Port monitor는 data를 H/W 포트에
writing 하기 위해 OS file system API를 사용한다. 이후 모든 프린터 관련 펌웨어는
우리가 신경쓰지 않아도 되는데, 문서의 인쇄가 위에 설명한 소프트웨어 컴포넌트의 긴
체인을 거친 후 완벽히 완료된다는 것만 신경쓰면 된다.

자 그럼, Windows NT/2000에서의 인쇄 시스템 컴포넌트들을 좀더 자세하게
살펴보자.

The Win32 Spooler Client DLL

Win32 spooler client DLL (winspool.drv)은 유저 애플리케이션에게 spooler API를
노출한다. 유저 애플리케이션은 아래와 같을 때 spooler API를 사용한다.

    - 프린터에게 쿼리
    - 잡(job)을 인쇄하기 
    - 프린터 설정 변경
    - 프린터 설정을 쿼리
    - 프린터의 특별한 설정 속성 화면을 보여주기 위한 '프린터 드라이버 유저
      인터페이스 DLL'을 로드하거나
    - 그외 등등

예를 들면, spooler API들 중 OpenPrinter, WritePrinter, ClosePrinter를 사용할
수 있는데, 이 API는 일반적인 GDI 그리기 작업과 프린터 드라이버의 렌더링 작업
없이 raw data를 프린터로 보내기 위한 용도이다.

Spooler API는 winspool.h 헤더 파일과 winspool.lib 라이브러리 파일에 정의되어 있다.
그러므로 winspool.drv는 인쇄가 필요할 때 애플리케이션 프로세스에 로드된다. Spooler
client DLL은 인쇄잡이 어떻게 처리되어야 하는지 결정하기 위해 GDI를 돕는다.
일반적인 job은, GDI가 EMF 파일을 생성하고 그것을 spooler client에게 보낸다. 
spooler client는 spooler system service process에 job을 보내기 위해 RPC(Remote
procedure call)를 사용한다.

Spooler System Service Process

Windows NT/2000 spooler는 시스템 서비스로 구현되어 있다. 시스템 서비스 프로세스는
특별한 권한을 가지며 시스템에 책임이 있다. 이 spooler service는 OS가 시작될 때 시작된다.
이 때문에 재부팅이 되면 미완료 인쇄 job들이 자동으로 인쇄될 때가 있는 것이다.

net stop spooler는 스풀 프로세스를 중지시키고, net start spooler는 스풀 프로세스를
재개시킨다. spooler가 중지되면 컨트롤 패널(인쇄 작업 목록)에 중지된 작업을 볼 수 있다.

Spooler service는 RPC 인터페이스를 spooler client DLL에 export한다.
이로써 유저 애플리케이션이 프린터 및 프린터 드라이버, 인쇄 job을  관리할 수 있다.
Spooler service의 실체는 작은 EXE 파일(spoolsv.exe)이다. Spooler service는 자신이 
호출 받은 대부분을 spooler router를 통해 printer provider에게 전달한다.
Spooler service는 대체될 수 없는 시스템 컴포넌트다. 

Spooler Router

당신이 인쇄하고 있는 프린터는 아마도 로컬 프린터이거나 Microsoft network 어딘가에 있거나,
Novell server로 붙어 있거나 wide world 어딘가에 있거나, URL 주소만 가지고 있을 것이다.
Spooler system service는 인쇄 job을 printer provider에게 건내주기 위해 spooler router
DLL (spool ss.dll)을 사용한다. Printer provider는 인쇄 job을 어디로 보내야 하는지 알고 있다.

Spoolss.dll은 winspool.drv와 유사하게 노출 함수를 제공한다. 
AddPrinter, OpenPrinter, EnumJobW 등이 있다. 동일한 호출 명령이 이 모듈에서
저 모듈로, 또 그 다음 모듈로... 최종 목적지에 전달되기 위한 작업은 printer spooler 입장에서 
일반적인 것이다.

Router가 하는 일은 간단하다. 옳바른 printer provider를 찾고, 정보를 전달한다. 
이 작업은 프린터 이름 또는 프린터 핸들 정보를 통해 이루어 진다. 프린터 핸들은 시스템 레지스트리
에 있는 많은 프린터 관련 설정의 인쇄 job으로 부터 온다.

유저 애플리케이션이 OpenPrinter를 spooler client DLL(winspool.drv)에 호출하면 
그 호출은 spooler system service (spoolsv.exe)에 전달한다. Spoolsv.exe는 
spooler router를 호출하는데... spooler router는 각각의 printer
provider의 OpenPrinter를 핸들이 리턴될 때 까지 호출한다.
OpenPrinter API는 프린터 이름으로 호출하며 프린터 핸들을 리턴한다. 
이 핸들은 애플리케이션에 리턴되고 그 이후의 호출은 일치하는 printer provider에서 
다이렉트로 (핸들이)전달된다.

Spooler router는 대체될 수 없는 시스템 DLL이다.

Print Provider

Print Provider는 다이렉트 인쇄 job에 책임이 있다. (로컬 머신과 원격 머신 모두에서)
또한 시작, 중지 그리고 job 열거(enumeration)와 같은 print-job 큐의 운영을 관리한다. 
spooler service process와 spooler router 와는 다르게 시스템에 여러개의 print
provider가 있을 수 있다. H/W 제작사는 심지어 그들만의 printer provider를 Windows 
NT/2000 DDK를 이용해 만들 수 있다. 

아래와 같이 OS는 몇 가지의 print provider를 제공한다.
  • Local Print Provider (localspl.dll)

  • Windows Network Print Provider (win32spl.dll)

  • Novel Netware Print Provider (nwprovau.dll)

  • HTTP Print Provider (inetpp.dll)


댓글 1개:

  1. 저랑 똑같은 업무를 맡으셨네요.. 구현 하셨나요?

    답글삭제