Windows 10 標準装備の仮想プリンタ Microsoft Print to PDF ですが、作成されるPDFファイル名をアプリケーションプログラムのコードから指定できないか探していたところ、以下を見つけました。
How to programmatically print to PDF file without prompting for filename in C# using the Microsoft Print To PDF printer that comes with Windows 10
C/C++ から Windwos API を直接呼び出している場合は、CreateDC の第3パラメータ DOCINFO 構造体の3つ目のメンバ lpszOutput にデフォルトの "PORTPROMPT:" ではなく出力したいファイル名を指定すればいいです。
DOCINFO di = { sizeof(di), "テストDocName" }; di.lpszOutput = "C:\\HOGE\\HOGEHOGE.PDF";
OWLNext の場合は、TPrinter インスタンスにメンバ関数 GetData を呼び出して取得する TPrintDialog::TData クラスインスタンスに SetDevNames で設定するときの第3パラメータに、出力したいファイル名を指定すればいいです。OWLNext はそのデータを元に TCreatedDC::TCreatedDC にて、Windows API 関数 CreateDC を呼び出すようになっています。
TPrinter printer; printer.GetData()->SetDevNames("winspool", "Microsoft Print to PDF", "C:\\HOGE\\HOGEHOGE.PDF");
VC141 + OWLNext6.44.2 で動作するサンプルコードができましたので載せておきます。
// <pdf.cpp> // Copyright 2018 Perce-neige https://perce-neige.hateblo.jp/ // Copyright を削除しない限り、ご自由にお使いください #define _USE_MATH_DEFINES // <cmath> にて M_PI を定義してもらう #define _OWLPCH #include <owl/pch.h> #pragma hdrstop #include <owl/printer.h> // owl::TPrintout #include <owl/printdia.h> // owl::TPrintDialog #include <owl/applicat.h> // owl::TApplication #include <owl/framewin.h> // owl::TFrameWindow #include <owl/menu.h> // owl::TMenu #include <windows.h> #include <algorithm> // std::min #include <cmath> // std::sin #include <memory> // std::unique_ptr #include <string> // std::string #include "pdf.rh" // リソースID定義 class TMyPrintOut : public owl::TPrintout { public: TMyPrintOut(const char* title) : owl::TPrintout(title) {} // 1ページだけ void GetDialogInfo(int& minPage, int& maxPage, int& selFromPage, int& selToPage) { minPage = maxPage = selFromPage = selToPage = 1; } bool HasPage(int pageNumber) { return pageNumber == 1; } void BeginPage(owl::TRect& clientR); void PrintPage(int page, owl::TRect& bandRect, unsigned flags); }; void TMyPrintOut::BeginPage(owl::TRect& clientRect) { DC->SetMapMode(MM_ANISOTROPIC); DC->SetViewportExt(PageSize); // 印字可能サイズ [mm] owl::TSize printableSize(DC->GetDeviceCaps(HORZSIZE), DC->GetDeviceCaps(VERTSIZE)); // スケーリング: これで以降論理単位が 0.1mm となる owl::TSize windowExtt(printableSize.cx * 10, printableSize.cy * 10); DC->SetWindowExt(windowExtt); // clientRect.left = clientRect.top = 0; clientRect.right = clientRect.left + windowExtt.cx; clientRect.bottom = clientRect.top + windowExtt.cy; } // サンプルのページ描画 void TMyPrintOut::PrintPage(int /*page*/, owl::TRect& /*bandRect*/, unsigned /*flags*/) { owl::TRect clientRect; BeginPage(clientRect); DC->MoveTo(clientRect.left, clientRect.bottom / 2); DC->LineTo(clientRect.right, clientRect.bottom / 2); DC->MoveTo(clientRect.right / 2, clientRect.bottom); DC->LineTo(clientRect.right / 2, clientRect.top); double r = std::min(clientRect.right, clientRect.bottom) / 4; // カージオイド を (3/2)π 回転したもの // 媒介変数 t を -π <= t <= π で動かす int n = int(M_PI * r); for (int i = -n; i <= n; i++) { double t = i * M_PI / n; double c = std::cos(t); double s = std::sin(t); int dx = int(r * (1 + c) * (-s)); int dy = int(r * (1 + c) * c); int x = int(clientRect.right / 2 + dx); int y = int(clientRect.bottom / 2 + dy); if (i == -n) DC->MoveTo(x, y); else DC->LineTo(x, y); } } class TMyFrame : public owl::TFrameWindow { public: TMyFrame(const char* name) : owl::TFrameWindow(0, name) {} private: void CmOutputPDF(); DECLARE_RESPONSE_TABLE(TMyFrame); }; DEFINE_RESPONSE_TABLE1(TMyFrame, owl::TFrameWindow) EV_COMMAND(CM_OUTPUTPDF, CmOutputPDF), END_RESPONSE_TABLE; void TMyFrame::CmOutputPDF() { try { std::string driver = "winspool"; std::string device = "Microsoft Print to PDF"; std::string port = "C:\\WORK\\PDFOWL.PDF"; // ### 出力PDFファイル名 // owl::TPrinter printer; printer.GetData()->SetDevNames(driver.c_str(), device.c_str(), port.c_str()); TMyPrintOut printOut("PDF出力テスト"); printer.Print(this, printOut, false); } catch (const std::exception& x) { MessageBox(x.what(), "エラー", MB_OK | MB_ICONERROR); } catch (...) { MessageBox("想定外の例外です。", "エラー", MB_OK | MB_ICONERROR); } } class TMyApp : public owl::TApplication { public: TMyApp(const char* title) : owl::TApplication(title), Title(title) {} private: void InitMainWindow() { std::unique_ptr<owl::TFrameWindow> mainWindow(new TMyFrame(Title.c_str())); mainWindow->SetMenuDescr(owl::TMenuDescr(MAIN_MENU, 1, 0, 0, 0, 0, 0)); SetMainWindow(mainWindow.release()); } std::string Title; }; int OwlMain(int /*argc*/, char** /*argv*/) { TMyApp("PDF出力テスト").Run(); return 0; }
// <pdf.rh> #define MAIN_MENU 10000 #define CM_OUTPUTPDF 10100
// <pdf.rc> #include "pdf.rh" #include <owl/window.rh> #include <owl/except.rc> #include <owl/printer.rc> MAIN_MENU MENU { POPUP "ファイル(&F)" { MENUITEM "PDF出力(&P)", CM_OUTPUTPDF MENUITEM "終了(&X)", CM_EXIT } }
CMakeLists.txt は https://perce-neige.hateblo.jp/entry/2018/10/25/214023 にあります。