实现功能: 打印窗体

问题:   

在我的电脑上编译后运行,打印出错,错误请看下面代码。
在其他电脑上编译后运行,打印正常。
在其他电脑上不编译直接运行我的程序,打印出错。

(公司的电脑都测试了下,几台正常,几台出错)

代码如下:

Unit1.h

C/C++ code
//————————————————————————— #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

C/C++ code
//————————————————————————— #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 &brvbar &brvbar (dwBytesRead != dwFileSize)       
                  &brvbar &brvbar (pbmfh->bfType != * (WORD *) "BM")
                  &brvbar &brvbar (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)再试试。

引用 4 楼 jacknes009 的回复:
电脑无打印机噢。。搞不起来噢。。

可以用微软的虚拟打印机调试的

不知道为什么 我的电脑上 :

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补丁也可以解决!