none
GDIに渡せる座標の最大値、最小値はいくらなのでしょう。 RRS feed

  • 質問

  • いまさらの話題で申し訳ないのですがGDIについての疑問です。

    GDIで使用する座標は一般にPOINT{long x,long y}等、longなのですが、
    このメンバx、yの最大値は、LONG_MAX、LONG_MINではなく、2^27だそうです。これより

    const long GDI_MAX_VALUE = long( 0x07FFFFFF);
    const long GDI_MIN_VALUE = long( 0xF8000000);

    などとシーリングしてたのですが、最近負側のY座標=0xF8000089付近でエラーになりました。
    LineTo()の戻り値は0、GetLastError()=87(ERROR_INVALID_PARAMETER)となりました。
    では

    Q1.GDIに渡せる座標の最大、最小値はいったいいくつなのでしょう。
    Q2.それが書かれている、できたら公式なドキュメントはありますか。

    という質問なのですが、探し方が悪いのかさっぱり見つかりません。
    もし、情報をお持ちの方がいらっしゃいましたら助けていただけると幸いです。

    (参考:大昔のバグ)
    https://support.microsoft.com/kb/KbView/299533?wa=wsignin1.0

    2015年3月3日 2:09

すべての返信

  • 私は、それを言明しているドキュメントが存在しないという認識でいます。
    経験則的に、なんとなくに、大きな値を避ける開発者が多いと思います。(16bit を超えると危ういという勘)

    もっとも、その 16bit も根拠がありません。
    ただ、桁を大きくすればするほど、障害に当たるリスクが高まりますので、本当に必要なのであれば有償サポートに問い合わせることを考えていただいた方が良いでしょう。
    特定の関数では、内部で 23bit 程度の仮数部しかないので大きな値ではおかしくなるという回答があったという話を人づてに聞いたことがあります。(不正確な可能性があります)

    あまりに大きな数値を扱わないように設計・実装されるか、十分にテストされるか、有償サポートに問い合わせるかしかないと思います。

    2015年3月3日 13:09
    モデレータ
  • 普段意識しない素人なので、いいかげんな返信ですが・・・。

    GDI 座標制限なら論理ページ領域と論理デバイス領域が制限になるかなと想像しました。

    制限値記述は以下のページがありましたが・・・。

    Transformation of Coordinate Spaces

    ここで見ると 2^27 の分解能っぽいですが、言明とはいえないドキュメント・・・。

    Mapping Mode が MM_TEXT 以外の場合は、計算の関係で更に制限されてもおかしくない気もするし・・・。

    • 回答の候補に設定 お馬鹿 2015年3月19日 10:37
    2015年3月4日 0:33
  • Azuleanさま、コメントありがとうございます。
    8と8.1は未確認ですが、この現象はVista、 7、また、Virtual PCのXPモードでも発生します。
    以上から、この制限はGDIに実装されており物理デバイスとは無関係ではないかと考えられます。
    これが真実の場合、この制限は実装した側が無償で公開するべき基本的な内容であると考えています。
    2015年3月4日 2:11
  • kyano30さま、コメントありがとうございます。
    Azuleanさんへの返答に記述した通り、もしGDIにコードされているという推測が真実であれば、
    同ページにある通り、出力目的の算定値は全て2^27ビットで丸めなければなりません。
    従って、2^32の空間は文字通り絵空事と言えるかもしれません。
    かつ、エラーの結果は、この2^27の値すら真実でない可能性を示しています。
    やむをえず、実験で得た値にわずかな余裕を持たせてシーリングしなおしましたが、
    公式な値が知りたいものです。

    2015年3月4日 2:15
  • 自分の書いたリンク先よく読むと解釈が難しいですね・・・。

    この記述だと、高さ&幅方向がそれぞれ 2^27 の分解能があるという記述にとれます、もしそうなら MAX と MIN の幅が 2^27 と考えられるので制限値は不明ですね・・・。

    XFORM 構造体が FLOAT 型なので仮数部は 23bit と思われ、写像のためそれ以上の絶対値が使えないのは納得できます。

    なので正負 23 bit の範囲が望ましい気もしますが、分解能制限があるならもっと小さい 16 bit 範囲すら怪しい・・・。

    この解釈だと、論理デバイス領域の MAX, MIN は、元デバイスによってシステム固有でも原点次第なのですよね・・・。

    拡張を考えると規定するのも難がある気がしますし、なんとも役立たずな情報返して申し訳ない・・・。

    2015年3月4日 5:06
  • LineTo() API コール時に指定した Device Context に対応する Logical Surface のサイズはどのくらいだったのでしょうか?

    描画対象となる線分の長さが Logical Surface の範囲外であるならば、ERROR_INVALID_PARAMETER が返されるのは当然の結果であると思います。
    もっと言えば、GDI で規定される範囲と「実際に描画できる範囲」は異なって当然と考えます。
    なぜなら、GDI はその名の通り単なるインターフェイスであり、実際の描画処理はディスプレイあるいはプリンタといった表示系ドライバによって処理されるからです。
    表示系ドライバは渡された描画リクエストを Logical Surface に対して行いますが、この Logical Surface は Physical Surface および Resolution によって変化する有限領域です。
    従って、GDI の仕様として許容する範囲に対して実際に描画可能な範囲は、描画対象となるデバイスがサポートする Physical Surface および Resolution に依存して変化する、と考えるのが妥当ではないのでしょうか?
    (つまり GDI の仕様のみに着目しても意味がないと思います。)

    ご質問された事象に関する原因を明確にしたいのであれば、LineTo() から win32k.sys や表示系ドライバまでの処理の流れを丹念にトレースしていけば、少なくとも ERROR_INVALID_PARAMETER をセットしている箇所を特定することは可能だと思います。
    (まったくの個人的な勝手な推測ですが、ERROR_INVALID_PARAMETER は LineTo() API 自身ではなく、win32k.sys 辺りがセットしているのだと思っています。)


    • 編集済み お馬鹿 2015年3月4日 6:04 誤記訂正
    2015年3月4日 5:50
  • お馬鹿さま、コメントありがとうございます。

    しぶしぶ gdi32.dll の中に入ってみました(デバッグ環境の関係上Xpモード)。
    もうしわけありません。ご指摘の通りGDIは範囲チェックもしていず、
    ntdll.dll 経由で sysenter し、リング0に行って戻るだけでした。
    この中で errに87が設定されてます。
    残念ながらその中まで見る根性も、環境もありません。

    --gdi32.dll---
    77EDD997  mov         edi,edi
    77EDD999  push        ebp 
    77EDD99A  mov         ebp,esp
    77EDD99C  push        ebx 
    77EDD99D  mov         ebx,dword ptr [ebp+8]
    77EDD9A0  push        esi 
    77EDD9A1  mov         eax,ebx
    77EDD9A3  and         eax,7F0000h
    77EDD9A8  mov         esi,10000h
    77EDD9AD  cmp         eax,esi
    77EDD9AF  push        edi 
    77EDD9B0  jne         77EE1F3E
    77EDD9B6  mov         eax,dword ptr fs:[00000018h]
    77EDD9BC  push        dword ptr [ebp+10h]    ;; ここにYの値
    77EDD9BF  and         dword ptr [eax+6D0h],0
    77EDD9C6  push        dword ptr [ebp+0Ch]
    77EDD9C9  push        ebx 
    77EDD9CA  call        77EDD9DB
    77EDD9CF  pop         edi 
    77EDD9D0  pop         esi 
    77EDD9D1  pop         ebx 
    77EDD9D2  pop         ebp 
    77EDD9D3  ret         0Ch 
    ----------------------
    77EDD9DB  mov         eax,10E0h
    77EDD9E0  mov         edx,7FFE0300h
    77EDD9E5  call        dword ptr [edx]  ;;-->ntdll.dllへ
    77EDD9E7  ret         0Ch 

    --ntdll.dll--
    7C94E510  mov         edx,esp
    7C94E512  sysenter        
    7C94E514  ret             

    2015年3月4日 8:06
  • 書き忘れましたが、win32k.sys はカーネル モード側のモジュールなので、カーネル  デバッグ接続でないとトレースできません。
    Hyper-V か VMWare などの仮想環境があれば、簡単にカーネル デバッグ接続ができます。
    (ただ、VS2013 とかだと設定が面倒だったはず。。。私は WinDBG で接続していますが、とても簡単です。)

    以下は、Windows 8 x86 環境のペイント (MSPaint.exe) を使用してライン描画させた際に採取したコール スタックです。

    (長くなってしまうので、デバッグ ログを張り付けようか迷ったのですが。。。)

    ------------------------------------------------------------------------------
     # ChildEBP RetAddr  Args to Child             
    00 8367df40 813bd288 12011429 00000054 00000034 win32k!NtGdiLineTo (FPO: [Non-Fpo]) ;; ;; ☆☆ カーネル モード側 : NtGdiLineTo() API
    01 8367df40 77a27134 12011429 00000054 00000034 nt!KiSystemServicePostCall (FPO: [0,3] TrapFrame @ 8367df54)
    02 00d8db10 76d38bf6 76d38be0 12011429 00000054 ntdll!KiFastSystemCallRet (FPO: [0,0,0])
    03 00d8db14 76d38be0 12011429 00000054 00000034 GDI32!NtGdiLineTo+0xa (FPO: [3,0,0])
    04 00d8db34 76d3b724 12011429 00000054 00000034 GDI32!LineTo+0x32 (FPO: [Non-Fpo])  ;; ☆☆ ユーザ モード側 : LineTo() API
    05 00d8dc08 76d3625c 0000002e 00000027 00000000 GDI32!MultiPartStringOut+0x760 (FPO: [Non-Fpo])
    06 00d8dc48 76d24021 0000002e 00000027 00000000 GDI32!InternalStringOut+0x293 (FPO: [Non-Fpo])
    07 00d8ddd8 76d22c1f 00e81d50 0000002e 00000027 GDI32!ScriptStringOut+0x195 (FPO: [Non-Fpo])
    08 00d8dee0 76d2274f 0000002e 00000030 00000027 GDI32!LpkCharsetDraw+0x4d1 (FPO: [Non-Fpo])
    09 00d8df08 7709d154 12011429 0000002e 00000027 GDI32!LpkDrawTextEx+0x2e (FPO: [Non-Fpo])
    0a 00d8e124 7709d3e6 03dbc590 00000006 00008120 USER32!DrawTextExWorker+0x361 (FPO: [Non-Fpo])
    0b 00d8e164 69f14460 12011429 03dbc590 00000006 USER32!DrawTextW+0x46 (FPO: [Non-Fpo])
    0c 00d8e1bc 69f14414 12011429 03dbc590 00000006 UIRibbon!NUIDrawTextExW+0xcb (FPO: [Non-Fpo])
    0d 00d8e220 69e4f524 03d5ffc8 00000410 12011429 UIRibbon!NetUI::DrawElementText+0x127 (FPO: [Non-Fpo])
    0e 00d8e304 69e4f1bd 12011429 03dbc590 00d8e364 UIRibbon!NetUI::Element::PaintTextEx+0x6df (FPO: [Non-Fpo])
    0f 00d8e378 69e4ef71 12011429 00d8e404 00d8e5f0 UIRibbon!NetUI::Element::PaintContent+0x444 (FPO: [Non-Fpo])
    10 00d8e444 69e4711f 12011429 00d8e5f0 00d8e594 UIRibbon!NetUI::Element::Paint+0xa36 (FPO: [Non-Fpo])
    11 00d8e4e0 69e474c8 02e42400 03d5ffc8 00d8e540 UIRibbon!NetUI::Element::_DisplayNodeCallback+0x440 (FPO: [Non-Fpo])
    12 00d8e52c 69e4e105 02e42400 00d8e540 00000002 UIRibbon!GPCB::xwInvokeDirect+0x22 (FPO: [Non-Fpo])
    13 00d8e568 69e4f0c9 02e42400 12011429 00d8e5f0 UIRibbon!GPCB::xrFirePaint+0x4a (FPO: [Non-Fpo])
    14 00d8e5a8 69e4e4fe 00d8eb90 00d8e5f0 00000019 UIRibbon!DuVisual::xrDrawCore+0xcc (FPO: [Non-Fpo])
    15 00d8e614 69e4e521 00d8eb90 0000002d 00000019 UIRibbon!DuVisual::xrDrawTrivial+0x1b4 (FPO: [Non-Fpo])
    16 00d8e684 69e4e521 00d8eb90 00000001 00000019 UIRibbon!DuVisual::xrDrawTrivial+0x1d7 (FPO: [Non-Fpo])
    17 00d8e6f4 69e4e521 00d8eb90 00000001 00000019 UIRibbon!DuVisual::xrDrawTrivial+0x1d7 (FPO: [Non-Fpo])
    18 00d8e764 69e4e521 00d8eb90 00000001 00000019 UIRibbon!DuVisual::xrDrawTrivial+0x1d7 (FPO: [Non-Fpo])
    19 00d8e7d4 69e4e521 00d8eb90 00000001 00000019 UIRibbon!DuVisual::xrDrawTrivial+0x1d7 (FPO: [Non-Fpo])
    1a 00d8e844 69e4e521 00d8eb90 00000001 00000019 UIRibbon!DuVisual::xrDrawTrivial+0x1d7 (FPO: [Non-Fpo])
    1b 00d8e8b4 69e4e521 00d8eb90 00000001 00000019 UIRibbon!DuVisual::xrDrawTrivial+0x1d7 (FPO: [Non-Fpo])
    1c 00d8e924 69e4e521 00d8eb90 00000001 00000019 UIRibbon!DuVisual::xrDrawTrivial+0x1d7 (FPO: [Non-Fpo])
    1d 00d8e994 69e4e521 00d8eb90 00000000 00000000 UIRibbon!DuVisual::xrDrawTrivial+0x1d7 (FPO: [Non-Fpo])
    1e 00d8ea04 69e4e521 00d8eb90 00000000 00000000 UIRibbon!DuVisual::xrDrawTrivial+0x1d7 (FPO: [Non-Fpo])
    1f 00d8ea74 69e4e521 00d8eb90 00000000 00000000 UIRibbon!DuVisual::xrDrawTrivial+0x1d7 (FPO: [Non-Fpo])
    20 00d8eae4 69e4e521 00d8eb90 00000000 00000000 UIRibbon!DuVisual::xrDrawTrivial+0x1d7 (FPO: [Non-Fpo])
    21 00d8eb54 69e4e3de 00d8eb90 00000000 00000000 UIRibbon!DuVisual::xrDrawTrivial+0x1d7 (FPO: [Non-Fpo])
    22 00d8ecfc 69e4fa66 00d8ed30 02e4cd38 ffffffff UIRibbon!DuVisual::xrDrawFull+0x703 (FPO: [Non-Fpo])
    23 00d8ee9c 69e4e149 00d8ef90 02e4cd38 00000000 UIRibbon!DuVisual::xrDrawFull+0x780 (FPO: [Non-Fpo])
    24 00d8eeb4 69e51f27 00d8ef90 00000000 0000000f UIRibbon!DuVisual::xrDrawStart+0x3c (FPO: [Non-Fpo])
    25 00d8efcc 69f145bf 00000000 200105e7 00d8f010 UIRibbon!DuRootGadget::xrDrawTree+0x384 (FPO: [Non-Fpo])
    26 00d8f05c 69e488f5 0000000f 00000000 00000000 UIRibbon!HWndContainer::xdHandleMessage+0x19a (FPO: [Non-Fpo])
    27 00d8f090 77097433 00020228 0000000f 00000000 UIRibbon!ExtraInfoWndProc+0x7d (FPO: [Non-Fpo])
    28 00d8f0bc 7709993d 69e48887 00020228 0000000f USER32!InternalCallWinProc+0x23
    29 00d8f134 770992b0 69e48887 00020228 0000000f USER32!UserCallWinProcCheckWow+0x1cb (FPO: [SEH])
    2a 00d8f194 77098f53 018ca228 0000000f 00000000 USER32!DispatchClientMessage+0xb5 (FPO: [Non-Fpo])
    2b 00d8f1bc 77a2706e 00d8f1d8 00000018 00d8f49c USER32!__fnDWORD+0x2c (FPO: [Non-Fpo])
    2c 00d8f1ec 770c6016 7709ba7c 0003012c 00000066 ntdll!KiUserCallbackDispatcher+0x2e (FPO: [0,0,0])
    2d 00d8f1f0 7709ba7c 0003012c 00000066 03db6ca8 USER32!NtUserCallHwndLock+0xa (FPO: [2,0,0])
    2e 00d8f204 69f8998d 0003012c 03db6ca8 00e2c330 USER32!UpdateWindow+0x45 (FPO: [Non-Fpo])
    2f 00d8f238 69f896ec 00000000 01db6ca8 00000000 UIRibbon!NetUI::ToolWindowMgr::ShowWindow+0x381 (FPO: [Non-Fpo])
    30 00d8f258 69f036f0 00000000 00000000 00000001 UIRibbon!NetUI::CtxUIMgr::_HwndShowCtxUI+0x1b9 (FPO: [Non-Fpo])
    31 00d8f270 69f89c08 00000000 03db6ca8 00000001 UIRibbon!NetUI::CtxUIMgr::HwndShowCtxUI+0x42 (FPO: [Non-Fpo])
    32 00d8f31c 69f89a7e 00000001 00000001 00e5a310 UIRibbon!NetUI::Anchor::ShowAnchorDropdown+0x18b (FPO: [Non-Fpo])
    33 00d8f330 69f89a36 00000001 00e5a308 00d8f370 UIRibbon!NetUI::Anchor::FToggleAnchorDropdown+0x2f (FPO: [Non-Fpo])
    34 00d8f340 69f532b1 00e5a310 00d8f390 00d8f598 UIRibbon!NetUI::Anchor::OnCommand+0x44 (FPO: [Non-Fpo])
    35 00d8f370 69f06cf7 00e37af8 6a0c2d50 00d8f390 UIRibbon!NetUI::Node::FExecuteCommand+0x15b (FPO: [Non-Fpo])
    36 00d8f3c4 69f00203 00d8f598 00d8f598 00d8f56c UIRibbon!NetUI::SimpleButton::OnEvent+0x70 (FPO: [Non-Fpo])
    37 00d8f3d8 69e541fc 00d8f598 0000000a 00000000 UIRibbon!NetUI::Checkbox::OnEvent+0x82 (FPO: [Non-Fpo])
    38 00d8f460 69e474c8 02e4a7a8 00e37af8 00d8f56c UIRibbon!NetUI::Element::_DisplayNodeCallback+0x4ff (FPO: [Non-Fpo])
    39 00d8f4ac 69e58160 02e4a7a8 00d8f56c 00000000 UIRibbon!GPCB::xwInvokeDirect+0x22 (FPO: [Non-Fpo])
    3a 00d8f534 69e59f83 02e4a7a8 00d8f56c 00000000 UIRibbon!GPCB::xwInvokeFull+0x10a (FPO: [Non-Fpo])
    3b 00d8f554 69f351cc 00d8f56c 00000001 00000000 UIRibbon!DUserSendEvent+0x84 (FPO: [Non-Fpo])
    3c 00d8f580 69f06d5a 00d8f598 00000001 00000001 UIRibbon!NetUI::Element::FireEvent+0x96 (FPO: [Non-Fpo])
    3d 00d8f5c0 69f06909 00e37af8 00d8f5e8 00e37af8 UIRibbon!NetUI::_FirePressedEvent+0x53 (FPO: [Non-Fpo])
    3e 00d8f604 69f066d9 00d8f630 00e37af8 02e58198 UIRibbon!NetUI::SimpleButton::OnInput+0x94 (FPO: [Non-Fpo])
    3f 00d8f618 69f03fca 00d8f630 0000000a 00000000 UIRibbon!NetUI::Checkbox::OnInput+0x5b (FPO: [Non-Fpo])
    40 00d8f6a0 69e474c8 02e4a7a8 00e37af8 02e58198 UIRibbon!NetUI::Element::_DisplayNodeCallback+0x3dc (FPO: [Non-Fpo])
    41 00d8f6ec 69e58160 02e4a7a8 02e58198 00000000 UIRibbon!GPCB::xwInvokeDirect+0x22 (FPO: [Non-Fpo])
    42 00d8f774 69f00cb7 02e4a7a8 02e58198 00000000 UIRibbon!GPCB::xwInvokeFull+0x10a (FPO: [Non-Fpo])
    43 00d8f788 69e54688 02e58174 00000000 00e424d0 UIRibbon!xwProcessFull+0x1a (FPO: [Non-Fpo])
    44 00d8f7b8 69f00c57 02e4a7a8 00000201 00d8f854 UIRibbon!BaseMsgQ::xwProcessNL+0x43 (FPO: [Non-Fpo])
    45 00d8f7d4 69f00c44 02e41588 01d8f854 00d8f864 UIRibbon!DelayedMsgQ::xwProcessDelayedNL+0x70 (FPO: [Non-Fpo])
    46 00d8f7e4 69e49d26 000102c8 02e41588 00000000 UIRibbon!ContextLock::~ContextLock+0x3a (FPO: [Non-Fpo])
    47 00d8f864 69e488f5 00000201 00000001 002a0026 UIRibbon!HWndContainer::xdHandleMessage+0x6da (FPO: [Non-Fpo])
    48 00d8f898 77097433 000102c8 00000201 00000001 UIRibbon!ExtraInfoWndProc+0x7d (FPO: [Non-Fpo])
    49 00d8f8c4 77097980 69e48887 000102c8 00000201 USER32!InternalCallWinProc+0x23
    4a 00d8f93c 77097bb2 69e48887 000102c8 00000201 USER32!UserCallWinProcCheckWow+0x11c (FPO: [SEH])
    4b 00d8f9a4 77097c19 00000000 00000201 00d8f9e0 USER32!DispatchMessageWorker+0x19e (FPO: [Non-Fpo])
    4c 00d8f9b4 6b065d81 01308054 01308020 01308054 USER32!DispatchMessageW+0x10 (FPO: [Non-Fpo])
    4d 00d8f9c4 6b065d02 ffffffff 01308020 01308020 MFC42u!CWinThread::PumpMessage+0x3d (FPO: [0,0,0])
    4e 00d8f9e0 6b070444 00000001 00000020 00000000 MFC42u!CWinThread::Run+0x5a (FPO: [Non-Fpo])
    4f 00d8f9f4 012810a7 01270000 00000000 00e1139c MFC42u!AfxWinMain+0x5c (FPO: [Non-Fpo])
    50 00d8fa84 76c1173e 7f03f000 00d8fad4 77a4af94 mspaint!_initterm_e+0x17c (FPO: [Non-Fpo])
    51 00d8fa90 77a4af94 7f03f000 f6ccc486 00000000 KERNEL32!BaseThreadInitThunk+0xe (FPO: [Non-Fpo])
    52 00d8fad4 77a4af40 ffffffff 77ad4d3a 00000000 ntdll!__RtlUserThreadStart+0x4a (FPO: [SEH])
    53 00d8fae4 00000000 012a49b0 7f03f000 00000000 ntdll!_RtlUserThreadStart+0x1c (FPO: [Non-Fpo])
    ------------------------------------------------------------------------------

    上記コール スタックから、ユーザ モード側 GDI32!LineTo ルーチンの処理は ntdll.dll を経由して、カーネル モード側 win32k!NtGdiLineTo ルーチンに渡されていることがわかると思います。
    で、GDI32!LineTo と win32k!NtGdiLineTo の実装を確認すると、以下のようになっています。
    (こんなの貼り付けたら怒られるかも。。。モデレーターの方、不適切な場合は削除をお願いします。)

    ---------------------------------------
    GDI32!LineTo:
    76d38baa 8bff            mov     edi,edi
    76d38bac 55              push    ebp
    76d38bad 8bec            mov     ebp,esp
    76d38baf 53              push    ebx
    76d38bb0 56              push    esi
    76d38bb1 8b7508          mov     esi,dword ptr [ebp+8]
    76d38bb4 8bc6            mov     eax,esi
    76d38bb6 2500007f00      and     eax,7F0000h        ;; 「2^27 のチェック」 は誤り。正しくは「hdc であるかのチェック」
    76d38bbb 57              push    edi
    76d38bbc 3d00000100      cmp     eax,10000h
    76d38bc1 0f8535570200    jne     GDI32!LineTo+0x39 (76d5e2fc)

    GDI32!LineTo+0x19:
    76d38bc7 ff7510          push    dword ptr [ebp+10h]
    76d38bca 64a118000000    mov     eax,dword ptr fs:[00000018h]
    76d38bd0 ff750c          push    dword ptr [ebp+0Ch]
    76d38bd3 83a0d006000000  and     dword ptr [eax+6D0h],0
    76d38bda 56              push    esi
    76d38bdb e80c000000      call    GDI32!NtGdiLineTo (76d38bec)
    76d38be0 5f              pop     edi
    76d38be1 5e              pop     esi
    76d38be2 5b              pop     ebx
    76d38be3 5d              pop     ebp
    76d38be4 c20c00          ret     0Ch
    ---------------------------------------
    GDI32!NtGdiLineTo:
    76d38bec b850100000      mov     eax,1050h
    76d38bf1 e808000000      call    GDI32!NtGdiLineTo+0xd (76d38bfe)
    76d38bf6 c20c00          ret     0Ch
    ---------------------------------------
    win32k!NtGdiLineTo:
    90cb0515 8bff            mov     edi,edi
    90cb0517 55              push    ebp
    90cb0518 8bec            mov     ebp,esp
    90cb051a 83e4f8          and     esp,0FFFFFFF8h
    90cb051d 83ec44          sub     esp,44h
    90cb0520 53              push    ebx
    90cb0521 56              push    esi
    90cb0522 57              push    edi
    90cb0523 ff7508          push    dword ptr [ebp+8]
    90cb0526 33f6            xor     esi,esi
    90cb0528 8d442410        lea     eax,[esp+10h]
    90cb052c 50              push    eax
    90cb052d 89742414        mov     dword ptr [esp+14h],esi
    90cb0531 89742418        mov     dword ptr [esp+18h],esi
    90cb0535 8974241c        mov     dword ptr [esp+1Ch],esi
    90cb0539 e87de30b00      call    win32k!XDCOBJ::vLock (90d6e8bb)
    90cb053e 8b44240c        mov     eax,dword ptr [esp+0Ch]
    90cb0542 85c0            test    eax,eax
    90cb0544 7414            je      win32k!NtGdiLineTo+0x45 (90cb055a)

    win32k!NtGdiLineTo+0x31:
    90cb0546 8d4c240c        lea     ecx,[esp+0Ch]
    90cb054a 894c242c        mov     dword ptr [esp+2Ch],ecx
    90cb054e 39b0f4010000    cmp     dword ptr [eax+1F4h],esi
    90cb0554 0f8593c92300    jne     win32k!NtGdiLineTo+0x23c9d8 (90eeceed)

    win32k!NtGdiLineTo+0x45:
    90cb055a ff7510          push    dword ptr [ebp+10h]
    90cb055d 8b4d0c          mov     ecx,dword ptr [ebp+0Ch]
    90cb0560 ff7508          push    dword ptr [ebp+8]
    90cb0563 e838000000      call    win32k!GreLineTo (90cb05a0)    ;; Graphics Engine Function をコール。
    90cb0568 8bf8            mov     edi,eax
    90cb056a 85f6            test    esi,esi
    90cb056c 0f85d1c92300    jne     win32k!NtGdiLineTo+0x23ca2e (90eecf43)

    win32k!NtGdiLineTo+0x5d:
    90cb0572 837c240c00      cmp     dword ptr [esp+0Ch],0
    90cb0577 7417            je      win32k!NtGdiLineTo+0x7b (90cb0590)

    win32k!NtGdiLineTo+0x64:
    90cb0579 8d44240c        lea     eax,[esp+0Ch]
    90cb057d 50              push    eax
    90cb057e e8a0e40b00      call    win32k!XDCOBJ::RestoreAttributes (90d6ea23)
    90cb0583 8b4c240c        mov     ecx,dword ptr [esp+0Ch]
    90cb0587 8d4908          lea     ecx,[ecx+8]
    90cb058a ff158432f090    call    dword ptr [win32k!_imp_InterlockedDecrement (90f03284)]

    win32k!NtGdiLineTo+0x7b:
    90cb0590 8bc7            mov     eax,edi
    90cb0592 5f              pop     edi
    90cb0593 5e              pop     esi
    90cb0594 5b              pop     ebx
    90cb0595 8be5            mov     esp,ebp
    90cb0597 5d              pop     ebp
    90cb0598 c20c00          ret     0Ch
    ---------------------------------------

    上記逆アセンブラ コードを確認すると、ここでは Last Error Code をセットしている箇所は見当たりません。
    で、win32k!GreLineTo ルーチンの中をさらに確認すると。。。
    (win32k!GreLineTo ルーチンはとても長いので全部は貼り付けません。)

    ---------------------------------------
    win32k!GreLineTo:
    90cb05a0 8bff            mov     edi,edi
    90cb05a2 55              push    ebp
    90cb05a3 8bec            mov     ebp,esp
    ....
    ....
    win32k!GreLineTo+0x23caa8:
    90eed048 6a57            push    57h
    90eed04a e8bbe9e1ff      call    win32k!EngSetLastError (90d0ba0a)
    ....
    ....
    win32k!GreLineTo+0x23cae7:
    90eed087 6a57            push    57h
    90eed089 e87ce9e1ff      call    win32k!EngSetLastError (90d0ba0a)
    ....
    ....
    ---------------------------------------

    上記より、GDI LineTo() API での ERROR_INVALID_PARAMETER (87 = 0x57) は、win32k!GreLineTo ルーチンの中でセットされた可能性が高いことが言えると思います。
    (断言しないのは、実際にトレースした訳ではないので、他のルーチンでセットされる可能性も排除できないため。)
    さらに、win32k!GreLineTo ルーチンはディスプレイやプリンタなどの描画系ドライバと連動して処理を行うはずなので、それらドライバの挙動(処理)に依存して GDI LineTo() API の描画結果も影響を受けるはずです。

    以上の解析より、GDI の仕様としてサポートされる論理サーフェイスと、実際に描画可能な論理サーフェイスは分けて考える必要があると考えます。








    • 編集済み お馬鹿 2015年3月5日 2:55 誤りを訂正
    2015年3月4日 9:52
  • お馬鹿さま、ありがとうございます。
    貴重な時間を使ってここまでしていただけるとは、大変に申し訳ありません。
    後でじっくりと検討してみます(削除される前にコピーしときました(vv;))。
    また、暇なときにカーネルデバッグを勉強しておきます。
    (実はWinDBGも持っていたりする)

    ところで、
    and         eax,7F0000h
    mov         esi,10000h
    cmp         eax,esi
    push        edi 
    jne         77EE1F3E

    のくだりは自分も2^27のチェックのように見えたのですが、
    1.(2^27 - 1) は 0x07FFFFFF のはずなので、EAXに設定した値は4bitずれてる?。
    2.また、0x00010000 と比較するるのはなんか妙。
    3.スタック上の2つの値を検査するはず。
    から、ちがうと思うのですがどうなんでしょう。
    かといって、何をしているのかはわかりませんが・・・。

    2015年3月4日 12:29
  • システム DLL 内部の事を書くのは色々と微妙な気がしますが・・・。

    仲澤@失業者 様が [ebp+10h]  が Y の値としてますし、 その時点の eax は [ebp+8] だろうから、2^27 チェックではなく hdc のチェックじゃないですかね?

    今回のエラー原因は論理デバイス領域外書き込みの可能性が高く、こんな口出し書き込みしてすみませんが・・・。

    2015年3月5日 0:02
  • > ところで、
    >  and         eax,7F0000h
    >  mov         esi,10000h
    >  cmp         eax,esi
    >  push        edi 
    >  jne         77EE1F3E
    >
    > のくだりは自分も2^27のチェックのように見えたのですが、
    > 1.(2^27 - 1) は 0x07FFFFFF のはずなので、EAXに設定した値は4bitずれてる?。
    > 2.また、0x00010000 と比較するるのはなんか妙。
    > 3.スタック上の2つの値を検査するはず。
    > から、ちがうと思うのですがどうなんでしょう。

    大変失礼いたしました。
    kyano30 さんが指摘してくださったように、上記処理は Device Context のチェックだと思います。
    hdc 自体はそのプロセス内に確保されている Handle Table 内の Index のはずで、Device Context に限らず、File, Directory, Device, Event, Process, Thread といった各種ハンドルは、この Handle Table で一元管理されているはず。
    で、この Handle Table 内の Index が示す個々の情報を基に、その Handle (Index) が何のオブジェクトに対応するハンドルなのかを判別しているはずなので、上記処理は kyano30 さんの仰るとおり、ハンドルが Device Context に対応するものであるかをチェックしているんだと思います。
    ご指摘いただき、ありがとうございました。
    またちゃんと確認もせずに、誤った情報を書き込んでしまい、大変申し訳ありませんでした。



    • 編集済み お馬鹿 2015年3月5日 3:08
    2015年3月5日 2:51
  • すこし実験してみました。

    WM_PAINTで MoveToEx(hdc, 0, 0, 0); LineTo(hdc, d, d); d を色々変えてみた結果、

    WindowsXpとWindows7(32bit エアロoff)では、論理座標(d,d)をDevice座標に変換した値と、Screen座標に変換した値が 28bit integer の範囲にあれば描画されました。ただし、28bit integerの両端はだめでした(0x07fffffe, 0xf8000001までok)。

    Windows8(8.1かも 64bitOS上の32bitアプリ)では、上記のScreen座標が、アプリのフレームの左上を原点とした座標にかわっていました。LineToがゼロを返したときのGetLastErrorはゼロが返りました。

    いずれも納得できる結果だったので報告します。

    2015年3月15日 10:28
  • 貴重なお時間で追試いただきありがとうございます。
    参考にさせていただきます。
    自分も手動の検査で、同じWindows7でも境界値が異なるものを発見しました。
    手間を省くため、テスト用アプリケーションを作成する予定ですが、
    忙しくてまだとりかかれていません。
    とりあえず、お礼まで。
    2015年3月16日 7:57
  • その後、いろいろと実験してみた結果を報告して、
    本スレッドを終了したいと思います。

    【試験内容】
    (A)実験はWin32APIのみで作成した試験用アプリケーションで行いました。
    (B)実験内容は原点(0,0)から、正方向、負方向にLineTo()を実行し、
    (C)その戻り値がFALSEになった値を記録しました。
    (D)試験対象は X軸の正負、Y軸の正負について行いました。
    (E)数種類の異なるPC上で実験しました。

    【試験結果】
    以下は、自分のPCのプライマリ出力の結果です。
     X=0xF8000001~0x07FFFFF6(-134217727~134217718)
     Y=0xF8000001~0x07FFFFCB(-134217727~134217675)
    同じPC、同じボードのセカンダリ出力の結果は以下の通りです。
     X=0xF800032A~0x07FFFFFF(-134216918~134217727)
     Y=0xF8000001~0x07FFFF54(-134217727~134217556)
    この様な試験結果を複数のPCのメインとサブモニタから取得しました。

    【結果から導出される結論】
    1.グラフィックチップによって異なる結果が得られる。
      結果はPCによって異なりました。

    2.同一PC、同一チップでも、複数ある出力結果は異なる場合がある。
     メイン、サブなどとして複数の出力を使用している場合は、
     それぞれのに異なる結果がえられました。

    3.上記は、実行中のアプリケーションをメインからサブに移動した場合でも異なる結果になる。
     実行中の試験アプリをプライマリからセカンダリに移動しただけで結果が異なりました。

    4.実行するたびに異なるものもある。
     数回の試験結果が一定の値になるものと、そうでないものがありました。

    5.同一出力であっても、VirtualPC等で実行した場合には異なる値となる。

    6.XとYの値は異なる

    7.ただし、HDCの属性はすべてデフォルト、かつGetDC()したものを使用した。
     SetMapMode( MM_ISOTROPIC)した場合は32bitまで正常に動作するようです。
     ただしSetWindowExtEx()SetViewportExtEx()で1対1にするとMM_TEXTと同じ結果になります。

    以上です。

    コメントを寄せてくださったみなさんに御礼申し上げます。

    2015年3月19日 5:31