none
SaveDC()、RestoreDC()は、ビューポート原点がサポートされないのでしょうか? RRS feed

  • 質問

  • ■質問事項

      1.SaveDC()、RestoreDC()は、ビューポート原点がサポート(保存、復元)されないのでしょうか?

      2.ビューポート原点がサポート(保存、復元)されない場合、SaveDC()、RestoreDC()がサポートしている/していない

         デバイスコンテキストの状態とは、なにが該当するか情報はないでしょうか?

    ■問題現象

      印刷処理を確認するために、添付のコードにて、2ページ目のTextOut()の印字位置は、(0,0)からとなることを期待しているが、(500,500)から印字される。

    ■開発環境

       ・Microsoft Visual C++ 2010 Express

       ・Windows XP

    ■確認した出力プリンタ

      ・Microsoft XPS Document Writer

     

    ■ソースコード

    #define MYOUTTEXT TEXT("PrintTest 20110606 SaveDC, RestoreDC...")

    VOID DoPrint2()
    {
        DOCINFO diInfo = {0};
        HDC hdc;
        INT iRetValue = 0;
        int iValSaveDC = 0;
        POINT pointTmp;
        COLORREF colorRefTmp;
        int iValMapMode = 0;

        diInfo.cbSize = sizeof (DOCINFO);
        diInfo.lpszDocName = TEXT("DocName_PrintTest20110606");

        if (!(hdc = CreateDC(NULL , TEXT("Microsoft XPS Document Writer") , NULL , NULL)))
        {
            return;
        }
        for(;;)
        {
            if (StartDoc(hdc , &diInfo) > 0)
            {
                ////////////////////////////////////////////////////////////////////////////////////////////
                //[1ページ目印刷]
                {
                    iValSaveDC = SaveDC(hdc);
                    if(iValSaveDC == 0)
                    {
                        break;
                    }
                    if(StartPage(hdc) > 0)
                    {
                        // 以前のマッピングモードには、MM_TEXT(1)が格納されます。
                        if((iValMapMode = SetMapMode(hdc , MM_LOMETRIC)) == 0)
                        {
                            break;
                        }
                        // 以前のテキストの色には、(0,0,0)が格納されます。
                        if((colorRefTmp = SetTextColor(hdc, RGB(255 , 0 , 0))) == CLR_INVALID)
                        {
                            break;
                        }
                        // 以前のビューポート原点には、(0,0)が格納されます。
                        (VOID)SetViewportOrgEx(hdc, 500, 500, &pointTmp);
                        // 印刷領域の(500,500)の位置から印刷されます。
                        TextOut(hdc , 0 , 0 , MYOUTTEXT , lstrlen(MYOUTTEXT));
                        EndPage(hdc);
                    }
                    else
                    {
                        break;
                    }
                    // 現在のビューポート原点には、(500,500)が返ります。
                    if(GetViewportOrgEx(hdc, &pointTmp) == FALSE)
                    {
                        break;
                    }
                    // 現在のテキストの色には、(255,0,0)が格納されます。
                    if((colorRefTmp = GetTextColor(hdc)) == CLR_INVALID)
                    {
                        break;
                    }
                    // 現在のマッピングモードには、MM_LOMETRIC(2)が格納されます。
                    if((iValMapMode = GetMapMode(hdc)) == 0)
                    {
                        break;
                    }
                    if(RestoreDC(hdc, iValSaveDC) == FALSE)
                    {
                        break;
                    }
                    // 現在のビューポート原点には、(0,0)が返ります。
                    if(GetViewportOrgEx(hdc, &pointTmp) == FALSE)
                    {
                        break;
                    }
                    // 現在のテキストの色には、(0,0,0)が格納されます。
                    if((colorRefTmp = GetTextColor(hdc)) == CLR_INVALID)
                    {
                        break;
                    }
                    // 現在のマッピングモードには、MM_TEXT(1)が格納されます。
                    if((iValMapMode = GetMapMode(hdc)) == 0)
                    {
                        break;
                    }
                }
                ////////////////////////////////////////////////////////////////////////////////////////////
                //[2ページ目印刷]
                {
                    iValSaveDC = SaveDC(hdc);
                    if(iValSaveDC == 0)
                    {
                        break;
                    }
                    if(StartPage(hdc) > 0)
                    {
                        // 現在のビューポート原点には、(0,0)が返ります。
                        (VOID)GetViewportOrgEx(hdc, &pointTmp);
                        // 印刷領域の(500,500)の位置から印刷されます。
                        // ※MM_TEXTを設定した場合は、(0,0)の位置から印刷されます。
                        TextOut(hdc , 0 , 0 , MYOUTTEXT , lstrlen(MYOUTTEXT));

                        EndPage(hdc);
                    }
                    else
                    {
                        break;
                    }
                    if(RestoreDC(hdc, iValSaveDC) == FALSE)
                    {
                        break;
                    }
                }
            }
            EndDoc(hdc);
            break;
        }

        DeleteDC(hdc);

    }


    • 編集済み tr160 2011年6月8日 14:37 「仲澤@失業者」様からの確認事項をソースコードに反映
    2011年6月7日 13:03

回答

  • あとは、同一ページ内でのSaveDC()、RestoreDC()を試してみて、
    StartPage()、EndPage()の嫌疑を晴らして(同じ様に異常な結果になる)
    やるだけですが、いずれにしてもプリンターのDCに対して
    両APIはマニュアルの記載通りには動作しないようですね。
    気になるのは、取得した設定情報(原点や色)と実際にプリントされる内容が異なる点ですが、
    どういった原因でこのような状態になっているのか判断しかねます。(vv;)。



    • 回答としてマーク tr160 2011年7月2日 10:36
    2011年6月9日 11:02
  • 提示されているSource Codeで試してみました。
    同じ現象になりますね。

    例えばMFCの場合、Page単位でDCの初期化をOnPrepareDCで行うようになっています。
    (Applicationによっては、OnDrawでも設定を行うかもしれません。)
    また、SaveDC/RestoreDCは使わずに処理を行っています。

    本現象の原因はわかりませんが、そういう仕様なのかもしれませんね。
    MFCみたくPageごとにDCの初期化を行う処理にした方がよいでしょう。

    補足です。
    > デバイスコンテキストの状態とは、なにが該当するか情報はないでしょうか?
    現在DCに選択されているGDI Objectと、以下のPageに記述されているDCの情報です。

    [Graphic Modes]
      http://msdn.microsoft.com/en-us/library/dd144961(v=VS.85).aspx

    • 編集済み kozz 2011年6月13日 11:58 補足
    • 回答としてマーク tr160 2011年7月2日 10:35
    2011年6月13日 10:53

すべての返信

  • 大昔のOS(3.x、95)ではStartPage()やEndPage()でHDCの設定がデフォルトに戻るという
    仕様でしたので、一般に印刷コードではページ先頭で必ずHDCの必要な属性を全て
    再設定する必要がありました。現在ではそのようなリセットは行われないという認識です。
    で、
    1.マップモードの設定は成功(0以外が戻る)しているのでしょうか(確認)。
    2.上が成功している場合、復帰はできているのでしょうかGetMapMode()(で確認)。
    3.SaveDC()、RestoreDC()の行を全てコメントアウトして、両ページとも
      500の位置に印刷されることを確認。そうならない場合は、StartPage()、
      EndPage()がHDCの状態を変更している可能性があり、印刷用のHDCには
     SaveDC()、RestoreDC()は有効に働かせることはできないということに なります。
    4.カラープリンタなら、文字の色を変えてはどうでしょう。
     色はリストアできるが、原点は戻らないのかもしれません。
    などと、テストしてみるのはどうでしょう。
    現在、残念ながら、実際にコードを動かしてみることがでない環境ですので、あしからず。


    2011年6月8日 1:45
  • 返信ありがとうございます。

    確認を行いました。
    「1~3」は意図した結果を得ています。
    「4」については、意図していない結果となりました。
    結論は『印刷用のHDCにはSaveDC()、RestoreDC()は有効に働かせることはできない』とする可能性が
    高いと感じていますが、いかがでしょうか?

    ■確認結果
    > 1.マップモードの設定は成功(0以外が戻る)しているのでしょうか(確認)。
    設定は、成功(0以外が戻る)していることを確認しました。

    > 2.上が成功している場合、復帰はできているのでしょうかGetMapMode()(で確認)。
    RestoreDC()後のマップモードを取得したところ、復帰していることを確認しました。

    > 3.SaveDC()、RestoreDC()の行を全てコメントアウトして、両ページとも
    >   500の位置に印刷されることを確認。そうならない場合は、StartPage()、
    >   EndPage()がHDCの状態を変更している可能性があり、印刷用のHDCには
    >   SaveDC()、RestoreDC()は有効に働かせることはできないということに なります。
    SaveDC()、RestoreDC()の行を全てコメントアウトして、両ページとも500の位置に印刷されることを確認しました。

    > 4.カラープリンタなら、文字の色を変えてはどうでしょう。
    >    色はリストアできるが、原点は戻らないのかもしれません。
    SetTextColor()を用いて文字の色を「赤」に変更しました。
    ・RestoreDC()後に、文字の色を取得したところ、変更前の文字の色「黒」でした。
    ・しかし、印刷結果において、2ページ目の文字の色は『赤』でした。
    結果、色もリストアできないことを確認しました。


    • 編集済み tr160 2011年6月8日 14:34 誤記修正
    2011年6月8日 14:33
  • あとは、同一ページ内でのSaveDC()、RestoreDC()を試してみて、
    StartPage()、EndPage()の嫌疑を晴らして(同じ様に異常な結果になる)
    やるだけですが、いずれにしてもプリンターのDCに対して
    両APIはマニュアルの記載通りには動作しないようですね。
    気になるのは、取得した設定情報(原点や色)と実際にプリントされる内容が異なる点ですが、
    どういった原因でこのような状態になっているのか判断しかねます。(vv;)。



    • 回答としてマーク tr160 2011年7月2日 10:36
    2011年6月9日 11:02
  • 提示されているSource Codeで試してみました。
    同じ現象になりますね。

    例えばMFCの場合、Page単位でDCの初期化をOnPrepareDCで行うようになっています。
    (Applicationによっては、OnDrawでも設定を行うかもしれません。)
    また、SaveDC/RestoreDCは使わずに処理を行っています。

    本現象の原因はわかりませんが、そういう仕様なのかもしれませんね。
    MFCみたくPageごとにDCの初期化を行う処理にした方がよいでしょう。

    補足です。
    > デバイスコンテキストの状態とは、なにが該当するか情報はないでしょうか?
    現在DCに選択されているGDI Objectと、以下のPageに記述されているDCの情報です。

    [Graphic Modes]
      http://msdn.microsoft.com/en-us/library/dd144961(v=VS.85).aspx

    • 編集済み kozz 2011年6月13日 11:58 補足
    • 回答としてマーク tr160 2011年7月2日 10:35
    2011年6月13日 10:53
  • 問題を調べる際の観点について、アドバイスありがとうございます。

     

    2011年7月2日 10:40
  • 返信ありがとうございます。

     

    kozzさんの回答「MFCでは、SaveDC/RestoreDCは使わずに処理を行っている」という情報から、

    なんらかの仕様によって、「SaveDC()、RestoreDC()は、ビューポート原点はサポートされない」という結論とし、クローズさせていただきます。

     

    今回、仕様がすべて公開されていない(情報が少ない)場合もあることを思い知りました。

     

    「仲澤@失業者」さん、「kozz」さん、感謝いたします。


    • 編集済み tr160 2011年7月2日 11:17 誤記修正
    2011年7月2日 11:06