因为水晶报表的PaperSize是enum类型,但有时客户用的纸张不在其定义范围内,虽然在设计报表时可以选择目的打印机和纸型,但如果重新配置过该
打印机则报表默认纸型不再有效,报表将按A4进行预览且会失真。
//获取本机所有打印机将其名称填充到comboBoxPrinters中:包含本地和网络打印机
foreach
(
string
printer in
System
.
Drawing
.
Printing
.
PrinterSettings
.
InstalledPrinters)
{
this
.
comboBoxPrinters.
Items.
Add(
printer)
;
}
//当从comboBoxPrinters中选择打印机时获取其支持的纸张大小将其填充到listBoxPapers
this
.
listBoxPapers.
Items.
Clear(
)
;
string
printer =
this
.
comboBoxPrinters.
Text
;
this
.
m_printer =
printer;
Microsoft
.
Win32
.
RegistryKey
rk;
if
(
!
this
.
comboBoxPrinters.
Text
.
StartsWith(
@
"//"
)
)
//本地打印机
rk =
Microsoft
.
Win32
.
Registry
.
LocalMachine.
OpenSubKey(
"SOFTWARE//Microsoft//Windows
NT//CurrentVersion//Print//Printers//"
+
this
.
comboBoxPrinters.
Text
+
"//DsDriver"
)
;
else
//网络打印机
{
string
[
]
p =
printer.
Remove(
0,
2)
.
Split(
new
char
[
]
{
'//'
}
)
;
string
path
=
"SOFTWARE//Microsoft//Windows
NT//CurrentVersion//Print//Providers//LanMan Print Services//Servers//"
+
p[
0]
+
"//Printers//"
+
p[
1]
+
"//DsDriver"
;
rk =
Microsoft
.
Win32
.
Registry
.
LocalMachine.
OpenSubKey(
path
)
;
}
string
[
]
papers =
(
string
[
]
)
(
rk.
GetValue(
"printMediaSupported"
)
)
;
for
(
int
i=
0;
i<
papers.
Length;
i+
+
)
{
this
.
listBoxPapers.
Items.
Add(
papers[
i]
)
;
}
//根据纸张名称获取其所在本地机上的PaperSize:调用的是PaperSizeGetter.Get_PaperSizes静态方法
(是从水晶报表中reflect精简出来的,版权归原作者所有)
public
class
PaperSizeGetter
{
public
static
string
OutputPort =
String
.
Empty;
[
DllImport(
"winspool.drv"
,
CharSet
=
CharSet
.
Auto,
SetLastError=
true
)
]
public
static
extern
int
DeviceCapabilities(
string
pDevice,
string
pPort,
short
fwCapabilities,
IntPtr
pOutput,
IntPtr
pDevMode)
;
public
static
int
[
]
Get_PaperSizes(
string
printer)
{
string
text1 =
printer;
int
num1 =
FastDeviceCapabilities(
0x10,
IntPtr
.
Zero,
-
1,
text1)
;
if
(
num1 =
=
-
1)
{
return
new
int
[
0]
;
}
int
num2 =
Marshal
.
SystemDefaultCharSize
*
0x40;
IntPtr
ptr1 =
Marshal
.
AllocCoTaskMem(
num2 *
num1)
;
FastDeviceCapabilities(
0x10,
ptr1,
-
1,
text1)
;
IntPtr
ptr2 =
Marshal
.
AllocCoTaskMem(
2 *
num1)
;
FastDeviceCapabilities(
2,
ptr2,
-
1,
text1)
;
IntPtr
ptr3 =
Marshal
.
AllocCoTaskMem(
8 *
num1)
;
FastDeviceCapabilities(
3,
ptr3,
-
1,
text1)
;
int
[
]
sizeArray1 =
new
int
[
num1]
;
for
(
int
num3 =
0;
num3 <
num1;
num3+
+
)
{
string
text2 =
Marshal
.
PtrToStringAuto(
(
IntPtr
)
(
(
(
long
)
ptr1)
+
(
num2 *
num3)
)
,
0x40)
;
int
num4 =
text2.
IndexOf(
'/0'
)
;
if
(
num4 >
-
1)
{
text2 =
text2.
Substring(
0,
num4)
;
}
short
num5 =
Marshal
.
ReadInt16(
(
IntPtr
)
(
(
(
long
)
ptr2)
+
(
num3 *
2)
)
)
;
int
num6 =
Marshal
.
ReadInt32(
(
IntPtr
)
(
(
(
long
)
ptr3)
+
(
num3 *
8)
)
)
;
int
num7 =
Marshal
.
ReadInt32(
(
IntPtr
)
(
(
(
(
long
)
ptr3)
+
(
num3 *
8)
)
+
4)
)
;
sizeArray1[
num3]
=
System
.
Convert
.
ToInt32(
num5)
;
}
Marshal
.
FreeCoTaskMem(
ptr1)
;
Marshal
.
FreeCoTaskMem(
ptr2)
;
Marshal
.
FreeCoTaskMem(
ptr3)
;
return
sizeArray1;
}
private
static
int
FastDeviceCapabilities(
short
capability,
IntPtr
pointerToBuffer,
int
defaultValue,
string
printerName)
{
int
num1 =
DeviceCapabilities(
printerName,
OutputPort,
capability,
pointerToBuffer,
IntPtr
.
Zero)
;
if
(
num1 =
=
-
1)
{
return
defaultValue;
}
return
num1;
}
}
//根据纸型名称在其名称列表中的索引,获取该索引在调用Get_PaperSizes后的size数组中的对应值
int
[
]
sizes =
PaperSizeGetter.
Get_PaperSizes(
printerName)
;
int
paperSizeid =
sizes[
this
.
listBoxPapers.
SelectedIndex]
;
//将该size赋值给报表对象
report.
PrintOptions.
PaperSize
=
(
CrystalDecisions.
Shared.
PaperSize
)
(
paperSizeid)
;
|
本地机的每种纸型在每个支持的打印机上都对应了个id值,不同的配置顺序,不同的客户机相同纸型名称对都会导致不同的id,怎么获取这个id是关键,例如
本机的
Letter 1
Tabloid 3
Legal 5
A3 8
A4 9
A5 11
B4 119
B5 120
11x17 121
25x25 122 //自定义
PostScript 自定义页面大小 32767
从打印机服务器属性中删除25x25,增加26x26,再增加25x25
Letter 1
Tabloid 3
Legal 5
A3 8
A4 9
A5 11
B4 119
B5 120
11x17 121
26x26 122 //自定义
25x25 123 //自定义
PostScript 自定义页面大小 32767
通过reflect水晶报表的PaperSize属性得知水晶报表通过这个id来设置其纸张大小,所以才想出这么个笨方法暂时解决了客户的要求。
Get_PaperSizes方法,以及这个id真实涵义自己还没弄懂,还请高人指点。