说我有一个ASCII编码的文本文件mytextfile.txt
,我想打印它。
我在MSDN上找到了各种来源,但似乎都没有用:
来自here:
定义从Windows Forms应用程序打印时将输出发送到打印机的可重用对象。
public ref class PrintDocument : Component
但这仅适用于C ++(而非C)
我还发现this,它定义了几个功能,实际上似乎没有一个能够打印:
IPrintDocumentPackageStatusEvent
:表示打印作业的进度。
IPrintDocumentPackageTarget
:允许用户枚举受支持的包目标类型并创建具有给定类型ID的目标。 IPrintDocumentPackageTarget还支持跟踪包装打印进度和取消。
IPrintDocumentPackageTargetFactory
:与IPrintDocumentPackageTarget一起用于启动打印作业。
啊!看起来像!事实证明,这也适用于C ++:
IPrintDocumentPackageTargetFactory::CreateDocumentPackageTargetForPrintJob
我认为尝试模仿C类是不切实际的(而且很困难)。
我可以使用print
命令:
system("print mytextfile.txt");
但这似乎有点不合常理,是否有更好的方法来使用功能打印文件?
要澄清一下:我希望此打印在纸张而不是终端上。
答案 0 :(得分:3)
以下是一些适合您的示例打印代码,可以正确执行此工作。这是一个最小的,独立的示例,您应该可以编译并运行它。基于此,您应该能够使其适应您的特定需求。首先,这里是代码,然后是一些解释性注释。
请注意,我已将此内容编写为控制台应用程序,但这可能并不是您真正想要的。另外,现在可以根据要求从C调用完成所有工作的函数(print_file()
。 OK,这是代码:
#include <windows.h>
#include <conio.h>
#include <string>
#include <fstream>
#include <iostream>
#define SCALE_FACTOR 100 // percent
inline static int MM_TO_PIXELS (int mm, int dpi)
{
return MulDiv (mm * 100, dpi, 2540);
}
// Calculate the wrapped height of a string
static int calculate_wrapped_string_height (HDC hDC, int width, const std::string& s)
{
RECT r = { 0, 0, width, 16384 };
DrawText (hDC, s.c_str (), (int) s.length (), &r, DT_CALCRECT | DT_NOPREFIX | DT_WORDBREAK);
return (r.bottom == 16384) ? calculate_wrapped_string_height (hDC, width, " ") : r.bottom;
}
// Print a string in the width provided.
static void print_string (HDC hDC, int x, int y, int width, const std::string& s)
{
RECT r = { x, y, x + width, 16384 };
DrawText (hDC, s.c_str (), (int) s.length (), &r, DT_NOPREFIX | DT_WORDBREAK);
}
// Print page number. Returns (y + vertical space consumed)
static int print_pagenum (HDC hDC, int x, int y, int width, int& pagenum)
{
std::string hdr = "Page: " + std::to_string (++pagenum) + "\n";
int space_needed = calculate_wrapped_string_height (hDC, width, hdr);
print_string (hDC, x, y, width, hdr);
std::cout << "Printing page: " << pagenum << "\n";
return space_needed;
}
extern "C" bool print_file (const char *filename)
{
std::ifstream f;
f.open ("g:\\temp\\print_me.txt", std::ios_base::in);
if (!f)
{
std::cout << "Cannot open input file, error " << GetLastError () << "\n";
return false;
}
// Display print dialog
PRINTDLGEX pdex = { sizeof (pdex) };
PRINTPAGERANGE pr [10] = { };
HDC hDC;
pdex.hwndOwner = GetDesktopWindow ();
pdex.Flags = PD_ALLPAGES | PD_RETURNDC | PD_NOCURRENTPAGE | PD_NOSELECTION;
pdex.nMaxPageRanges = _countof (pr);
pdex.nPageRanges = 1;
pr [0].nFromPage = pr [0].nToPage = 1;
pdex.lpPageRanges = pr;
pdex.nMinPage = 1;
pdex.nMaxPage = 999999;
pdex.nCopies = 1;
pdex.nStartPage = START_PAGE_GENERAL;
HRESULT hr = PrintDlgEx (&pdex);
if (hr != S_OK)
{
std::cout << "PrintDlgEx failed, error " << GetLastError () << "\n";
return false;
}
if (pdex.dwResultAction == PD_RESULT_CANCEL)
return false;
hDC = pdex.hDC;
if (pdex.dwResultAction != PD_RESULT_PRINT)
{
DeleteDC (hDC);
return false;
}
// Only print what we need to
int max_page = 0x7fffffff;
if (pdex.Flags & PD_PAGENUMS)
{
max_page = 0;
for (int i = 0; i < (int) pdex.nPageRanges; ++i)
{
if ((int) pdex.lpPageRanges [i].nToPage > max_page)
max_page = pdex.lpPageRanges [i].nToPage;
}
}
constexpr int dpi = 96 * 100 / SCALE_FACTOR;
int lpx = GetDeviceCaps (hDC, LOGPIXELSX);
int lpy = GetDeviceCaps (hDC, LOGPIXELSX);
int res_x = GetDeviceCaps (hDC, HORZRES);
int res_y = GetDeviceCaps (hDC, VERTRES);
// margins
int left_margin = MM_TO_PIXELS (10, dpi);
int top_margin = MM_TO_PIXELS (20, dpi);
int right_margin = MM_TO_PIXELS (20, dpi);
int bottom_margin = MM_TO_PIXELS (20, dpi);
int width = MulDiv (res_x, dpi, lpx) - (left_margin + right_margin);
int y_max = MulDiv (res_y, dpi, lpy) - bottom_margin;
// Set up for SCALE_FACTOR
SetMapMode (hDC, MM_ANISOTROPIC);
SetWindowExtEx (hDC, dpi, dpi, NULL);
SetViewportExtEx (hDC, lpx, lpy, NULL);
SetStretchBltMode (hDC, HALFTONE);
DOCINFO di = { 0 };
di.cbSize = sizeof (di);
di.lpszDocName = "Stack Overflow";
int job_id = StartDoc (hDC, &di);
if (job_id <= 0)
{
std::cout << "StartDoc failed, error " << GetLastError () << "\n";
DeleteDC (hDC);
return false;
}
SetBkMode (hDC, TRANSPARENT);
LOGFONT lf = { 0 };
lf.lfWeight = FW_NORMAL;
lf.lfHeight = -12;
HFONT hTextFont = CreateFontIndirect (&lf);
HFONT hOldFont = (HFONT) GetCurrentObject (hDC, OBJ_FONT);
SelectObject (hDC, hTextFont);
int x = left_margin;
int y = top_margin;
int pagenum = 0;
int err = StartPage (hDC);
if (err <= 0)
{
std::cout << "StartPage failed, error " << GetLastError () << "\n";
DeleteDC (hDC);
return false;
}
y += print_pagenum (hDC, x, y, width, pagenum);
// Printing loop, per line
for ( ; ; )
{
if (_kbhit ())
{
AbortDoc (hDC);
break;
}
std::string line;
std::getline (f, line);
if (!f)
break;
int space_needed = calculate_wrapped_string_height (hDC, width, line);
if (space_needed > y_max - y)
{
if (pagenum >= max_page)
break;
if (EndPage (hDC) < 0 || StartPage (hDC) < 0)
break;
y = top_margin;
y += print_pagenum (hDC, x, y, width, pagenum);
}
print_string (hDC, x, y, width, line);
y += space_needed;
}
EndPage (hDC);
EndDoc (hDC);
SelectObject (hDC, hOldFont);
DeleteObject (hTextFont);
DeleteDC (hDC);
return true;
}
// main
int main ()
{
bool ok = print_file ("g:\\temp\\print_me.txt");
return !ok;
}
注释:
该代码显示如何正确分页输出。我在他的打印输出中包括页码,只是为了好玩。
输入文件名是硬编码的。请根据您的需求进行调整。
正如我所说,这是作为控制台应用程序编写的。如果要在Windows应用程序中包括此功能,则将使用其他父窗口句柄和其他机制(通常是无模式对话框)来报告进度并允许用户取消打印作业。
编写的代码期望被编译为ANSI(纯粹为了方便)。我确定您可以解决此问题。
此代码不能正确处理用户在Windows标准“打印”对话框中输入的页面范围。我把它留给读者练习。
要使此代码可从C调用,请将其编译为单独的.cpp文件(当然不包括main
),然后将原型print_file
(在
单独的.h文件)为:
extern "C" bool print_file (const char *filename);
然后#将此文件同时包含在.cpp文件和.c文件中。
请注意,bool
是预定义类型-在C99和更高版本中为-,请参见:
答案 1 :(得分:1)
您可以读取一行,循环打印一行,直到EOF
编辑后输出到打印机
Xamarin.Forms.ContentPage