中国石凳联盟 登录注册

【原创】【类】行打印的实现

rockage··14 回复·892 浏览

发表回复

用过Windows的人都知道,几乎所有软件,Word也好,Excel也好,AutoCAD也好,在打印的时候,一旦按下【打印】按钮,打印机就会开始动作,然后整页纸会被送入打印机,哪怕这张纸上仅有一个字也是如此。这就是所谓的“按页”打印,。嗯,是的,这在一般情况下似乎也没有什么问题。但是,有的场合就不行了,比如票据打印,还有打印一些流水帐之类的东西,总不至于打一份记录就用一整页纸这么夸张吧,所以我们必须找到一个“按行”打印的方法,当打印机打完一行后,并不执行出纸动作,而是停留在下一行的位置待命。因此我编写了这个类,以方便需要用到“按行”打印的人士使用。

------------------------------------------------------

简单讲一下原理,我们都知道Windows程序在打印的时候都有一个“打印到文件”的功能,这个功能可以讲打印的内容存为一种后缀为.PRN的文件,很多工具都能浏览这种文件,比如Adobe的PageMaker。

当我们生成了.PRN文件(而不是实质打印后),就能对文件本身进行修改,根据我的实验,发现该文件最后三个字节为“出纸”命令。Windows打印每次都换页的秘密就在于此,简单的,我们只需要将这三个字节删除,打印机就不会执行“出纸”命令了。

接着,我们将处理后的.PRN(最后三个字节被删除)文件用常规的方法再实质性(也就是启动打印机)打印一遍,打印机因为收不到“出纸”指令,所以它打完一行之后如果没有新的内容,它就会卡在原处不动,除非有新的内容需要它再次启动。

至此,完成“按行”打印的目的。

------------------------------------------------------

说明:
1. 本程序只使用于针式打印机
2. 本程序所使用的长度单位为“像素”

------------------------------------------------------


首先按常规方法添加向工程里添加一个类,取名为clsLBLPrn,并将以下内容复制进去:

*************************************************************
LBL (Line By Line) Print class
2004.06.01 Written By Rockage(Yang Hua)

http://www.rockags.com

http://www.stoneren.com

email:
rockages@gmail.com

*************************************************************
Author grants royalty-free rights to use this code.
*************************************************************
Option Explicit

Private Type DOCINFO
cbSize As Long
lpszDocName As String
lpszOutput As String
lpszDatatype As String
fwType As Long
End Type

Private Type DOC_INFO_1
pDocName As String
pOutputFile As String
pDatatype As String
End Type

Private Type POINT_TYPE
x As Long
y As Long
End Type

Private Type LOGFONT
lfHeight As Long
lfWidth As Long
lfEscapement As Long
lfOrientation As Long
lfWeight As Long
lfItalic As Byte
lfUnderline As Byte
lfStrikeOut As Byte
lfCharSet As Byte
lfOutPrecision As Byte
lfClipPrecision As Byte
lfQuality As Byte
lfPitchAndFamily As Byte
lfFaceName As String * 32
End Type

Drawing API:
Private Declare Function CreateFontIndirect Lib "gdi32.dll" Alias "CreateFontIndirectA" (lplf As LOGFONT) As Long
Private Declare Function SelectObject Lib "gdi32.dll" (ByVal hdc As Long, ByVal hObject As Long) As Long
Private Declare Function TextOut Lib "gdi32" Alias "TextOutA" (ByVal hdc As Long, ByVal x As Long, ByVal y As Long, ByVal lpString As String, ByVal nCount As Long) As Long
Private Declare Function DeleteObject Lib "gdi32.dll" (ByVal hObject As Long) As Long
Private Declare Function CreatePen Lib "gdi32.dll" (ByVal fnPenStyle As Long, ByVal nWidth As Long, ByVal crColor As Long) As Long
Private Declare Function MoveToEx Lib "gdi32.dll" (ByVal hdc As Long, ByVal x As Long, ByVal y As Long, lpPoint As POINT_TYPE) As Long
Private Declare Function LineTo Lib "gdi32.dll" (ByVal hdc As Long, ByVal x As Long, ByVal y As Long) As Long

Printer API:
Private Declare Function DeleteDC Lib "gdi32.dll" (ByVal hdc As Long) As Long
Private Declare Function CreateDC Lib "gdi32.dll" Alias "CreateDCA" (ByVal lpszDriver As String, ByVal lpszDevice As String, ByVal lpszOutput As Long, lpInitData As Any) As Long
Private Declare Function StartPage Lib "gdi32.dll" (ByVal hdc As Long) As Long
Private Declare Function StartDoc Lib "gdi32.dll" Alias "StartDocA" (ByVal hdc As Long, lpdi As DOCINFO) As Long
Private Declare Function EndPage Lib "gdi32.dll" (ByVal hdc As Long) As Long
Private Declare Function EndDoc Lib "gdi32.dll" (ByVal hdc As Long) As Long
Private Declare Function GetProfileString Lib "kernel32" Alias "GetProfileStringA" (ByVal lpAppName As String, ByVal lpKeyName As Any, ByVal lpDefault As String, ByVal lpReturnedString As String, ByVal nSize As Long) As Long
Private Declare Function OpenPrinter Lib "winspool.drv" Alias "OpenPrinterA" (ByVal pPrinterName As String, phPrn As Long, pDefault As Any) As Long
Private Declare Function StartDocPrinter Lib "winspool.drv" Alias "StartDocPrinterA" (ByVal hPrn As Long, ByVal Level As Long, pDocInfo As DOC_INFO_1) As Long
Private Declare Function StartPagePrinter Lib "winspool.drv" (ByVal hPrn As Long) As Long
Private Declare Function WritePrinter Lib "winspool.drv" (ByVal hPrn As Long, pBuf As Any, ByVal cdBuf As Long, pcWritten As Long) As Long
Private Declare Function EndPagePrinter Lib "winspool.drv" (ByVal hPrn As Long) As Long
Private Declare Function EndDocPrinter Lib "winspool.drv" (ByVal hPrn As Long) As Long
Private Declare Function ClosePrinter Lib "winspool.drv" (ByVal hPrn As Long) As Long

Private lf As LOGFONT, itsCurrentX As Long, itsCurrentY As Long
Private pt As POINT_TYPE
Private ret As Long
Private hPrintDC As Long
Private di As DOCINFO
Private prnName As String, strDOC As Boolean

Public Property Let CurrentY(ByVal vNewValue As Long)
itsCurrentY = vNewValue
End Property

Public Property Let CurrentX(ByVal vNewValue As Long)
itsCurrentX = vNewValue
End Property

Public Property Let FontSize(ByVal vNewValue As Long)
lf.lfHeight = vNewValue
End Property

Public Sub PrintLine(ByVal X1 As Long, ByVal Y1 As Long, ByVal X2 As Long, ByVal Y2 As Long)
MoveToEx hPrintDC, X1, Y1, pt
LineTo hPrintDC, X2, Y2
End Sub

Public Sub PrintText(ByVal strText As String)
Dim hFont As Long, hOldFont As Long

hFont = CreateFontIndirect(lf)
hOldFont = SelectObject(hPrintDC, hFont)
ret = TextOut(hPrintDC, itsCurrentX, itsCurrentY, strText, LenB(StrConv(strText, vbFromUnicode)))
ret = SelectObject(hPrintDC, hOldFont)
ret = DeleteObject(hFont)


End Sub

Public Sub EndDocs()

If strDOC Then

ret = EndPage(hPrintDC) 结束虚拟打印,temp.prn过渡文件生成完毕
ret = EndDoc(hPrintDC)

--------------------------------------------
进入实质打印:

Dim hPrn As Long
Dim Written As Long
Dim I As Long
Dim hFile As Integer
Dim sFile As String
Dim Buffer() As Byte, lstByte As Long
Dim di2 As DOC_INFO_1

hFile = FreeFile
sFile = App.Path "" "temp.prn" 装载过渡文件

di2.pDocName = sFile
di2.pOutputFile = vbNullString
di2.pDatatype = "RAW"

Call OpenPrinter(prnName, hPrn, ByVal 0)
Call StartDocPrinter(hPrn, 1, di2) 打开一个直传模式的打印Job
Call StartPagePrinter(hPrn)

hFile = FreeFile


Open sFile For Binary Access Read As hFile

If LOF(hFile) 0 Then

ReDim Buffer(1 To LOF(hFile)) As Byte
lstByte = UBound(Buffer) - 3 temp.prn文件的最后三个字节为翻页指令,此处将此3字节过滤

For I = 1 To lstByte
Get #hFile, , Buffer(I)
Next I

Call WritePrinter(hPrn, Buffer(1), lstByte, Written) 数据直接传送到打印机
End If lof=0
Close #hFile

Call EndPagePrinter(hPrn)
DoEvents
Call EndDocPrinter(hPrn) 结束打印
Call ClosePrinter(hPrn)
ret = DeleteDC(hPrintDC)
strDOC = False
Kill sFile 删除过渡文件

End If

End Sub

Public Sub StartDocs()


创建一个与默认打印机相关联的DC:
hPrintDC = CreateDC("WINSPOOL", prnName, 0, ByVal CLng(0))

di.cbSize = Len(di)
di.lpszDocName = "Heavy Metal Forever" 打印标题,随意设
di.lpszOutput = App.Path "" "temp.prn" 打印到过渡文件
di.lpszDatatype = ""
di.fwType = 0

ret = StartDoc(hPrintDC, di) 以传统模式开始一个打印Job
ret = StartPage(hPrintDC)
strDOC = True

End Sub

Private Sub Class_Initialize()

Dim sRet As String
Dim nRet As Integer
Dim I As Integer

查WIN.INI 中的默认打印机:
sRet = Space(255)
nRet = GetProfileString("Windows", ByVal "device", "", sRet, Len(sRet))
sRet = UCase(Left(sRet, InStr(sRet, ",") - 1))

prnName = sRet 默认打印机

End Sub


Private Sub Class_Terminate()
Exit Code
End Sub
点赞0 收藏

下面给出一个使用这个类的范例:

Dim LBL As New clsLBLPrn 创建一个新的clsLBLPrn 类实例

LBL.StartDocs 开始一个新的打印任务

LBL.CurrentX = 30 X坐标设置

LBL.CurrentY = 70 Y坐标设置

LBL.FontSize = 20 设置字号

LBL.PrintText "I LOVE WWW.STONEREN.COM " 打印文字

LBL.PrintLine 1, 1, 100,100 画一条从坐标1,1到100,100的直线

LBL.EndDocs 开始打印
点赞0 收藏
不错不错嘛,挺好的一个功能
Being a devil is the same as being a human. We should be kind. If we are kind, we are not a devil, we are a hybrid.
点赞0 收藏
我觉的这跟我们以前玩的虫子老虎棒子一样
Being a devil is the same as being a human. We should be kind. If we are kind, we are not a devil, we are a hybrid.
点赞0 收藏

星爷〈功夫〉主题曲-〈Kung Fu Fighting〉的来龙去脉


1974年春天,住在伦敦的印度裔音乐制作人Biddu正在费劲脑汁的寻找一个声音,一种充满激情与欢乐的声音--以期在著名DISCO音乐家Larry Weiss的新歌中客串男声。这之前的两年,Biddu通过为一部电影制作音乐而结识了牙买加的歌者Carl Douglas,Carl Douglas在这部电影的音乐制作中,演唱了主题曲。Biddu想来想去,觉得Carl Douglas的音质是再合适不过Larry Weiss的这首曲子,于是他给了通电话给Carl:“我已经为你准备好了一切。”

Larry Weiss打算把他的这首曲子放在A SIDE作为主打曲目,可是他和Biddu商量在B SIDE中他有几首曲子也想让人来演唱,正好Carl Douglas喜欢作词,于是他随意挑了几首歌词给Larry Weiss看。最后,Larry Weiss决定将Carl自写的一首〈ku fung fighting作为B SIDE的歌曲来用。一切都很平常,再普通不过的单曲构思过程,后来的事情是谁也没有想到的。

10分钟,ku fung fighting就在录音棚里录制完成。可是最初拿去给唱片公司高层的是A SIDE的那支曲子。Pye Records的高层当时听了主打曲子并未表现出太多的惊讶,于是询问Biddu这支单曲里还有其它的歌吗?Biddu立即把拿给他听,谁知道高层非常高兴:“我认为这是一支十分有趣的歌曲,我想拿来做A SIDE的主打歌是绰绰有余的。”Biddu也兴奋的说:“是呀,我们在里面加了很多新的元素,我保证它能卖的很好!”

Pye Records之所以做出这样的决定是因为他们考虑到70年代虽然空手道盛极一时,但是通过李小龙的电影大家熟悉起了中国原始、充满艺术性的功夫。功夫的热潮显然已经盖过了其它的形式的格斗技。Pye Records1974年在英国发行了kung fu fight的单曲,静静等待结果。

Biddu现在仍然充满激情的回忆着说:“你要知道,开始我们是十分沮丧和失望的,要知道开始5个星期没有在电台播出过一次,甚至没有卖出一张唱片!这对于歌手、制作人和唱片公司都是最无情的打击。谁知道呢?之后简直是太神气了!”Biddu眼里迸射出光芒,嗓音也变大起来:“之后我们的歌突然在每一个俱乐部热播,我们的歌瞬间成为英国的TOP 1,之后在整个世界范围引起轰动,每个国家都是排行榜的第一名。是的,我们整整卖出了9百万张!”

是在20th Century Records旗下登陆美国的,起初在BILLBOARD排行榜只排名94位,之后的几个月顽强的拼掉一个又一个对手最终赢得了这个美国最权威的音乐排行榜TOP 100的第一名!

Carl Douglas过去是位工程学的学生,后来在美国只有一次次登陆的记录,1975年3月发行的唱片。但是他在英国继续走红着,1977年他再次进入主流音乐榜的前30名。

Biddu发行制作了很多畅销DISCO纯乐唱片,当然也制作了另外一张英国TOP 1的单曲--由Tina CharlesI演唱的.他经常往返在祖国印度和英国之间,制作电影原声和一般的流行音乐唱片。目前暂时在伦敦栖息。

“我制作过很多大热单曲,惟独〈kung fu fighting是在制作阶段没有料到会如此的大热。当它在街头巷尾响起、被人传唱时……你要知道,通常人们并不知道还有许多非常棒的歌曲。就是这样成功的。”

----Biddu


2002年10月,Sanctuary/Castle Records再次发行了以kung fu fighting〉为主打的复古舞曲精选,唱片冠名为〈Soul of the Kung Fu Fighter〉。

在各个大大小小形形色色的SUPER STAR中,kung fu fighting的翻唱率非常高,这些大牌(FOO FIGHTER,BE GEES,WU TANG CLAN……)通常喜欢在演唱会中通过翻唱这首歌来让LVIE达到一个高潮!经典地位由此可见。

星爷选用这首曲子一方面为了让人感到“功夫”很世界,二来大概也想借借“900万张伟大单曲”的东风吧~哈哈



点赞0 收藏
支持,但问一个问题,楼主这个类,我用了,如果打印了几行后想换一张纸了怎么办?怎么结束打印?
点赞0 收藏
常规的打印模式本来就是按“页”打印的啊
如果你的目的是走几行 然后换纸 那么不需要使用这个类的!常规方式就好了
点赞0 收藏

本人试了你的程序,但还是按页打印


本人使用机型EPSON LQ-1600KⅢH 针打 USB接口


希望早日得到你的帮助,非常感谢!
点赞0 收藏
wshwsh你好,这段程序我现在已经没办法去测试了,因为手头上没有针式打印机,
我估计可能和USB接口有关,当年我也是用LQ1600K,其后又在NEC P-2000,和国产的“映美”打印机上试过都是可行的,不过他们都是并口打印机。
点赞0 收藏
发表回复
发表回复