C++Builder 程序员博客
17 Jul
实现功能: 打印窗体
问题:
在我的电脑上编译后运行,打印出错,错误请看下面代码。
在其他电脑上编译后运行,打印正常。
在其他电脑上不编译直接运行我的程序,打印出错。
(公司的电脑都测试了下,几台正常,几台出错)
代码如下:
Unit1.h
//————————————————————————— #ifndef Unit1H #define Unit1H //————————————————————————— #include <Classes.hpp> #include <Controls.hpp> #include <StdCtrls.hpp> #include <Forms.hpp> #include <Dialogs.hpp> //————————————————————————— class TForm1 : public TForm { __published: // IDE-managed Components TButton *Button1; TPrintDialog *PrintDialog1; void __fastcall Button1Click(TObject *Sender); private: // User declarations public: // User declarations __fastcall TForm1(TComponent* Owner); void Print_SW(Graphics::TBitmap * Bitmap); //2007/11/30 add by shiwei<– BITMAPFILEHEADER * DibLoadImage (PTSTR pstrFileName); }; //————————————————————————— extern PACKAGE TForm1 *Form1; //————————————————————————— #endif
Unit1.cpp
//————————————————————————— #include <vcl.h> #pragma hdrstop #include "Unit1.h" //————————————————————————— #pragma package(smart_init) #pragma resource "*.dfm" TForm1 *Form1; //————————————————————————— __fastcall TForm1::TForm1(TComponent* Owner) : TForm(Owner) { } //————————————————————————— void __fastcall TForm1::Button1Click(TObject *Sender) { int nWinState; if(PrintDialog1->Execute()) { Graphics::TBitmap *formbmp, *temp; formbmp = new Graphics::TBitmap(); temp = new Graphics::TBitmap(); try { Button1->Visible = false; nWinState=this->WindowState; this->WindowState = wsMaximized; temp = GetFormImage(); formbmp->Width = ClientWidth; formbmp->Height = ClientHeight; TRect tmpRec; tmpRec.Top = 1; tmpRec.Left = 1; tmpRec.Right = ClientWidth; tmpRec.Bottom = ClientHeight; formbmp->Canvas->CopyRect( ClientRect, temp->Canvas, tmpRec ); Print_SW(formbmp); } __finally { this->WindowState =nWinState; delete formbmp; delete temp; } } } void TForm1::Print_SW(Graphics::TBitmap * Bitmap) { static BITMAPFILEHEADER * pbmfh ; static BITMAPINFO * pbmi ; static BYTE * pBits ; static int DIBWidth, DIBHeight, PrintWidth, PrintHeight; Bitmap->SaveToFile(".\\~tmp.bmp"); // Load the entire DIB into memory AnsiString TmpStr = GetCurrentDir()+"\\~tmp.bmp"; pbmfh = DibLoadImage(TmpStr.c_str()); //Get pointers to the info structure & the bits pbmi = (BITMAPINFO *) (pbmfh + 1) ; pBits = (BYTE *) pbmfh + pbmfh->bfOffBits ; // Get the DIB width and height if (pbmi->bmiHeader.biSize == sizeof (BITMAPCOREHEADER)) { DIBWidth = ((BITMAPCOREHEADER *) pbmi)->bcWidth ; DIBHeight = ((BITMAPCOREHEADER *) pbmi)->bcHeight ; } else { DIBWidth = pbmi->bmiHeader.biWidth ; DIBHeight = abs (pbmi->bmiHeader.biHeight) ; } PrintHeight = Printer()->Canvas->ClipRect.Height(); PrintWidth = Printer()->Canvas->ClipRect.Width(); Printer()->BeginDoc(); SetStretchBltMode(Printer()->Canvas->Handle,COLORONCOLOR); StretchDIBits( Printer()->Canvas->Handle, 0, 0, PrintWidth, PrintHeight, 0, 0, DIBWidth, DIBHeight, pBits, pbmi, DIB_RGB_COLORS, SRCCOPY ); Printer()->EndDoc(); if (pbmfh) free (pbmfh) ; DeleteFile(TmpStr); } //————————————————————————— BITMAPFILEHEADER * TForm1::DibLoadImage (PTSTR pstrFileName) { BOOL bSuccess ; DWORD dwFileSize, dwHighSize, dwBytesRead ; HANDLE hFile ; BITMAPFILEHEADER * pbmfh ; hFile = CreateFile (pstrFileName, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_FLAG_SEQUENTIAL_SCAN, NULL) ; if (hFile == INVALID_HANDLE_VALUE) return NULL ; dwFileSize = GetFileSize (hFile, &dwHighSize) ; if (dwHighSize) { CloseHandle (hFile) ; return NULL ; } pbmfh =(BITMAPFILEHEADER *)malloc(dwFileSize) ; if (!pbmfh) { CloseHandle (hFile) ; return NULL ; } bSuccess = ReadFile (hFile, pbmfh, dwFileSize, &dwBytesRead, NULL) ; CloseHandle (hFile) ; if (!bSuccess || (dwBytesRead != dwFileSize) || (pbmfh->bfType != * (WORD *) "BM") || (pbmfh->bfSize != dwFileSize)) { free (pbmfh) ; return NULL ; } return pbmfh ; }
根据进去后 发现我的电脑上问题出现在这里:
if (!bSuccess ¦ ¦ (dwBytesRead != dwFileSize)
¦ ¦ (pbmfh->bfType != * (WORD *) "BM")
¦ ¦ (pbmfh->bfSize != dwFileSize))
{
free (pbmfh) ;
return NULL ;
}
中的 (pbmfh->bfSize != dwFileSize) 不相等,所以返回了NULL;
但是其他电脑上(pbmfh->bfSize != dwFileSize) 相等,执行打印正常。
大家帮忙测试下,看看是什么问题!!!谢谢!!
是不是你的打印机上的驱动没有安好?
晕,你没仔细看我的写的东西,驱动正常的
电脑无打印机噢。。搞不起来噢。。
首先,确定你的BCB引用的头文件路径正确,库文件路径正确(%BCB%\include,%BCB%\lib应该写在其它路径前面)
然后,找到BITMAPFILEHEADER的声明部分(应该在wingdi.h里),在它的前面写上#pragma pack(push,2),后面写上#pragma pack(pop)再试试。
可以用微软的虚拟打印机调试的
不知道为什么 我的电脑上 :
pbmfh =(BITMAPFILEHEADER *)malloc(dwFileSize) ;
bSuccess = ReadFile (hFile, pbmfh, dwFileSize, &dwBytesRead, NULL) ;
返回值1,成功,但是读进来的值pbmfh 的size很小,只有几十,和dwFileSize(几百万)无法相比。
其他电脑上这两个值是相等的。
我觉得应该就是字节对齐的问题,在偶的电脑上试也木有问题,你干脆直接重新定义BITMAPFILEHEADER吧:
#pragma pack(push,2)
struct MYBITMAPFILEHEADER {
WORD bfType;
DWORD bfSize;
WORD bfReserved1;
WORD bfReserved2;
DWORD bfOffBits;
};
#pragma pack(pop)
粘贴用16进制工具打开图片(前面一部分):
BM6.=…..6…(…………. …….=……………..€€€.€€€.€€€.€€€.€€€.€€€.€€€.€€€.€€€.€€€.€€€.€€€.€€€.€€€.€€€.€€€.€€€.€€€.€€€.€€€.€€€.€€€.€€€.€€€.€€€.€€€.€€€.€€€.€€€.€€€.€€
没有具体的数字,怎么会出现点了。。
bmp的图片大小 3906K
你这是16进制工具吗? 应该是: 42 4D 36 酱紫的。
恩,刚下的专门的16进制工具,应该不会有问题的,不知道为什么出来的都是
…(…………. …….=……………..€€€.€€€.€€€.€€€.€€€.€€€.€€€.€€€.€€€.€€€.€€€.€€€.€€€.€€€.€€€.€€€.€€€.€€€.€€€.€€€.€€€.€€€.€€€.€€€.€€€.€€€.€€€.€€€.€€€.€€€.€€
你帮忙推荐个好的工具。
晕,你直接把前10个字节的ASCII码给写上来吧。
我推荐的16进制编辑器是PSPad和XVI32,都是免费的。
42 4D 36 E0 38 00 00 00 00 00 36 00 00 00 28 00
00 00 00 05 00 00 D8 02 00 00 01 00 20 00 00 00
00 00 00 E0 38 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 80 80 80 00 80 80 80 00 80 80
80 00 80 80 80 00 80 80 80 00 80 80 80 00 80 80
80 00 80 80 80 00 80 80 80 00 80 80 80 00 80 80
…..
80 00 80 80 80 00 80 80 80 00 80 80 80 00 80 80
图片我传到纳米盘了,您看看
图片地址:
http://www.namipan.com/d/f0c100f85309d3be2258ca287342dd79773551e836e03800
看来图片没有问题,是3727414。
别研究了,是你的BITMAPFILEHEADER定义有问题,很可能是字节对齐问题或者是引用了不正确的头文件。
右击BITMAPFILEHEADER,查找定义,看BCB打开的相关头文件是不是%BCB%\Include\wingdi.h。如果不是,应该是你的工程属性里的头文件引用顺序不对,把%BCB%\Include调在前面即可。
如不确实是%BCB%\Include\wingdi.h,那偶也不知道是怎么回事了,你可以试试把正常的电脑上的%BCB%\Include\覆盖你的。或者最后一招,重装BCB:-(
好的,我去试试,谢谢!
刚把正常的电脑上的%BCB%\Include\覆盖后,可以了。
请问下,include中的文件覆盖会不会造成我安装控件出现问题?
Waiting4you 2008年07月17日 17点19分50秒 说:
注意在定义的前后加#pragma pack(push,2)和#pragma pack(pop),它的作用是取消编译器的字节对齐功能。
字节对齐是一个优化内存读写能力的功能,我想你的编译器就是错误地优化了这个结构的数据对齐,本来bfType占用两字节,接下来就是四字节的bfSize。但是你的编译器很可能在bfType和bfSize之间插入了2字节以保证所谓的字节对齐。
~~~~~~~~~~~~~~~~~~~~~~~~~~~~ⷠ
解决问题的方法有两个:
1.把正常的电脑上的%BCB%\Include\覆盖不正常的电脑上的%BCB%\Include\
2.按照您说的,BITMAPFILEHEADER的定义 前后加上 #pragma pack(push,2)和#pragma pack(pop)
为什么别的电脑上不加上 #pragma pack(push,2)和#pragma pack(pop),也没有问题。
我的电脑需要加上这个,就解决了问题
看看,学习下
BITMAPFILEHEADER的原来的定义
#include <pshpack2.h>
typedef struct tagBITMAPFILEHEADER {
WORD bfType;
DWORD bfSize;
WORD bfReserved1;
WORD bfReserved2;
DWORD bfOffBits;
} BITMAPFILEHEADER, FAR *LPBITMAPFILEHEADER, *PBITMAPFILEHEADER;
#include <poppack.h>
修改后:
#include <pshpack2.h>
#pragma pack(push,2)
typedef struct tagBITMAPFILEHEADER {
WORD bfType;
DWORD bfSize;
WORD bfReserved1;
WORD bfReserved2;
DWORD bfOffBits;
} BITMAPFILEHEADER, FAR *LPBITMAPFILEHEADER, *PBITMAPFILEHEADER;
#pragma pack(pop)
#include <poppack.h>
于是把include文件下的pshpack2.h文件比对了下
发现打印错误的电脑上的pshpack2.h文件前后多了这两行:
#pragma option push -b -a8 -pc -A- /*P_O_Push*/
……….中间相同
#pragma option pop /*P_O_Pop*/
poppack.h 也一样多了
#pragma option push -b -a8 -pc -A- /*P_O_Push*/
……….中间相同
#pragma option pop /*P_O_Pop*/
马甲来顶顶,不然发不了言
完美解决,说到底还是
Waiting4you 大哥说的 字节对齐 问题
把 pshpack2.h 和 poppack.h 中的头尾两行去掉,就可以了!
谢谢 Waiting4you 大哥:),Waiting4you 大哥是好人。
这么耐心的教我!
再研究研究,明天来结贴!
为什么我的电脑里%BCB%\Include\下的 pshpack2.h 和 poppack.h 头尾会多出
#pragma option push -b -a8 -pc -A- /*P_O_Push*/
……
#pragma option pop /*P_O_Pop*/
难道是版本的问题!
通过打sp4补丁也可以解决!