CPrintDialogの設定の保存・復元


ひる  2011-09-15 20:27:11  No: 72913  IP: [192.*.*.*]

MFCダイアログベースのアプリケーションで、
CPrintDialogを使って印刷機能を実装したものがあります。

ここで、そのCPrintDialogで選択された設定を、
次回印刷時の初期値として復元するという機能を載せたいと思っています。
保存場所はレジストリやINIファイルを考えています。

この場合、どのような情報を取得して保存し、
どのようにCPrintDialogに復元してやることになるのでしょうか?

DEVMODEとかを使うのかなとは思っているのですが、
具体的な方法をなかなか見つけられないため、質問させていただきます。

編集 削除
gak  2011-09-16 13:33:46  No: 72914  IP: [192.*.*.*]

色んなとこからソース切り貼り+整形+ビルド通してない+実行していない、なコードなので参考程度に。
# 力技になっちゃった気もする…もっと簡単な方法があるかも知れない

extern myCWinApp theApp;

bool save(PRINTDLG &pd) {
    if (pd.hDevMode == NULL) {
        return false;
    }
    LPDEVMODE p = LPDEVMODE(::GlobalLock(pd.hDevMode));
    // 今のプリンタ名記憶
    theApp.WriteProfileString(_T("printer"), _T("name"), LPCTSTR(p->dmDeviceName));
    // 例えば用紙サイズ記憶
    theApp.WriteProfileInt(_T("printer"), _T("papersize"), p->dmPaperSize);
    // 例えば給紙方法記憶
    theApp.WriteProfileInt(_T("printer"), _T("defaultsource"), p->dmDefaultSource);
    // 例えば用紙向き記憶
    theApp.WriteProfileInt(_T("printer"), _T("orientation"), p->dmOrientation);
    ::GlobalUnlock(pd.hDevMode);
    return true;
}

bool load(PRINTDLG &pd) {
    bool result = false;
    HANDLE printer;
    if (::OpenPrinter(theApp.GetProfileString(_T("printer"), _T("name")), &printer, NULL)) {
        DWORD length;
        ::GetPrinter(printer, 2, NULL, 0, &length);
        std::vector<BYTE> buffer(length);
        if (::GetPrinter(printer, 2, &buffer[0], length, &length)) {
            LPPRINTER_INFO_2 info = LPPRINTER_INFO_2(&buffer[0]);
            // DEVNAMES 作る
            HGLOBAL devnames;
            {
                const int driverLen = _tcslen(info->pDriverName) + 1;
                const int printerLen = _tcslen(info->pPrinterName) + 1;
                const int portLen = _tcslen(info->pPortName) + 1;
                devnames = ::GlobalAlloc(GHND, sizeof(DEVNAMES) + sizeof(TCHAR) * (driverLen + printerLen + portLen));
                LPDEVNAMES p = LPDEVNAMES(::GlobalLock(devnames));
                p->wDriverOffset = sizeof(DEVNAMES) / sizeof(TCHAR);
                p->wDeviceOffset = p->wDriverOffset + driverLen;
                p->wOutputOffset = p->wDeviceOffset + printerLen;
                p->wDefault = 0;
                _tcscpy(LPTSTR(p) + p->wDriverOffset, info->pDriverName);
                _tcscpy(LPTSTR(p) + p->wDeviceOffset, info->pPrinterName);
                _tcscpy(LPTSTR(p) + p->wOutputOffset, info->pPortName);
                ::GlobalUnlock(devnames);
            }
            // DEVMODE 作る
            HGLOBAL devmode;
            {
                devmode = ::GlobalAlloc(GHND, info->pDevMode->dmSize + info->pDevMode->dmDriverExtra);
                LPDEVMODE p = LPDEVMODE(::GlobalLock(devmode));
                memcpy(p, info->pDevMode, info->pDevMode->dmSize + info->pDevMode->dmDriverExtra);
                // 例えば用紙サイズ復元
                p->dmPaperSize = theApp.GetProfileInt(_T("printer"), _T("papersize"), p->dmPaperSize);
                // 例えば給紙方法復元
                p->dmDefaultSource = theApp.GetProfileInt(_T("printer"), _T("defaultsource"), p->dmDefaultSource);
                // 例えば用紙向き復元
                p->dmOrientation = theApp.GetProfileInt(_T("printer"), _T("orientation"), p->dmOrientation);
                ::GlobalUnlock(devmode);
            }
            ::GlobalFree(pd.hDevMode);
            ::GlobalFree(pd.hDevNames);
            pd.hDevMode = devmode;
            pd.hDevNames = devnames;
            result = true;
        }
        ::ClosePrinter(printer);
    }
    return result;
}

xxxx {
    CPrintDialog dlg(TRUE);
    load(dlg.m_pd);
    dlg.DoModal();
    save(dlg.m_pd);
}

編集 削除
gak  2011-09-16 14:05:01  No: 72915  IP: [192.*.*.*]

> devnames = ::GlobalAlloc(GHND, sizeof(DEVNAMES) + sizeof(TCHAR) * (driverLen + printerLen + portLen));
> LPDEVNAMES p = LPDEVNAMES(::GlobalLock(devnames));
> p->wDriverOffset = sizeof(DEVNAMES) / sizeof(TCHAR);
この部分は↓の方が多分安全だわ。

const int offset = (sizeof(DEVNAMES) + (sizeof(TCHAR) - 1)) / sizeof(TCHAR);
devnames = ::GlobalAlloc(GHND, sizeof(TCHAR) * (offset + driverLen + printerLen + portLen));
LPDEVNAMES p = LPDEVNAMES(::GlobalLock(devnames));
p->wDriverOffset = offset;

編集 削除
ひる  2011-09-20 11:09:09  No: 72916  IP: [192.*.*.*]

詳細なサンプルありがとうございます。参考にさせていただきます。
OpenPrinterやGetPrinterなどの関数は全くの未経験です。
このへんの処理は基本的にAPIレベルでやっていかないといけないのですね。

編集 削除