关于数据报表的打印设置
2006-02-27 11:45:14 来源:WEB开发网核心提示:数据报表(DataReport)是VB6新增功能之一,用过它的朋友对这个设计器可以说是既爱且恨,关于数据报表的打印设置,尽管它功能强大,但却有个非常致命的缺点:无法在设计环境中改变纸张大小及走向,就可能造成混乱,尽管如此,即使你在程序中使用PRinter对象改变纸张大小及打印走向,也解决不了问题
数据报表(DataReport)是VB6新增功能之一。用过它的朋友对这个设计器可以说是既爱且恨。尽管它功能强大,但却有个非常致命的缺点:无法在设计环境中改变纸张大小及走向。即使你在程序中使用PRinter对象改变纸张大小及打印走向,也解决不了问题。对于非A4纸的报表或是横向打印的报表,连报表预览都不行。
问题的原因是:DR基于系统默认的打印设置创建自己的内部设备环境。而这个设备环境是没有向外界展现的。DR的内部设备环境与VB的Printer对象的内部设备环境是完全不同的,因此改变打印机对象的属性对DR一点效果也没有。
解决这个问题的笨办法是,在预览或打印时改变系统默认打印机的设置。使用这个方法连自己都会觉得麻烦,更何况是你的用户。没办法,只能通过代码强行改变系统默认打印机的设置来解决。将下面的代码放入一个模块中:
OptionExplicit
PublicEnumPrinterOrientationConstants
OrientPortrait=1
OrientLandscape=2
EndEnum
PrivateTypeDEVMODE
dmDeviceNameAsString*32
dmSpecVersionAsInteger
dmDriverVersionAsInteger
dmSizeAsInteger
dmDriverExtraAsInteger
dmFieldsAsLong
dmOrientationAsInteger
dmPaperSizeAsInteger
dmPaperLengthAsInteger
dmPaperWidthAsInteger
dmScaleAsInteger
dmCopiesAsInteger
dmDefaultSourceAsInteger
dmPrintQualityAsInteger
dmColorAsInteger
dmDuplexAsInteger
dmYResolutionAsInteger
dmTTOptionAsInteger
dmCollateAsInteger
dmFormNameAsString*32
dmUnusedPaddingAsInteger
dmBitsPerPelAsInteger
dmPelsWidthAsLong
dmPelsHeightAsLong
dmDisplayFlagsAsLong
dmDisplayFrequencyAsLong
EndType
PrivateTypePRINTER_DEFAULTS
pDataTypeAsString
pDevModeAsLong
DesiredaccessAsLong
EndType
PrivateTypePRINTER_INFO_2
pServerNameAsLong
pPrinterNameAsLong
pShareNameAsLong
pPortNameAsLong
pDriverNameAsLong
pCommentAsLong
pLocationAsLong
pDevModeAsLong
pSepFileAsLong
pPrintProcessorAsLong
pDataTypeAsLong
pParametersAsLong
pSecurityDescriptorAsLong
AttributesAsLong
PriorityAsLong
DefaultPriorityAsLong
StartTimeAsLong
UntilTimeAsLong
StatusAsLong
cJobsAsLong
AveragePPMAsLong
EndType
PublicConstDMPAPER_A5=11
PrivateConstDM_IN_BUFFERAsLong=8
PrivateConstDM_OUT_BUFFERAsLong=2
PrivateConstDM_ORIENTATIONAsLong=&H1
PrivateConstDM_PAPERSIZE=&H2&
PrivateConstPRINTER_ACCESS_ADMINISTERAsLong=&H4
PrivateConstPRINTER_ACCESS_USEAsLong=&H8
PrivateConstSTANDARD_RIGHTS_REQUIREDAsLong=&HF0000
PrivateConstPRINTER_ALL_ACCESS=(STANDARD_RIGHTS_REQUIREDOrPRINTER_ACCESS_ADMINISTEROrPRINTER_ACCESS_USE)
PrivateDeclareSubCopyMemoryLib"kernel32"Alias"RtlMoveMemory"(hpvDestAsAny,hpvSourceAsAny,ByValcbCopyAsLong)
PrivateDeclareFunctionOpenPrinterLib"winspool.drv"Alias"OpenPrinterA"(ByValpPrinterNameAsString,phprinterAsLong,pDefaultAsAny)AsLong
PrivateDeclareFunctionClosePrinterLib"winspool.drv"(ByValhPrinterAsLong)AsLong
PrivateDeclareFunctionDocumentPropertiesLib"winspool.drv"Alias"DocumentPropertiesA"(ByValhWndAsLong,ByValhPrinterAsLong,ByValpDeviceNameAsString,pDevModeOutputAsAny,pDevModeInputAsAny,ByValfModeAsLong)AsLong
PrivateDeclareFunctionGetPrinterLib"winspool.drv"Alias"GetPrinterA"(ByValhPrinterAsLong,ByValLevelAsLong,pPrinterAsAny,ByValcbBufAsLong,pcbNeededAsLong)AsLong
PrivateDeclareFunctionSetPrinterLib"winspool.drv"Alias"SetPrinterA"(ByValhPrinterAsLong,ByValLevelAsLong,pPrinterAsAny,ByValCommandAsLong)AsLong
FunctionSetDefaultPrinterOrientation(ByValeOrientationasprinterOrientationConstants)AsBoolean
DimbDevMode()AsByte
DimbPrinterInfo2()AsByte
DimhPrinterAsLong
DimlResultAsLong
DimnSizeAsLong
DimsPrnNameAsString
DimdmAsDEVMODE
DimpdAsPRINTER_DEFAULTS
Dimpi2AsPRINTER_INFO_2
'获取默认打印机的设备名称
sPrnName=Printer.DeviceName
'由于要调用SetPrinter,所以
'如果是在NT下就要求PRINTER_ALL_ACCESS
pd.DesiredAccess=PRINTER_ALL_ACCESS
'获取打印机句柄
IfOpenPrinter(sPrnName,hPrinter,pd)Then
'获取PRINTER_INFO_2结构要求的字节数
CallGetPrinter(hPrinter,2&,0&,0&,nSize)
ReDimbPrinterInfo2(1TonSize)AsByte
lResult=GetPrinter(hPrinter,2,bPrinterInfo2(1),nSize,nSize)
CallCopyMemory(pi2,bPrinterInfo2(1),Len(pi2))
nSize=DocumentProperties(0&,hPrinter,sPrnName,0&,0&,0)
ReDimbDevMode(1TonSize)
Ifpi2.pDevModeThen
CallCopyMemory(bDevMode(1),ByValpi2.pDevMode,Len(dm))
Else
CallDocumentProperties(0&,hPrinter,sPrnName,bDevMode(1),0&,DM_OUT_BUFFER)
EndIf
CallCopyMemory(dm,bDevMode(1),Len(dm))
Withdm
'设置新的走向
.dmOrientation=eOrientation
.dmFields=DM_ORIENTATION
'.dmPaperSize=DMPAPER_A5将纸张大小设为A5,请自行更改所需大小
'.dmFields=DM_PAPERSIZE必须,否则无法设置纸张大小
EndWith
CallCopyMemory(bDevMode(1),dm,Len(dm))
CallDocumentProperties(0&,hPrinter,sPrnName,_
bDevMode(1),bDevMode(1),DM_IN_BUFFEROr_
DM_OUT_BUFFER)
pi2.pDevMode=VarPtr(bDevMode(1))
lResult=SetPrinter(hPrinter,2,pi2,0&)
CallClosePrinter(hPrinter)
SetDefaultPrinterOrientation=True
Else
SetDefaultPrinterOrientation=False
EndIf
EndFunction
在打印或预览之前直接调用SetDefaultPrinterOrientation打印走向常数。注意:红色注释部分用于改变纸张的大小。
这个解决方案仍有两个问题:
1。对有些型号的打印机不起作用,例如佳能的BJC-265SP
2。即使是在预浏DR时,也必须改变打印机的设置。这时如果有其它使用打印机默认设置的程序(如Notepad)要进行打印作业,就可能造成混乱。
尽管如此,这个方法是目前唯一好用的方法。->
问题的原因是:DR基于系统默认的打印设置创建自己的内部设备环境。而这个设备环境是没有向外界展现的。DR的内部设备环境与VB的Printer对象的内部设备环境是完全不同的,因此改变打印机对象的属性对DR一点效果也没有。
解决这个问题的笨办法是,在预览或打印时改变系统默认打印机的设置。使用这个方法连自己都会觉得麻烦,更何况是你的用户。没办法,只能通过代码强行改变系统默认打印机的设置来解决。将下面的代码放入一个模块中:
OptionExplicit
PublicEnumPrinterOrientationConstants
OrientPortrait=1
OrientLandscape=2
EndEnum
PrivateTypeDEVMODE
dmDeviceNameAsString*32
dmSpecVersionAsInteger
dmDriverVersionAsInteger
dmSizeAsInteger
dmDriverExtraAsInteger
dmFieldsAsLong
dmOrientationAsInteger
dmPaperSizeAsInteger
dmPaperLengthAsInteger
dmPaperWidthAsInteger
dmScaleAsInteger
dmCopiesAsInteger
dmDefaultSourceAsInteger
dmPrintQualityAsInteger
dmColorAsInteger
dmDuplexAsInteger
dmYResolutionAsInteger
dmTTOptionAsInteger
dmCollateAsInteger
dmFormNameAsString*32
dmUnusedPaddingAsInteger
dmBitsPerPelAsInteger
dmPelsWidthAsLong
dmPelsHeightAsLong
dmDisplayFlagsAsLong
dmDisplayFrequencyAsLong
EndType
PrivateTypePRINTER_DEFAULTS
pDataTypeAsString
pDevModeAsLong
DesiredaccessAsLong
EndType
PrivateTypePRINTER_INFO_2
pServerNameAsLong
pPrinterNameAsLong
pShareNameAsLong
pPortNameAsLong
pDriverNameAsLong
pCommentAsLong
pLocationAsLong
pDevModeAsLong
pSepFileAsLong
pPrintProcessorAsLong
pDataTypeAsLong
pParametersAsLong
pSecurityDescriptorAsLong
AttributesAsLong
PriorityAsLong
DefaultPriorityAsLong
StartTimeAsLong
UntilTimeAsLong
StatusAsLong
cJobsAsLong
AveragePPMAsLong
EndType
PublicConstDMPAPER_A5=11
PrivateConstDM_IN_BUFFERAsLong=8
PrivateConstDM_OUT_BUFFERAsLong=2
PrivateConstDM_ORIENTATIONAsLong=&H1
PrivateConstDM_PAPERSIZE=&H2&
PrivateConstPRINTER_ACCESS_ADMINISTERAsLong=&H4
PrivateConstPRINTER_ACCESS_USEAsLong=&H8
PrivateConstSTANDARD_RIGHTS_REQUIREDAsLong=&HF0000
PrivateConstPRINTER_ALL_ACCESS=(STANDARD_RIGHTS_REQUIREDOrPRINTER_ACCESS_ADMINISTEROrPRINTER_ACCESS_USE)
PrivateDeclareSubCopyMemoryLib"kernel32"Alias"RtlMoveMemory"(hpvDestAsAny,hpvSourceAsAny,ByValcbCopyAsLong)
PrivateDeclareFunctionOpenPrinterLib"winspool.drv"Alias"OpenPrinterA"(ByValpPrinterNameAsString,phprinterAsLong,pDefaultAsAny)AsLong
PrivateDeclareFunctionClosePrinterLib"winspool.drv"(ByValhPrinterAsLong)AsLong
PrivateDeclareFunctionDocumentPropertiesLib"winspool.drv"Alias"DocumentPropertiesA"(ByValhWndAsLong,ByValhPrinterAsLong,ByValpDeviceNameAsString,pDevModeOutputAsAny,pDevModeInputAsAny,ByValfModeAsLong)AsLong
PrivateDeclareFunctionGetPrinterLib"winspool.drv"Alias"GetPrinterA"(ByValhPrinterAsLong,ByValLevelAsLong,pPrinterAsAny,ByValcbBufAsLong,pcbNeededAsLong)AsLong
PrivateDeclareFunctionSetPrinterLib"winspool.drv"Alias"SetPrinterA"(ByValhPrinterAsLong,ByValLevelAsLong,pPrinterAsAny,ByValCommandAsLong)AsLong
FunctionSetDefaultPrinterOrientation(ByValeOrientationasprinterOrientationConstants)AsBoolean
DimbDevMode()AsByte
DimbPrinterInfo2()AsByte
DimhPrinterAsLong
DimlResultAsLong
DimnSizeAsLong
DimsPrnNameAsString
DimdmAsDEVMODE
DimpdAsPRINTER_DEFAULTS
Dimpi2AsPRINTER_INFO_2
'获取默认打印机的设备名称
sPrnName=Printer.DeviceName
'由于要调用SetPrinter,所以
'如果是在NT下就要求PRINTER_ALL_ACCESS
pd.DesiredAccess=PRINTER_ALL_ACCESS
'获取打印机句柄
IfOpenPrinter(sPrnName,hPrinter,pd)Then
'获取PRINTER_INFO_2结构要求的字节数
CallGetPrinter(hPrinter,2&,0&,0&,nSize)
ReDimbPrinterInfo2(1TonSize)AsByte
lResult=GetPrinter(hPrinter,2,bPrinterInfo2(1),nSize,nSize)
CallCopyMemory(pi2,bPrinterInfo2(1),Len(pi2))
nSize=DocumentProperties(0&,hPrinter,sPrnName,0&,0&,0)
ReDimbDevMode(1TonSize)
Ifpi2.pDevModeThen
CallCopyMemory(bDevMode(1),ByValpi2.pDevMode,Len(dm))
Else
CallDocumentProperties(0&,hPrinter,sPrnName,bDevMode(1),0&,DM_OUT_BUFFER)
EndIf
CallCopyMemory(dm,bDevMode(1),Len(dm))
Withdm
'设置新的走向
.dmOrientation=eOrientation
.dmFields=DM_ORIENTATION
'.dmPaperSize=DMPAPER_A5将纸张大小设为A5,请自行更改所需大小
'.dmFields=DM_PAPERSIZE必须,否则无法设置纸张大小
EndWith
CallCopyMemory(bDevMode(1),dm,Len(dm))
CallDocumentProperties(0&,hPrinter,sPrnName,_
bDevMode(1),bDevMode(1),DM_IN_BUFFEROr_
DM_OUT_BUFFER)
pi2.pDevMode=VarPtr(bDevMode(1))
lResult=SetPrinter(hPrinter,2,pi2,0&)
CallClosePrinter(hPrinter)
SetDefaultPrinterOrientation=True
Else
SetDefaultPrinterOrientation=False
EndIf
EndFunction
在打印或预览之前直接调用SetDefaultPrinterOrientation打印走向常数。注意:红色注释部分用于改变纸张的大小。
这个解决方案仍有两个问题:
1。对有些型号的打印机不起作用,例如佳能的BJC-265SP
2。即使是在预浏DR时,也必须改变打印机的设置。这时如果有其它使用打印机默认设置的程序(如Notepad)要进行打印作业,就可能造成混乱。
尽管如此,这个方法是目前唯一好用的方法。->
更多精彩
赞助商链接