GDI中StartDoc函数32位正常,64位抛异常问题咨询
64位编译下调用
StartDoc触发异常但程序仍能正常运行的问题 在Visual Studio 2019环境下,我使用以下C++代码将JPEG图片打印到PDF文档:
// sdk #include <string> #include <memory> // windows #include <Windows.h> #include <Winspool.h> #include <gdiplus.h> #pragma comment (lib, "Gdiplus.lib") // resources #include "Resource.h" //------------------------------------------------------------------------------ HWND g_hWnd = nullptr; HWND g_hPrintBtn = nullptr; //------------------------------------------------------------------------------ void PrintToPDF(); //------------------------------------------------------------------------------ LRESULT CALLBACK WindowProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam) { switch (uMsg) { case WM_CLOSE: PostQuitMessage(0); break; case WM_DESTROY: return 0; case WM_COMMAND: // search for the pressed button if (g_hPrintBtn == reinterpret_cast<HWND>(lParam)) PrintToPDF(); break; default: return DefWindowProc(hWnd, uMsg, wParam, lParam); } return 0; } //------------------------------------------------------------------------------ HWND CreateButton(const RECT& clientRect, const std::wstring& caption, LONG pos) { // create button return ::CreateWindow(L"BUTTON", caption.c_str(), WS_TABSTOP | WS_VISIBLE | WS_CHILD | BS_DEFPUSHBUTTON, clientRect.left + 3, clientRect.bottom - ((25 * pos) + 3), (clientRect.right - clientRect.left) - 6, 25, g_hWnd, nullptr, (HINSTANCE)GetWindowLongPtr(g_hWnd, GWLP_HINSTANCE), nullptr); } //--------------------------------------------------------------------------- HBITMAP LoadJpgImage(const std::wstring& fileName) { HBITMAP hBitmap = nullptr; // initialize GDI+ Gdiplus::GdiplusStartupInput gdiplusStartupInput; ULONG_PTR gdiplusToken; Gdiplus::GdiplusStartup(&gdiplusToken, &gdiplusStartupInput, nullptr); // load the .jpg image std::unique_ptr<Gdiplus::Bitmap> pBitmap = std::make_unique<Gdiplus::Bitmap>(fileName.c_str()); // check if the image is loaded successfully if (pBitmap->GetLastStatus() == Gdiplus::Ok) { Gdiplus::Status result = pBitmap->GetHBITMAP(Gdiplus::Color::Transparent, &hBitmap); // free resources pBitmap.reset(); } else // error handling if image loading fails ::MessageBoxW(nullptr, L"Failed to load image.", L"Error", MB_OK | MB_ICONERROR); // shutdown GDI+ Gdiplus::GdiplusShutdown(gdiplusToken); return hBitmap; } //------------------------------------------------------------------------------ HDC GetPrinterDC(const std::wstring& printerName) { HDC hDC = ::CreateDC(NULL, printerName.c_str(), NULL, NULL); if (!hDC) return nullptr; return hDC; } //------------------------------------------------------------------------------ void PrintToPDF() { HBITMAP hBitmap = LoadJpgImage(L"..\\PrintToPDF\\Resources\\Coffee.jpg"); BITMAP bm; ::GetObject(hBitmap, sizeof(BITMAP), &bm); const std::size_t bmWidth = bm.bmWidth; const std::size_t bmHeight = bm.bmHeight; HDC hDC = GetPrinterDC(L"Microsoft Print to PDF"); const std::size_t cxPage = ::GetDeviceCaps(hDC, HORZRES); const std::size_t cyPage = ::GetDeviceCaps(hDC, VERTRES); ::DOCINFO di; di.cbSize = sizeof(DOCINFO); di.lpszDocName = L"INVOICE TABLE : Printing..."; di.lpszOutput = L"..\\PrintToPDF\\Printed docs\\MyDoc.pdf"; ::StartDoc(hDC, &di); ::StartPage(hDC); HDC hDcMem = ::CreateCompatibleDC(hDC); ::SelectObject(hDcMem, hBitmap); ::BitBlt(hDC, (int)((cxPage - bmWidth) / 2), (int)((cyPage - bmHeight) / 2), 4032, 3024, hDcMem, 0, 0, SRCCOPY); ::DeleteDC(hDcMem); ::EndPage(hDC); ::EndDoc(hDC); ::DeleteDC(hDC); } //------------------------------------------------------------------------------ int APIENTRY wWinMain(_In_ HINSTANCE hInstance, _In_opt_ HINSTANCE hPrevInstance, _In_ LPWSTR lpCmdLine, _In_ int nCmdShow) { WNDCLASSEX wcex = {}; MSG msg = {}; BOOL bQuit = FALSE; // register the window class wcex.cbSize = sizeof(WNDCLASSEX); wcex.style = CS_OWNDC; wcex.lpfnWndProc = WindowProc; wcex.cbClsExtra = 0; wcex.cbWndExtra = 0; wcex.hInstance = hInstance; wcex.hIcon = ::LoadIcon(hInstance, MAKEINTRESOURCE(IDI_APPICON)); wcex.hIconSm = ::LoadIcon(hInstance, MAKEINTRESOURCE(IDI_SMALL)); wcex.hCursor = ::LoadCursor(NULL, IDC_ARROW); wcex.hbrBackground = (HBRUSH)::GetStockObject(BLACK_BRUSH); wcex.lpszMenuName = NULL; wcex.lpszClassName = L"PrintToPDF"; if (!::RegisterClassEx(&wcex)) return 0; // create the main window g_hWnd = ::CreateWindowEx(0, L"PrintToPDF", L"Print to PDF", WS_OVERLAPPEDWINDOW, CW_USEDEFAULT, CW_USEDEFAULT, 800, 650, NULL, NULL, hInstance, NULL); ::ShowWindow(g_hWnd, nCmdShow); RECT clientRect; ::GetClientRect(g_hWnd, &clientRect); g_hPrintBtn = CreateButton(clientRect, L"Print to PDF", 1); // application main loop while (!bQuit) { // check for messages if (::PeekMessage(&msg, NULL, 0, 0, PM_REMOVE)) { // handle or dispatch messages if (msg.message == WM_QUIT) bQuit = TRUE; else { ::TranslateMessage(&msg); ::DispatchMessage(&msg); } } else { ::Sleep(10); } } // destroy the window explicitly ::DestroyWindow(g_hWnd); return (int)msg.wParam; } //------------------------------------------------------------------------------
上述代码在32位(x86)编译执行时完全正常,但在64位(x64)编译执行时会抛出如下异常:

如截图所示,异常在调用::StartDoc()函数时触发。若继续执行程序(按下F5),图片仍能按预期打印到PDF文档,且无其他错误。
我无法找出原因,能否有人指出我哪里出错了?
编辑1
这是一个已知的旧问题,相关反馈显示这是调试器捕获的驱动内部异常,而非代码本身问题。我是否应忽略该问题,或是有已知的解决方案?
解决方案
这个异常确实是Microsoft Print to PDF驱动在64位调试环境下的兼容性问题,你的代码本身没有错误:
- 该异常是调试器捕获到的驱动内部错误,不会影响程序的实际运行逻辑,PDF能正常生成就是直接证明。
- 可以通过以下方式解决调试时的异常提示:
- 在Visual Studio的「调试」→「窗口」→「异常设置」中,找到Win32异常类别,勾选"Element not found"(错误代码
0x80070490),或者直接添加规则忽略Print.PrintSupport.Source.dll抛出的异常。 - 升级Visual Studio到更高版本(比如2022),微软后续版本可能修复了调试器与该打印驱动的兼容性问题。
- 如果不需要调试打印流程,直接切换到Release模式编译运行,调试器不会触发该异常提示。
- 在Visual Studio的「调试」→「窗口」→「异常设置」中,找到Win32异常类别,勾选"Element not found"(错误代码
内容的提问来源于stack exchange,提问作者Jean-Milost Reymond
相关产品推荐
相关产品推荐

