MFC 打印图片 dc.EndDoc(); 并没有释放怎么办? 原因:打印到pdf才会出现,打印到真实打印机就正常

文章讲述了在MFC应用程序中使用CDC的StartDoc和EndDoc方法进行打印任务时,如何正确管理资源并防止内存泄漏。特别关注了EndDoc方法未能释放资源导致的内存增加问题及其解决策略。
摘要由CSDN通过智能技术生成

最后找到原因:打印到pdf才会出现,打印到真实打印机就正常

MFC释放资源 BOOL bPrintingOK = dc.StartDoc(&di);

在MFC (Microsoft Foundation Classes) 应用程序中,当你使用 CDC::StartDoc 方法开始一个打印任务时,如果该任务成功开始,则需要确保在任务完成后正确地结束打印任务,并且释放与之相关的资源。CDC::StartDoc 成功返回一个正值表示打印任务已经开始,这时你应该在打印完成后调用 CDC::EndDoc 方法来结束打印任务。如果在打印过程中遇到需要取消打印的情况,应该调用 CDC::AbortDoc

下面是如何根据 StartDoc 的返回值来处理资源释放的一个示例:

// 假设 di 是一个已经正确配置的 CPrintInfo 对象
// 并且 dc 是一个准备好的打印设备上下文(CDC 对象)
BOOL bPrintingOK = dc.StartDoc(&di);

if (bPrintingOK > 0) {
    // 打印任务成功开始
    // 进行打印操作...
    
    // 假设打印操作成功完成
    if (/* 打印成功 */) {
        dc.EndDoc(); // 正常结束打印任务
    } else {
        // 如果打印过程中发生错误,取消打印任务
        dc.AbortDoc();
    }
} else {
    // StartDoc 失败,处理错误
}

// 释放与 CDC 相关的资源
// 如果是通过 CWnd::GetDC 获得的 CDC 对象,则需要调用 CWnd::ReleaseDC
// 如果 CDC 对象是动态创建的(通过 new),则需要在适当的时候删除它
// 如果是函数内局部变量或类的成员,通常不需要手动释放,除非你手动调用了 CreateDC 或 CreateIC 创建了设备上下文

这里的关键点是,在使用 StartDoc 开始打印任务后,根据打印任务的结果(成功或失败),使用 EndDocAbortDoc 来正确结束或取消任务。这样做是为了确保资源被适当管理,并且打印作业能够正确地在操作系统中被关闭。

此外,对于通过 GetDC 获得的 CDC 对象,你需要使用 ReleaseDC 来释放。如果你是通过 new 创建的 CDC 对象,则需要使用 delete 来手动释放。如果 CDC 对象是自动变量或类的成员变量,那么当它们的作用域结束或类被销毁时,它们会自动被释放。

MFC dc.EndDoc(); 并没有释放怎么办?

在这里插入图片描述
如果你调用了 dc.EndDoc() 来结束一个打印任务,但感觉资源并没有被释放,这里有几个可能的原因和解决方案:

1. 确认资源未释放的具体表现

首先,确认“资源未释放”的具体表现是什么。是内存没有回收,还是某些设备上下文(DC)或GDI对象(如字体、位图等)没有被释放?这有助于确定问题的根源。

2. 检查其它资源的释放

dc.EndDoc() 只负责结束打印文档,它并不直接负责释放所有与设备上下文相关联的资源。如果你在打印过程中创建了GDI对象(如字体、位图等),你需要确保自己释放这些资源。例如,如果你使用 CreateFont 创建了一个字体并将其选入DC中,你需要在不再需要它时调用 DeleteObject 来释放它。

3. 确保正确使用 CDC 对象

如果你是通过 CWnd::GetDC() 获得 CDC 对象的,确保在结束打印任务后调用 CWnd::ReleaseDC() 来释放它。如果是通过 new 动态创建的 CDC 对象,确保在结束使用后用 delete 来释放它。

4. 使用智能指针管理资源

为了避免资源泄漏,你可以考虑使用智能指针(如 std::unique_ptrstd::shared_ptr)来管理动态分配的资源,这样即使发生异常也能保证资源的正确释放。

5. 检查设备驱动程序

如果你确定代码中已正确处理了所有资源的释放,但仍然存在问题,问题可能出在设备驱动程序上。确保打印机和图形设备的驱动程序是最新的,有时旧的或不兼容的驱动程序会导致资源管理问题。

6. 使用诊断工具

使用Visual Studio的诊断工具(如诊断会话窗口、性能分析器)来跟踪资源使用情况和潜在的泄漏。这些工具可以帮助你识别程序中的资源泄漏。

7. 联系技术支持

如果问题仍然无法解决,考虑联系微软的技术支持或在相关开发者社区(如Stack Overflow)寻求帮助,可能有经验丰富的开发者遇到过类似的问题。

记得,资源管理是开发过程中一个重要的方面,确保资源正确释放是防止内存泄漏和其它资源问题的关键。

图片的加载与释放已经成功了。打印机这里BOOL bPrintingOK = dc.StartDoc(&di);新增的还没释放。

		memDC.SelectObject(pBmp); //选回原来的
		bPrintingOK = (dc.EndPage() > 0);   // end page
		if (memDC.GetSafeHdc() != NULL) //释放
		{
			memDC.DeleteDC();
			bitmap.DeleteObject();
		}

把图片全删了试试

调用之前
在这里插入图片描述
调用BOOL bPrintingOK = dc.StartDoc(&di);之后
在这里插入图片描述
调用dc.EndDoc();之后 没变。
函数退出也没变,多出近8M,应该减少到调用前相近大小
没有打印图片,函数退出也没变,多出近8M,应该减少到调用前相近大小。

MFC调用打印函数后,内存增加,退出打印函数后内存增加了8M,怎么办?

内存在调用打印函数后增加了8MB,退出打印函数后没有释放,可能是因为资源没有被正确管理或释放。处理这类内存增加问题时,可以采取以下步骤来诊断和解决问题:

1. 确认内存增加的原因

  • 资源未释放:确认是否所有创建的GDI对象(如位图、字体等)和动态分配的内存都被正确释放。
  • 资源泄漏检测:使用Visual Studio的诊断工具(例如,内存使用情况工具、性能剖析器)来检测内存泄漏。

2. 使用RAII原则管理资源

确保使用资源获取即初始化(RAII)原则管理所有资源。对于GDI对象和其他系统资源,当对象离开作用域时,应自动释放这些资源。在C++中,可以通过自定义的封装类或智能指针(如std::unique_ptr,配合自定义删除器)来实现。

3. 代码审查

  • 审查创建和释放资源的代码:确保每个new都有对应的delete,每个Create函数调用(如CreatePenCreateFont等)都有对应的DeleteObject
  • 避免重复创建资源:在打印循环中重复创建而不释放资源,会导致内存迅速增加。

4. 使用MFC诊断功能

MFC提供了一套诊断功能来帮助开发者发现资源泄漏。可以在程序开始处定义_CrtSetDbgFlag来启用这些诊断功能,它会在程序退出时报告内存泄漏。

#define _CRTDBG_MAP_ALLOC
#include <stdlib.h>
#include <crtdbg.h>

#ifdef _DEBUG
   _CrtSetDbgFlag ( _CRTDBG_ALLOC_MEM_DF | _CRTDBG_LEAK_CHECK_DF );
#endif

5. 分析内存使用

使用第三方内存分析工具(如Valgrind,Visual Leak Detector等)来分析程序的内存使用情况,找出内存泄漏的具体位置。

6. 优化打印逻辑

  • 减少不必要的打印预览和计算:打印预览和页面布局计算可能会消耗大量资源,确保这些操作只在必要时执行。
  • 重用GDI对象:如果可能,重用GDI对象而不是在每次打印时都创建新的对象。

7. 搜索类似问题的解决方案

在开发者社区(如Stack Overflow,Microsoft Developer Network)搜索是否有类似问题的讨论和解决方案,有时候可以找到具体的解决思路或代码示例。

处理这类问题可能需要一些时间和耐心,通过细致的排查和逐步缩小问题范围,通常能够找到导致内存增加的原因,并采取相应的措施解决。

  • 18
    点赞
  • 28
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
使用pdfium库将pdf文件发送到打印机打印的方法如下: 1. 安装pdfium库,并使用C++代码读取pdf文件。 2. 将pdf文件转换为打印作业,可以使用Windows API中的Print Spooler API或者CUPS API。 3. 使用Print Spooler API或者CUPS API发送打印作业到打印机打印。 下面是一个简单的例子,演示如何使用pdfium库将pdf文件发送到打印机打印: ```c++ #include <stdio.h> #include <stdlib.h> #include <string.h> #include "fpdfview.h" #include "fpdf_doc.h" #include "fpdf_save.h" #ifdef _WIN32 #include <windows.h> #endif int main(int argc, char* argv[]) { // 读取pdf文件 FPDF_DOCUMENT doc = FPDF_LoadDocument("test.pdf", NULL); if (!doc) { printf("Error: cannot load PDF file.\n"); return 1; } // 转换为打印作业 FPDF_PRINT_SETTINGS print_settings; memset(&print_settings, 0, sizeof(print_settings)); print_settings.header = NULL; print_settings.footer = NULL; print_settings.bFitToPage = TRUE; print_settings.bPrintAsImage = FALSE; FPDF_DOCUMENT_OUTPUT_SETTINGS output_settings = {0, 0, 0, 0, NULL, &print_settings}; int num_pages = FPDF_GetPageCount(doc); for (int i = 0; i < num_pages; i++) { FPDF_PAGE page = FPDF_LoadPage(doc, i); if (!page) { printf("Error: cannot load page %d.\n", i); continue; } FPDF_PrintPage(page, &output_settings); FPDF_ClosePage(page); } // 发送到打印机打印 #ifdef _WIN32 // Windows平台使用Print Spooler API发送打印作业到打印机 HDC printer_dc = CreateDC(NULL, TEXT("Microsoft Print to PDF"), NULL, NULL); if (!printer_dc) { printf("Error: cannot create printer device context.\n"); return 1; } DOCINFO doc_info; memset(&doc_info, 0, sizeof(doc_info)); doc_info.cbSize = sizeof(doc_info); doc_info.lpszDocName = TEXT("test.pdf"); if (StartDoc(printer_dc, &doc_info) == SP_ERROR) { printf("Error: cannot start print job.\n"); DeleteDC(printer_dc); return 1; } if (StartPage(printer_dc) <= 0) { printf("Error: cannot start print page.\n"); EndDoc(printer_dc); DeleteDC(printer_dc); return 1; } FPDF_DOCUMENT pdf_doc = FPDF_LoadDocument("test.pdf", NULL); if (!pdf_doc) { printf("Error: cannot load PDF file.\n"); EndPage(printer_dc); EndDoc(printer_dc); DeleteDC(printer_dc); return 1; } num_pages = FPDF_GetPageCount(pdf_doc); for (int i = 0; i < num_pages; i++) { FPDF_PAGE page = FPDF_LoadPage(pdf_doc, i); if (!page) { printf("Error: cannot load page %d.\n", i); continue; } FPDF_RenderPage(printer_dc, page, 0, 0, 0, 0, FPDF_ROTATE_0, FPDF_PRINTING); FPDF_ClosePage(page); } FPDF_CloseDocument(pdf_doc); if (EndPage(printer_dc) <= 0) { printf("Error: cannot end print page.\n"); EndDoc(printer_dc); DeleteDC(printer_dc); return 1; } if (EndDoc(printer_dc) == SP_ERROR) { printf("Error: cannot end print job.\n"); DeleteDC(printer_dc); return 1; } DeleteDC(printer_dc); #else // Linux和macOS平台使用CUPS API发送打印作业到打印机 // TODO: 实现使用CUPS API发送打印作业到打印机的代码 #endif // 释放资源 FPDF_CloseDocument(doc); return 0; } ``` 注意:具体的打印操作需要根据操作系统和打印机类型来确定。在Windows中,可以使用Print Spooler API发送打印作业到打印机;在Linux和macOS中,可以使用CUPS API发送打印作业到打印机
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

小黄人软件

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值