暴米花 发表于 2006-12-11 11:40:00

关于鼠标右键弹不出问题的解决

<strong><br/></strong>在我正式开始写这个地图编辑器的时候,我并没有料到这个问题会困扰我长达一年之久,直到近日在网上某BBS中意外地发现了解决这个问题的方法,我已不只是为这个只需要一行代码即可解决的问题感慨了,我甚至感到了羞愧。正所谓“吃一堑长一智”,又有所谓“独乐乐不如众乐乐”,我便把这个困扰我的问题及它的解决方案写下来,与同我有一样问题的朋友们分享。 <p></p><p>问题是这样的(这里直接拷贝了我在论坛上的提问):我的地图编辑器有个问题老是解决不了,就是右键菜单、对话框显示的问题。怎么说呢,当我有时(注意是有时,有时又可以)点击右键时,右键菜单显示不了,但我确定它确实弹出来了,因为那时画面就停住了,且我在右键菜单出现的大概位置点击后,能实现相应项的功能。也就是说,右键菜单弹出来了,但是显示不出来。对话框也有这个问题。</p><p>问题的解决从看到那篇《[转帖]在全屏(资源独占)游戏中弹出非模态对话框的》开始。原来,在全屏模式下,DirectDraw独占了显示,这导致通过GDI创建的对话框或其它窗口无法正常显示(In&nbsp;full-screen&nbsp;mode,&nbsp;DirectDraw&nbsp;has&nbsp;exclusive&nbsp;control&nbsp;over&nbsp;the&nbsp;display.&nbsp;As&nbsp;a&nbsp;result,&nbsp;dialog&nbsp;boxes&nbsp;and&nbsp;other&nbsp;windows&nbsp;created&nbsp;through&nbsp;GDI&nbsp;are&nbsp;not&nbsp;normally&nbsp;visible.)。当用MessageBox()、DialogBox()等弹出对话框或菜单时,这些对话框或菜单只能显示在隐藏的GDI表面上,而在被DirectDraw所控制的主表面上,它们是不会被显示出来的。所以,我们应该采用特殊技巧。这个技巧说来也非常简单,就是调用IDirectDraw7::FlipToGDISurface方法,将GDI表面设为主表面。这个方法在MessageBox()、DialogBox()等需要用到系统GDI的API前使用。之后问题解决。</p>

暴米花 发表于 2006-12-11 11:41:00

转帖]在全屏(资源独占)游戏中弹出非模态对话框的 <p></p><p>DirectDraw&nbsp;7.0<br/>Displaying&nbsp;a&nbsp;Window&nbsp;in&nbsp;Full-Screen&nbsp;Mode<br/>&nbsp;<br/>The&nbsp;information&nbsp;in&nbsp;this&nbsp;topic&nbsp;pertains&nbsp;only&nbsp;to&nbsp;applications&nbsp;written&nbsp;in&nbsp;C++.&nbsp;<br/>&nbsp;<br/>In&nbsp;full-screen&nbsp;mode,&nbsp;DirectDraw&nbsp;has&nbsp;exclusive&nbsp;control&nbsp;over&nbsp;the&nbsp;display.&nbsp;As&nbsp;a&nbsp;result,&nbsp;dialog&nbsp;boxes&nbsp;and&nbsp;other&nbsp;windows&nbsp;created&nbsp;through&nbsp;GDI&nbsp;are&nbsp;not&nbsp;normally&nbsp;visible.&nbsp;However,&nbsp;by&nbsp;using&nbsp;special&nbsp;techniques&nbsp;you&nbsp;can&nbsp;incorporate&nbsp;a&nbsp;Windows&nbsp;dialog&nbsp;box,&nbsp;HTML&nbsp;Help,&nbsp;or&nbsp;any&nbsp;other&nbsp;kind&nbsp;of&nbsp;window&nbsp;in&nbsp;your&nbsp;application.</p><p>The&nbsp;FSWindow&nbsp;Sample&nbsp;illustrates&nbsp;how&nbsp;a&nbsp;dialog&nbsp;box&nbsp;can&nbsp;be&nbsp;displayed&nbsp;and&nbsp;updated&nbsp;in&nbsp;a&nbsp;full-screen&nbsp;application,&nbsp;and&nbsp;how&nbsp;mouse&nbsp;clicks&nbsp;and&nbsp;keystrokes&nbsp;work&nbsp;just&nbsp;as&nbsp;if&nbsp;the&nbsp;dialog&nbsp;box&nbsp;were&nbsp;being&nbsp;displayed&nbsp;by&nbsp;GDI.</p><p>In&nbsp;FSWindow,&nbsp;the&nbsp;dialog&nbsp;box&nbsp;is&nbsp;created&nbsp;and&nbsp;"shown"&nbsp;as&nbsp;an&nbsp;ordinary&nbsp;dialog&nbsp;window:</p><p>hWndDlg&nbsp;=&nbsp;CreateDialog(g_hInstance,<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;MAKEINTRESOURCE(IDD_DIALOG_SAMPLE),<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;hWnd,&nbsp;(DLGPROC)&nbsp;SampleDlgProc);<br/>ShowWindow(hWndDlg,&nbsp;SW_SHOWNORMAL);</p><p>Of&nbsp;course,&nbsp;at&nbsp;this&nbsp;point&nbsp;the&nbsp;dialog&nbsp;box&nbsp;is&nbsp;shown&nbsp;only&nbsp;on&nbsp;the&nbsp;hidden&nbsp;GDI&nbsp;surface.&nbsp;It&nbsp;does&nbsp;not&nbsp;appear&nbsp;on&nbsp;the&nbsp;primary&nbsp;surface,&nbsp;which&nbsp;is&nbsp;controlled&nbsp;by&nbsp;DirectDraw.&nbsp;</p><p>If&nbsp;the&nbsp;hardware&nbsp;capabilities&nbsp;include&nbsp;DDCAPS2_CANRENDERWINDOWED&nbsp;(see&nbsp;DDCAPS),&nbsp;displaying&nbsp;and&nbsp;updating&nbsp;the&nbsp;dialog&nbsp;box&nbsp;is&nbsp;easy.&nbsp;The&nbsp;application&nbsp;simply&nbsp;calls&nbsp;the&nbsp;IDirectDraw7::FlipToGDISurface&nbsp;method,&nbsp;which&nbsp;makes&nbsp;the&nbsp;GDI&nbsp;surface&nbsp;the&nbsp;primary&nbsp;surface.&nbsp;From&nbsp;now&nbsp;on,&nbsp;all&nbsp;updates&nbsp;to&nbsp;the&nbsp;dialog&nbsp;box&nbsp;will&nbsp;be&nbsp;displayed&nbsp;automatically,&nbsp;because&nbsp;GDI&nbsp;is&nbsp;now&nbsp;rendering&nbsp;directly&nbsp;to&nbsp;the&nbsp;front&nbsp;buffer.&nbsp;The&nbsp;application&nbsp;continues&nbsp;rendering&nbsp;to&nbsp;the&nbsp;back&nbsp;buffer,&nbsp;and&nbsp;on&nbsp;each&nbsp;pass&nbsp;through&nbsp;the&nbsp;rendering&nbsp;loop&nbsp;the&nbsp;contents&nbsp;of&nbsp;the&nbsp;back&nbsp;buffer&nbsp;are&nbsp;blitted&nbsp;to&nbsp;the&nbsp;front&nbsp;buffer&nbsp;by&nbsp;DirectDraw.&nbsp;The&nbsp;dialog&nbsp;box&nbsp;is&nbsp;not&nbsp;overwritten&nbsp;because&nbsp;the&nbsp;front&nbsp;buffer&nbsp;is&nbsp;clipped&nbsp;to&nbsp;the&nbsp;application&nbsp;window,&nbsp;and&nbsp;the&nbsp;dialog&nbsp;box&nbsp;is&nbsp;obscuring&nbsp;part&nbsp;of&nbsp;that&nbsp;window.</p><p>The&nbsp;following&nbsp;code,&nbsp;from&nbsp;the&nbsp;FSWindow_Init&nbsp;function,&nbsp;creates&nbsp;the&nbsp;clipper,&nbsp;associates&nbsp;it&nbsp;with&nbsp;the&nbsp;application&nbsp;window,&nbsp;and&nbsp;brings&nbsp;the&nbsp;GDI&nbsp;surface&nbsp;to&nbsp;the&nbsp;front:</p><p>if&nbsp;(ddObject-&gt;CreateClipper(0,&nbsp;&amp;ddClipper,&nbsp;NULL)&nbsp;==&nbsp;DD_OK)<br/>&nbsp;&nbsp;&nbsp;&nbsp;ddClipper-&gt;SetHWnd(0,&nbsp;hwndAppWindow);<br/>ddObject-&gt;FlipToGDISurface();</p><p>Then,&nbsp;in&nbsp;the&nbsp;FSWindow_Update&nbsp;function,&nbsp;the&nbsp;following&nbsp;code&nbsp;blits&nbsp;the&nbsp;rendered&nbsp;contents&nbsp;of&nbsp;the&nbsp;back&nbsp;buffer&nbsp;to&nbsp;the&nbsp;clipping&nbsp;region:</p><p>ddFrontBuffer-&gt;SetClipper(ddClipper);<br/>ddFrontBuffer-&gt;Blt(NULL,&nbsp;ddBackBuffer,&nbsp;NULL,&nbsp;DDBLT_WAIT,&nbsp;NULL);</p><p>Note&nbsp;that&nbsp;because&nbsp;the&nbsp;GDI&nbsp;surface&nbsp;is&nbsp;the&nbsp;primary&nbsp;surface,&nbsp;Windows&nbsp;continues&nbsp;displaying&nbsp;the&nbsp;mouse&nbsp;cursor.&nbsp;(This&nbsp;would&nbsp;not&nbsp;be&nbsp;the&nbsp;case,&nbsp;however,&nbsp;if&nbsp;the&nbsp;application&nbsp;were&nbsp;using&nbsp;DirectInput&nbsp;with&nbsp;the&nbsp;mouse&nbsp;device&nbsp;at&nbsp;the&nbsp;exclusive&nbsp;cooperative&nbsp;level.)</p><p>For&nbsp;hardware&nbsp;that&nbsp;does&nbsp;not&nbsp;have&nbsp;the&nbsp;DDCAPS2_CANRENDERWINDOWED&nbsp;capability,&nbsp;the&nbsp;process&nbsp;of&nbsp;displaying&nbsp;and&nbsp;updating&nbsp;a&nbsp;window&nbsp;in&nbsp;full-screen&nbsp;mode&nbsp;is&nbsp;somewhat&nbsp;more&nbsp;complicated.&nbsp;In&nbsp;this&nbsp;case,&nbsp;the&nbsp;application&nbsp;is&nbsp;responsible&nbsp;for&nbsp;obtaining&nbsp;the&nbsp;image&nbsp;of&nbsp;the&nbsp;window&nbsp;created&nbsp;by&nbsp;GDI&nbsp;and&nbsp;blitting&nbsp;it&nbsp;to&nbsp;the&nbsp;back&nbsp;buffer&nbsp;after&nbsp;the&nbsp;full-screen&nbsp;rendering&nbsp;has&nbsp;been&nbsp;done.&nbsp;The&nbsp;entire&nbsp;back&nbsp;buffer&nbsp;is&nbsp;then&nbsp;flipped&nbsp;to&nbsp;the&nbsp;front&nbsp;in&nbsp;the&nbsp;usual&nbsp;way.</p><p>The&nbsp;FSWindow&nbsp;sample&nbsp;provides&nbsp;two&nbsp;different&nbsp;methods&nbsp;for&nbsp;accessing&nbsp;the&nbsp;display&nbsp;memory&nbsp;of&nbsp;the&nbsp;window,&nbsp;depending&nbsp;on&nbsp;whether&nbsp;the&nbsp;content&nbsp;is&nbsp;static&nbsp;or&nbsp;dynamic.&nbsp;The&nbsp;method&nbsp;for&nbsp;static&nbsp;content&nbsp;is&nbsp;faster&nbsp;because&nbsp;it&nbsp;involves&nbsp;blitting&nbsp;from&nbsp;a&nbsp;memory&nbsp;device&nbsp;context&nbsp;rather&nbsp;than&nbsp;a&nbsp;screen&nbsp;device&nbsp;context.&nbsp;This&nbsp;method&nbsp;should&nbsp;be&nbsp;used&nbsp;for&nbsp;windows&nbsp;that&nbsp;do&nbsp;not&nbsp;change,&nbsp;such&nbsp;as&nbsp;informational&nbsp;dialog&nbsp;boxes.&nbsp;(Remember,&nbsp;though,&nbsp;that&nbsp;unless&nbsp;you&nbsp;manually&nbsp;update&nbsp;the&nbsp;bitmap&nbsp;in&nbsp;response&nbsp;to&nbsp;events,&nbsp;even&nbsp;basic&nbsp;animation&nbsp;such&nbsp;as&nbsp;a&nbsp;button&nbsp;press&nbsp;will&nbsp;not&nbsp;be&nbsp;visible&nbsp;to&nbsp;the&nbsp;user.)</p><p>If&nbsp;the&nbsp;content&nbsp;is&nbsp;static,&nbsp;FSWindow&nbsp;calls&nbsp;the&nbsp;CreateBMPFromWindow&nbsp;function&nbsp;when&nbsp;the&nbsp;window&nbsp;is&nbsp;initialized.&nbsp;This&nbsp;function&nbsp;creates&nbsp;a&nbsp;bitmap&nbsp;and&nbsp;blits&nbsp;the&nbsp;contents&nbsp;of&nbsp;the&nbsp;window&nbsp;into&nbsp;it.&nbsp;The&nbsp;bitmap&nbsp;handle&nbsp;is&nbsp;stored&nbsp;in&nbsp;the&nbsp;global&nbsp;variable&nbsp;hwndFSWindowBMP.&nbsp;Whenever&nbsp;the&nbsp;primary&nbsp;surface&nbsp;is&nbsp;about&nbsp;to&nbsp;be&nbsp;updated,&nbsp;this&nbsp;bitmap&nbsp;is&nbsp;blitted&nbsp;to&nbsp;the&nbsp;back&nbsp;buffer,&nbsp;as&nbsp;follows:</p><p>if&nbsp;(FSWindow_IsStatic)<br/>{<br/>&nbsp;&nbsp;&nbsp;&nbsp;hdcMemory&nbsp;=&nbsp;CreateCompatibleDC(NULL);<br/>&nbsp;&nbsp;&nbsp;&nbsp;SelectObject(hdcMemory,&nbsp;hwndFSWindowBMP);<br/>&nbsp;&nbsp;&nbsp;&nbsp;BitBlt(hdcBackBuffer,&nbsp;x,&nbsp;y,&nbsp;cx,&nbsp;cy,&nbsp;hdcMemory,&nbsp;0,&nbsp;0,&nbsp;SRCCOPY);<br/>&nbsp;&nbsp;&nbsp;&nbsp;DeleteDC(hdcMemory);<br/>}</p><p>If,&nbsp;on&nbsp;the&nbsp;other&nbsp;hand,&nbsp;the&nbsp;content&nbsp;of&nbsp;the&nbsp;window&nbsp;is&nbsp;dynamic,&nbsp;the&nbsp;following&nbsp;code&nbsp;is&nbsp;executed.&nbsp;It&nbsp;blits&nbsp;the&nbsp;image&nbsp;directly&nbsp;from&nbsp;the&nbsp;GDI&nbsp;surface&nbsp;(represented&nbsp;by&nbsp;the&nbsp;hdcScreen&nbsp;device&nbsp;context)&nbsp;to&nbsp;the&nbsp;back&nbsp;buffer.</p><p>BitBlt(hdcBackBuffer,&nbsp;x,&nbsp;y,&nbsp;cx,&nbsp;cy,&nbsp;hdcScreen,&nbsp;x,&nbsp;y,&nbsp;SRCCOPY);</p><p>The&nbsp;coordinates&nbsp;represent&nbsp;the&nbsp;position&nbsp;and&nbsp;dimensions&nbsp;of&nbsp;the&nbsp;window&nbsp;on&nbsp;the&nbsp;GDI&nbsp;surface,&nbsp;as&nbsp;retrieved&nbsp;through&nbsp;a&nbsp;call&nbsp;to&nbsp;GetWindowRect.</p><p>When&nbsp;the&nbsp;FSWindow&nbsp;application&nbsp;is&nbsp;running&nbsp;on&nbsp;hardware&nbsp;that&nbsp;does&nbsp;not&nbsp;have&nbsp;the&nbsp;DDCAPS2_CANRENDERWINDOWED&nbsp;capability,&nbsp;it&nbsp;does&nbsp;not&nbsp;use&nbsp;the&nbsp;GDI&nbsp;surface,&nbsp;so&nbsp;Windows&nbsp;cannot&nbsp;display&nbsp;the&nbsp;mouse&nbsp;cursor.&nbsp;The&nbsp;application&nbsp;takes&nbsp;over&nbsp;this&nbsp;task&nbsp;by&nbsp;obtaining&nbsp;information&nbsp;about&nbsp;the&nbsp;cursor&nbsp;and&nbsp;displaying&nbsp;it&nbsp;on&nbsp;the&nbsp;back&nbsp;buffer&nbsp;just&nbsp;before&nbsp;the&nbsp;flip.</p><p>首先,本文的方法只适合用C++写的程序</p><p>在全屏模式,由于DirectDraw太公孙,因此只有采用特殊技巧,才能显示对话框,html帮助,etc</p><p>下面就是说用FSWindow创建对话框。</p><p>一般来说,是:</p><p>hWndDlg&nbsp;=&nbsp;CreateDialog(g_hInstance,<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;MAKEINTRESOURCE(IDD_DIALOG_SAMPLE),<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;hWnd,&nbsp;(DLGPROC)&nbsp;SampleDlgProc);<br/>ShowWindow(hWndDlg,&nbsp;SW_SHOWNORMAL);</p><p>当然这只是在默认是GDI的时候才可以,有时候就不行,比如现在。</p><p>如果硬件支持DDCAPS2_CANRENDERWINDOWED,那么就比较好说。应用程序首先调用IDirectDraw7::FlipToGDISurface&nbsp;,让GDI</p><p>接口获得控制权。。。。。。。。。。。(此处省略250字)</p><p>下面这个代码,来自FSWindow_Init函数,创建clipper,关联应用程序窗口,并且把GDI升权:</p><p>if&nbsp;(ddObject-&gt;CreateClipper(0,&nbsp;&amp;ddClipper,&nbsp;NULL)&nbsp;==&nbsp;DD_OK)<br/>&nbsp;&nbsp;&nbsp;&nbsp;ddClipper-&gt;SetHWnd(0,&nbsp;hwndAppWindow);<br/>ddObject-&gt;FlipToGDISurface();</p><p>然后下面这段参考自FSWindow_Update的代码负责维护:</p><p>ddFrontBuffer-&gt;SetClipper(ddClipper);<br/>ddFrontBuffer-&gt;Blt(NULL,&nbsp;ddBackBuffer,&nbsp;NULL,&nbsp;DDBLT_WAIT,&nbsp;NULL);</p><p>由于GDI获得权限,因此这种情况下鼠标显示很正常。</p><p>如果硬件不支持DDCAPS2_CANRENDERWINDOWED&nbsp;,那么应用程序需要先接受GDI画好的图片,然后。。。。。。。。。(省略200</p><p>字)</p><p>FSWindow提供2种方法,这2种方法分别适用于静态content和动态content。静态content比较快,因为内存设备环境比窗口设</p><p>备环境快。当然局限就是只能画不变化的对话框,比如一些提示了,请记住采用这种方法必须自己改变图片,如果打算有一些</p><p>好看的操作。(估计你要的就是这种。。)</p><p>对于静态的,在初始化窗口的时候,FSWindow&nbsp;调用CreateBMPFromWindow&nbsp;,该函数创建位图句柄并在窗口上显示,保存位图</p><p>句柄的hwndFSWindowBMP是全局变量。如下:</p><p>if&nbsp;(FSWindow_IsStatic)<br/>{<br/>&nbsp;&nbsp;&nbsp;&nbsp;hdcMemory&nbsp;=&nbsp;CreateCompatibleDC(NULL);<br/>&nbsp;&nbsp;&nbsp;&nbsp;SelectObject(hdcMemory,&nbsp;hwndFSWindowBMP);<br/>&nbsp;&nbsp;&nbsp;&nbsp;BitBlt(hdcBackBuffer,&nbsp;x,&nbsp;y,&nbsp;cx,&nbsp;cy,&nbsp;hdcMemory,&nbsp;0,&nbsp;0,&nbsp;SRCCOPY);<br/>&nbsp;&nbsp;&nbsp;&nbsp;DeleteDC(hdcMemory);<br/>}</p><p><br/>对于动态的,用下面的函数:<br/>BitBlt(hdcBackBuffer,&nbsp;x,&nbsp;y,&nbsp;cx,&nbsp;cy,&nbsp;hdcScreen,&nbsp;x,&nbsp;y,&nbsp;SRCCOPY);<br/>该函数的参数来自GetWindowRect()</p><p>如果硬件不支持DDCAPS2_CANRENDERWINDOWED&nbsp;的时候,画鼠标需要自己画:displaying&nbsp;it&nbsp;on&nbsp;the&nbsp;back&nbsp;buffer&nbsp;just&nbsp;before&nbsp;</p><p>the&nbsp;flip</p>
页: [1]
查看完整版本: 关于鼠标右键弹不出问题的解决