닷넷에서 텍스트를 프린터로 출력하기
닷 넷 프레임워크에서는 텍스트를 그대로 프린터에 출력하는 기능(Raw 데이터 출력이라고 함)을 지원하지 않습니다. GDI+에서 DrawText()등의 메서드를 이용하여 출력할 수는 있지만, 때때로 텍스트만을 출력해야 하거나, 특수한 프린터(감열 영수증 프린터 등)를 사용할 때에는 Raw 데이터 출력이 필요할 때가 있습니다. 그런 기능을 하는 클래스를 하나 만들어 보았습니다.
안녕하세요 : )
닷넷 프레임워크에서 아무리 찾아봐도 Raw 프린트 기능을 지원하는 클래스가 없길래, WinAPI를 사용해서 하나 만들어 보았습니다.
그럼 시작합니다 : )
전체 소스 코드
|
|
|
|
using System; namespace System.IO [DllImport("winspool.drv")] [DllImport("winspool.drv")] [DllImport("winspool.drv")] [DllImport("winspool.drv")] public static void PrintText(string strPrintText) OpenPrinter(printername, ref handle, null); ClosePrinter(handle); public struct DOC_INFO_1 |
|
|
|
|
핸들을 마샬링하기
이 클래스는 WinAPI를 사용하고 있다. (WinAPI를 가져오는 방법에 대해서는 예전에 소개했던, C#에서 Native DLL(WinAPI) 사용하기를 참고) 예전 내용과 다른 점이라면, 파라메터에 LPHANDLE 타입의 변수가 있다는 점이다. 예를 들어 OpenPrinter() WinAPI 함수의 원형은 다음과 같다 :
BOOL OpenPrinter(
LPTSTR pPrinterName, // printer or server name
LPHANDLE phPrinter, // printer or server handle
LPPRINTER_DEFAULTS pDefault // printer defaults
);
LPHANDLE 은 HANDLE에 대한 포인터 타입이지만, 닷넷에서는 변수에 대한 포인터이든 변수이든 알아서 마샬링을 해 준다. 대신에, 그 타입에 적절한 마샬링 방법을 정해 주거나, 적절한 타입의 변수를 대응시켜주어야 한다. MSDN에 나와있는 Platform Invoke Data Types는 다음과 같다 :
Unmanaged type in Wtypes.h |
Unmanaged C language type |
Managed class name |
Description |
HANDLE |
void* |
System.IntPtr |
32 bits |
BYTE |
unsigned char |
System.Byte |
8 bits |
SHORT |
short |
System.Int16 |
16 bits |
WORD |
unsigned short |
System.UInt16 |
16 bits |
INT |
int |
System.Int32 |
32 bits |
UINT |
unsigned int |
System.UInt32 |
32 bits |
LONG |
long |
System.Int32 |
32 bits |
BOOL |
long |
System.Int32 |
32 bits |
DWORD |
unsigned long |
System.UInt32 |
32 bits |
ULONG |
unsigned long |
System.UInt32 |
32 bits |
CHAR |
char |
System.Char |
Decorate with ANSI. |
LPSTR |
char* |
System.String or System.StringBuilder |
Decorate with ANSI. |
LPCSTR |
Const char* |
System.String or System.StringBuilder |
Decorate with ANSI. |
LPWSTR |
wchar_t* |
System.String or System.StringBuilder |
Decorate with Unicode. |
LPCWSTR |
Const wchar_t* |
System.String or System.StringBuilder |
Decorate with Unicode. |
FLOAT |
Float |
System.Single |
32 bits |
DOUBLE |
Double |
System.Double |
64 bits |
(자세한 내용은 MSDN Library에서 Platform Invoke, Data Types 항목을 참고하기 바란다)
위 표에서 보면 HANDLE에 대응되는 타입으로 System.IntPtr을 제시하고 있다. OpenPrinter() WinAPI에서 사용되는 LPHANDLE은 HANDLE에 대한 포인터이지만, 포인터인 것과는 상관없이 마샬링이 가능하므로, System.IntPtr 타입으로 파라메터를 선언해서 함수를 호출할 수 있게 된다.
구조체와 관련된 부분은 코드를 보면 이해할 수 있을 것이다.
WinAPI 함수와 호환을 위한 문자열 관련 코드
그리고 또 짚고 넘어갈 부분으로 다음 코드가 있다 :
int dwBytesOfText = System.Text.Encoding.GetEncoding("euc-kr").GetByteCount(strPrintText);
위 코드는 프린트될 문자열의 바이트 길이를 구하는 코드이다. WritePrinter() WinAPI 함수가 프린트될 문자열의 길이를 요구하기 때문에 필요한 것인데, 위와 같이 GetEncoding() 메서드로 euc-kr에 대한 인코더를 구해서 직접 바이트 수를 구하는 이유는, 이렇게 하지 않으면 한글 문자에 대한 바이트 수가 제대로 전달되지 않기 때문이다. WinAPI 기반 함수에서는 한글로 된 한 글자가 2바이트를 차지하기 때문에, 그냥 string에서 Length 속성을 가져다가 dwBytesOfText 값으로 넘겨주면 한글도 한 바이트로 처리되므로 나중에 출력이 올바로 되지 않을 수 있다.
예를 들자면, "abcd"같은 경우 문자열의 길이로 4가 나와야 하지만, "가나다라"의 경우엔 8이 리턴되어야 출력될 문자열의 바이트 수가 맞기 때문에 (물론 euc-kr 인코딩 기준에서) 올바른 출력이 가능해진다.
정리
프 린터 클래스 하나를 만드는데 pinvoke에 문자열 인코딩까지 나와버렸습니다. WinAPI에 접근하는 것은 역시 그렇게 녹록하지는 않네요. pinvoke에 관련해서 HANDLE 까지 나오긴 했습니다만, 이것 말고도 배열에 관련된 내용이라든가, COM 객체를 호출할 때 VARIANT 타입을 주고받는 내용 등 몇 가지가 더 있습니다. 필수적인 것은 아니지만, 익혀두시면 도움이 될 내용이므로 미리 봐 두시는 것도 좋을 것 같습니다.
( 아니면 Kenial이 계속 아티클을 올릴 때까지 기다리시는 것도..^^; )
그럼 : )
'TechLog' 카테고리의 다른 글
닷넷에서 디버그 출력을 파일로 저장하기 (0) | 2008.11.12 |
---|---|
웹 서비스 팁 ; 세션 사용하기, 함수의 설명 제공하기 (0) | 2008.11.04 |
닷넷 프레임워크의 스트림 이해하기 (0) | 2008.10.31 |
윈도우 서버 제품군(2003, 2008 등)에 msn 메신저 설치 (0) | 2008.10.25 |
Flash & Asp.net - 4 ; Asp.net & Flash & Web Service! (0) | 2008.10.24 |