Win2000下开发设置自定义纸张的DLL,调用时候没有按照预定的方式执行???(100分)

  • 主题发起人 主题发起人 flyballball
  • 开始时间 开始时间
F

flyballball

Unregistered / Unconfirmed
GUEST, unregistred user!
开发环境2000professional,DELPHI6.0 打印机为EPSON 1600KIII
我先做了一个打印程序(exe形式),代码通过了,并能正常执行.可以自定义纸张的大小.但将代码以DLL 形式实现后(具体函数代码内容不变), 用一测试程序调用dll的函数后打印,却没有实现自定义纸张功能.请高手们赐教给点建议,这个事情很急,困扰了我很久.
下面的函数是在2000下加入一个自定义的单式这个程序在dll中的,通过调试可以确定他实现了加入自定义单式的功能
function Init_Print(FormName:PChar;Height:Integer;Width:Integer):Integer;stdcall;
var
PrintDevice, PrintDriver, PrintPort : array[0..255] of Char;
hDMode : THandle;
hPrinter: THandle;
FormInfo: TFormInfo1;
PaperSize: TSize;
PaperRect: TRect;
errcode: integer;
s: string;
begin
Printer.GetPrinter(PrintDevice, PrintDriver, PrintPort, hDMode);
OpenPrinter(PrintDevice, hPrinter, nil);
if hPrinter = 0 then
raise Exception.Create('Failed to open printer!');
//设置纸张格式结构参数
FormInfo.Flags := FORM_USER;
FormInfo.pName := FormName;
PaperSize.cx := Width;
PaperSize.cy := Height;
PaperRect.Left := 0;
PaperRect.Top := 0;
PaperRect.Right := Width;
PaperRect.Bottom := Height;
FormInfo.Size := PaperSize;
FormInfo.ImageableArea := PaperRect;
if not AddForm(hPrinter, 1, @FormInfo) then
begin
errcode := GetLastError;
if errcode <> ERROR_FILE_EXISTS then
// Form name exists?
begin
case errcode of
ERROR_ACCESS_DENIED: s := 'Access is denied';
ERROR_INVALID_HANDLE: s := 'The handle is invalid';
ERROR_NOT_READY: s := 'The device is not ready';
ERROR_CALL_NOT_IMPLEMENTED:
s := 'Function "AddForm" is not supported on this system';
else
s := 'Failed to add a Form (paper) name!';
end;
raise Exception.Create(s);
end;
end;
ClosePrinter(hPrinter);
Result :=1;
end;
然后我用下面的这个Set_Print函数取出我上面加入2000中的自定义单式
function Set_Print(pName:PChar;Height:Integer;Width:Integer):Integer;stdcall;
var
Device, Driver, Port: array[0..80] of Char;
DevMode: THandle;
pDevmode: PDeviceMode;
iPaperSize : integer;
begin
// Get printer device name etc.
Printer.GetPrinter(Device, Driver, Port, DevMode);
// 强制重新加载 DEVMODE
Printer.SetPrinter(Device, Driver, Port, 0) ;
// 得到 DEVMODE handle
Printer.GetPrinter(Device, Driver, Port, DevMode);
if DevMode <> 0 then
begin
// lock it to get pointer to DEVMODE record
pDevMode := GlobalLock( DevMode );
if pDevmode <> nil then
try
with pDevmode^do
begin
// 装载进要使用的纸张格式
StrLCopy( dmFormName, pName, CCHFORMNAME-1 );
// 指定打印机的应确定的长宽
dmPaperWidth := Width;
dmPaperLength := Height;
dmFields := dmFields or DM_FORMNAME or DM_PAPERWIDTH or DM_PAPERLENGTH;
end;
finally
GlobalUnlock( Devmode );
// unlock devmode handle.
end;
end;
Result :=1;
end;
最后我在测试程序中做打印测试
InitPrint(Pchar(edit3.Text),StrToInt(edit2.Text),StrToInt(edit1.Text));

SetPrint(PChar(edit3.Text),StrToInt(edit2.Text),StrToInt(edit1.Text));
with Printerdo
begin
begin
Doc;
Canvas.TextOut(10,10,'Hello, My Friend!');
EndDoc;
end;
这是结果却没有按照预期的实现自定义打印。 而同样的set_print代码在我另做的exe方式的程序中却可以实现自定义打印。
我实在是想不出问题出在哪里 为什么set_print已dll方式实现就不行??
我问了好久这个问题,没人能给我回答,请高手多多帮忙!!
 
现在我只想知道在2000下怎么能改变打印机的默认设置,比如改变它自动送纸的纸张类型为我想要的
 
和您有同样的困惑,期待高手指教!
 
设置->打印机->文件菜单->服务器属性
 
老大这个还用你说,我要的是在程序中就可以实现打印机纸张类型的改变,要是用手工设置还用得着问么
 
dmPaperSize未设置
 
我同样遇到这个问题,在98/me下可以自定义纸张大小,在2000就定义不了,总是A4纸,请高手指点
 
qr是在2000是设置不了自定义纸的,本人已经多次偿试在rm中就可以解决这个问题
 
不好意思,请问rm是什么东东?[?]
 
在2000下打印机没有自定义这个格式,如果你要打印自已定义的格式,你首先要在打印服务属性中定义好这个格式 ,然后你就可以在程序中调用了这个格式,有多少种格式,就要设置多少
种格式.当然纸张格式,你也可以使用程序来判断设置.这种方法我在NT下开发程序使用的.
相信也可以用在2000下.你的程序没有问题,但是你在调用格式时我有不同建议,你设置格式时应对格式定义一个名称,就象A4,B3等,然后用程序调用这个格式就可以了.
 
不好意思,请问rm是什么东东?[?]
是不是ReportMachine
 
这是我在大富翁上找的,在D7下编译通过,不过没打印机,所以没能测试过,谁给测一下? :)
unit FrmNTprnsize;
interface
uses Windows, SysUtils, WinSpool, Printers;
procedure PrnAddForm(const FormName: string;
PaperWidth, PaperLength: integer);
procedure PrnSetPaperSizeNT(FormName: string;
PaperWidth, PaperLength: integer);
implementation
{在 WindowsNT/200 环境下要自定义纸张尺寸所使用的方法与 Win9x 不同,
你必须先为目前的打印机定义一个自定义的 "Form"(API: AddForm,
此 API 声明于WinSpool 中),然后把这个 Form 的名称设给
DEVMODES 结构中的 dmFormName 字段。}
(*------------------------------------------------------
Define a new Form (WinNT/2000 only).
If FormName already exists,do
nothing and return.
If failed, an exception will be raised.
------------------------------------------------------*)
procedure PrnAddForm(const FormName: string;
PaperWidth, PaperLength: integer);
var
PrintDevice, PrintDriver, PrintPort: array[0..255] of Char;
hDMode: THandle;
hPrinter: THandle;
FormInfo: TFormInfo1;
PaperSize: TSize;
PaperRect: TRect;
errcode: integer;
s: string;
begin
Printer.GetPrinter(PrintDevice, PrintDriver, PrintPort, hDMode);
OpenPrinter(PrintDevice, hPrinter, nil);
if hPrinter = 0 then
raise Exception.Create('Failed to open printer!');
FormInfo.Flags := FORM_USER;
FormInfo.pName := PChar(FormName);
PaperSize.cx := PaperWidth;
PaperSize.cy := PaperLength;
PaperRect.Left := 0;
PaperRect.Top := 0;
PaperRect.Right := PaperWidth;
PaperRect.Bottom := PaperLength;
FormInfo.Size := PaperSize;
FormInfo.ImageableArea := PaperRect;
if not AddForm(hPrinter, 1, @FormInfo) then
begin
errcode := GetLastError;
if errcode <> ERROR_FILE_EXISTS then
// Form name exists?
begin
case errcode of
ERROR_ACCESS_DENIED: s := 'Access is denied';
ERROR_INVALID_HANDLE: s := 'The handle is invalid';
ERROR_NOT_READY: s := 'The device is not ready';
ERROR_CALL_NOT_IMPLEMENTED:
s := 'Function "AddForm" is not supported on this system';
else
s := 'Failed to add a Form (paper) name!';
end;
raise Exception.Create(s);
end;
end;
ClosePrinter(hPrinter);
end;

//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
function GetPrnPaperSize(const sPrinterName, sFormName: string;
var iPaperSize: Integer
): Boolean;
var
hPrinter: THandle;
pData: PChar;
i, iShift: Integer;
dwNeed, dwReturn: DWORD;
pForm: PFormInfo1 {PFORM_INFO_1};
dwVersion: DWORD;
begin
Result := false;
dwNeed := 0;
dwReturn := 0;
pData := nil;
////////////////////////////////////////////////
//NT 误差校正
dwVersion := GetVersion();
//非 WIN NT 系列
if (dwVersion > $80000000) then
Exit;
dwVersion := dwVersion and $000000FF;
if dwVersion = 4 then
//Win NT
iShift := 2
else
//Win 2000
iShift := 0;
////////////////////////////////////////////////
if not OpenPrinter(PChar(sPrinterName), hPrinter, nil) then
Exit;
try
EnumForms(hPrinter, 1, nil, 0, dwNeed, dwReturn);
pData := AllocMem(dwNeed);
EnumForms(hPrinter, 1, pData, dwNeed, dwNeed, dwReturn);
for i := 0 to dwReturn - 1do
begin
pForm := PFormInfo1 {PFORM_INFO_1}(Integer(pData) + i * SizeOf(FORM_INFO_1));
if pForm.pName = sFormName then
begin
iPaperSize := i + 1 + iShift;
Result := true;
Exit;
end;
end;
finally
if pData <> nil then
FreeMem(pData);
ClosePrinter(hPrinter);
end;
end;

//-------------------------------------------------------------------------------------
(*
Set custom paper size for WinNT/2000.
Make sure FormName is supported by current printer,
You can call PrnAddForm to define a new Form.
*)
procedure PrnSetPaperSizeNT(FormName: string;
PaperWidth, PaperLength: integer);
var
iPaperSize: Integer;
Device, Driver, Port: array[0..80] of Char;
DevMode: THandle;
pDevmode: PDeviceMode;
begin
// Get printer device name etc.
Printer.GetPrinter(Device, Driver, Port, DevMode);
// force reload of DEVMODE
Printer.SetPrinter(Device, Driver, Port, 0);
// get DEVMODE handle
Printer.GetPrinter(Device, Driver, Port, DevMode);
if DevMode <> 0 then
begin
// lock it to get pointer to DEVMODE record
pDevMode := GlobalLock(DevMode);
if pDevmode <> nil then
try
with pDevmode^do
begin
// modify form
StrLCopy(dmFormName, PChar(FormName), CCHFORMNAME - 1);
// tell printer driver that dmFormname field contains
// data it needs to inspect.
dmPaperWidth := PaperWidth;
dmPaperLength := PaperLength;
dmFields := dmFields or DM_FORMNAME or DM_PAPERWIDTH or DM_PAPERLENGTH;
////////////////////////////////
if GetPrnPaperSize(Device, FormName, iPaperSize) then
dmPaperSize := iPaperSize;
dmFields := dmFields or DM_FORMNAME or DM_PAPERWIDTH or DM_PAPERLENGTH or
DM_PAPERSIZE;
////////////////////////////////
end;
finally
GlobalUnlock(Devmode);
// unlock devmode handle.
end;
end;
{ If }
end;

end.

调用时:
--------------------------------------
{$R *.dfm}
uses FrmNTprnsize;
procedure TForm1.btn1Click(Sender: TObject);
begin
PrnAddForm(
edtFormName.Text,
StrToInt(edtPaperWidth.Text),
StrToInt(edtPaperLength.Text)
);
PrnSetPaperSizeNT(
edtFormName.Text,
StrToInt(edtPaperWidth.Text),
StrToInt(edtPaperLength.Text)
);
Printer。。。。
end;
 
如何在WINDOWS中控制打印字体的长宽,而不受限于SIZE 的限制

首先为了达到这个功能,可以采用Windows的逻辑字体(LogFont)
可以使用 CreateFont 或 CreateFontIndirect 这两个Windows API
函数来定义任何想要的字体,由于 CreateFont 所需的参数甚多通常
我们使用 CreateFontIndirect 来建立所需的逻辑字体,这个API函数
在Delphi中的声明为
function CreateFontIndirect(const p1: TLogFont): HFONT;
stdcall;
其中只有一个参数 p1: TLogfont
所有有关字体的参数完全通过这个
TLogfont结构来传送,Windows将根据结构中的内容创建出相应的逻辑
字体,在Delphi的Windows.pas中TLogFont是这样定义的

TLogFontA = packed record
lfHeight: Longint;
lfWidth: Longint;
lfEscapement: Longint;
lfOrientation: Longint;
lfWeight: Longint;
lfItalic: Byte;
lfUnderline: Byte;
lfStrikeOut: Byte;
lfCharSet: Byte;
lfOutPrecision: Byte;
lfClipPrecision: Byte;
lfQuality: Byte;
lfPitchAndFamily: Byte;
lfFaceName: array[0..LF_FACESIZE - 1] of AnsiChar;
end;

TLogFontW = packed record
lfHeight: Longint;
lfWidth: Longint;
lfEscapement: Longint;
lfOrientation: Longint;
lfWeight: Longint;
lfItalic: Byte;
lfUnderline: Byte;
lfStrikeOut: Byte;
lfCharSet: Byte;
lfOutPrecision: Byte;
lfClipPrecision: Byte;
lfQuality: Byte;
lfPitchAndFamily: Byte;
lfFaceName: array[0..LF_FACESIZE - 1] of WideChar;
end;

TLogFont = TLogFontA;

其中涉及到很多参数,其中

lfHeight: Longint;
指定以逻辑单位标定的字体高度,取值可为正负或零,对于需要随意
定义字体高度的情况下通常取负值,以保证获得实际尺寸的字体。

lfWidth: Longint;
用于指定字体的平均宽度,由于Windows系统下的大多数字体都是比例
字体因而采用平均宽度这个表示方法。若指定为0,则系统会自动根据
适当的比例自动处理宽度。

lfEscapement: Longint;
指定输出方向与当前坐标系X轴之间的以十分之一度为单位的角度。

lfOrientation: Longint;
指定每个字符与当前坐标系X轴之间的以十分之一度为单位的角度。在
Windows95中这个值等同于lfEscpement。

lfWeight: Longint;
指定范围为从0至1000的字体加重程度,400是标准字体700为加重字体,
0表示采用默认值。

lfItalic: Byte;
不为0表示采用斜体字。

lfUnderline: Byte;
不为0表示带下划线。

lfStrikeOut: Byte;
不为0表示带穿透线。

lfCharSet: Byte;
指定字体集。

lfOutPrecision: Byte;
指定输出精度。用于确定对前面一些设定值的精确程度。

lfClipPrecision: Byte;
指定裁剪精度。裁剪是Windows图形环境下的一种特殊处理,简单说就是
去掉图形中落在视图以外的部分,有助于提高图形的处理速度。

lfQuality: Byte;
指定输出质量。

lfPitchAndFamily: Byte;
指定字体的Pitch和Family。

lfFaceName: array[0..LF_FACESIZE - 1] of AnsiChar;
指定采用的字体名称。

在建立逻辑字体时,我们通常使用

lfHeight和lfWidth来确定字体的尺寸,使用lfEscapement和lfOrientation
来确定字体的输出方向,使用lfWeight
lfItalic
lfUnderline

lfStrikeOut
来确定字体的加重,斜体,下划线和穿透线,使用lfCharSet
来确定字体的字符集,通常采用系统默认的字符集。
对于lfOutPrecision
lfClipPrecision
lfQuality一般应用于对屏幕之外
的输出设备,通常采用默认值。采用lfPitchAndFamily来确定采用定宽或可
变字体和字体的家族。以lfFaceName来通过名称选择采用的字体。
另外应当注意在Windows环境下,每种字体具体输出为何种形式取决于很多
因素,需要对以上这些参数进行有效的组合才能达到所要的效果。
 
后退
顶部