質問者
GDIに渡せる座標の最大値、最小値はいくらなのでしょう。

質問
-
いまさらの話題で申し訳ないのですが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:18 値の誤り
すべての返信
-
私は、それを言明しているドキュメントが存在しないという認識でいます。
経験則的に、なんとなくに、大きな値を避ける開発者が多いと思います。(16bit を超えると危ういという勘)もっとも、その 16bit も根拠がありません。
ただ、桁を大きくすればするほど、障害に当たるリスクが高まりますので、本当に必要なのであれば有償サポートに問い合わせることを考えていただいた方が良いでしょう。
特定の関数では、内部で 23bit 程度の仮数部しかないので大きな値ではおかしくなるという回答があったという話を人づてに聞いたことがあります。(不正確な可能性があります)あまりに大きな数値を扱わないように設計・実装されるか、十分にテストされるか、有償サポートに問い合わせるかしかないと思います。
-
-
自分の書いたリンク先よく読むと解釈が難しいですね・・・。
この記述だと、高さ&幅方向がそれぞれ 2^27 の分解能があるという記述にとれます、もしそうなら MAX と MIN の幅が 2^27 と考えられるので制限値は不明ですね・・・。
XFORM 構造体が FLOAT 型なので仮数部は 23bit と思われ、写像のためそれ以上の絶対値が使えないのは納得できます。
なので正負 23 bit の範囲が望ましい気もしますが、分解能制限があるならもっと小さい 16 bit 範囲すら怪しい・・・。
この解釈だと、論理デバイス領域の MAX, MIN は、元デバイスによってシステム固有でも原点次第なのですよね・・・。
拡張を考えると規定するのも難がある気がしますし、なんとも役立たずな情報返して申し訳ない・・・。
-
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 誤記訂正
-
お馬鹿さま、コメントありがとうございます。
しぶしぶ 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:09
-
書き忘れましたが、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 誤りを訂正
-
お馬鹿さま、ありがとうございます。
貴重な時間を使ってここまでしていただけるとは、大変に申し訳ありません。
後でじっくりと検討してみます(削除される前にコピーしときました(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つの値を検査するはず。
から、ちがうと思うのですがどうなんでしょう。
かといって、何をしているのかはわかりませんが・・・。 -
> ところで、
> 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
-
すこし実験してみました。
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はゼロが返りました。
いずれも納得できる結果だったので報告します。
-
その後、いろいろと実験してみた結果を報告して、
本スレッドを終了したいと思います。【試験内容】
(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日 7:38