求助!关于WM_MOVE消息,如何从WM_MOVE消息中提取新窗口的坐标位置?

SteveYoung 2004-12-07 04:05:49
各位高手好!我看到了MSDN中对于WM_MOVE消息的描述:

lParam:
Specifies the x and y coordinates of the upper-left corner of the client area of the window. The low-order word contains the x-coordinate while the high-order word contains the y coordinate.

----------
但是我使用下述代码却无法提取这个参数中的新窗口的位置坐标

local @movedX ;窗口移动之后的x坐标
local @movedY ;窗口移动之后的y坐标

................

.elseif eax == WM_MOVE
mov ebx, lParam
and ebx, 0000ffffh ;低16位中是x坐标
mov @movedX, ebx
mov ebx, lParam
and ebx, 0ffff0000h ;高16位中是y坐标
mov ecx, 16
.while ecx != 0
shr ebx,1
.endw
mov @movedY, ebx


程序运行后,占用CPU高达100%,而且变成“无响应”,另外窗口客户区原先使用的GRAY_BRUSH画的背景,也变成白的了,在该程序中,鼠标一直处于漏斗状,不知为何?

请高手解释一下!!!非常感谢了!!!!!!!!!!!
...全文
199 6 打赏 收藏 转发到动态 举报
写回复
用AI写文章
6 条回复
切换为时间正序
请发表友善的回复…
发表回复
Areslee 2004-12-08
  • 打赏
  • 举报
回复
偶不用汇编写Windows代码,看看别人的建议吧
SteveYoung 2004-12-07
  • 打赏
  • 举报
回复
;(接上述程序)
_WinMain proc

LOCAL @stWndClass:WNDCLASSEX
local @stMsg:MSG
local @dwAppX ;程序窗口的 x 坐标
local @dwAppHeight ;程序窗口的高度
LOCAL @szBuffer[1024]:byte


invoke GetModuleHandle, NULL
mov hInstance, eax
invoke LoadIcon, hInstance, IDI_ICON
mov hIcon, eax
invoke RtlZeroMemory, addr @stWndClass, sizeof @stWndClass
invoke LoadCursor, 0, IDC_ARROW
push hInstance
pop @stWndClass.hInstance
mov @stWndClass.cbSize, sizeof WNDCLASSEX
mov @stWndClass.style, CS_HREDRAW or CS_VREDRAW
mov @stWndClass.lpfnWndProc, offset _ProcWinMain
invoke GetStockObject, GRAY_BRUSH
mov @stWndClass.hbrBackground, eax
mov @stWndClass.lpszClassName, offset szCustomClassName
mov eax, hIcon
mov @stWndClass.hIcon, eax
mov @stWndClass.hIconSm, eax

invoke RegisterClassEx, addr @stWndClass

invoke GetSystemMetrics, SM_CXFULLSCREEN ;获取屏幕分辨率
mov dwXScreen, eax
invoke GetSystemMetrics, SM_CYFULLSCREEN
mov dwYScreen, eax

mov eax, dwXScreen ;设置窗口初始化时的 x 坐标
shr eax, 1
sub eax, 6 ;分辨率宽度/2之后,总比理论值多6,遂减去之
mov @dwAppX, eax ; x 坐标存入 @dwAppX 变量

mov eax, dwYScreen
add eax, 20
mov @dwAppHeight, eax ;程序窗口高度,这个高度可根据分辨率及任务栏大小自适应

invoke CreateWindowEx, WS_EX_CLIENTEDGE or WS_EX_APPWINDOW, offset szCustomClassName, offset szWndTitle,\
WS_OVERLAPPED or WS_CAPTION or WS_SYSMENU or WS_MINIMIZEBOX or WS_THICKFRAME,\
@dwAppX, 2, 150, @dwAppHeight, NULL, NULL, hInstance, NULL

mov hWinMain, eax

invoke ShowWindow, hWinMain, SW_SHOWNORMAL
invoke UpdateWindow, hWinMain

.while TRUE
invoke GetMessage, addr @stMsg, NULL, 0, 0
.break .if eax == 0
invoke TranslateMessage, addr @stMsg
invoke DispatchMessage, addr @stMsg

.endw

ret
_WinMain endp

start:
call _WinMain
invoke ExitProcess, NULL

end start
---------------
程序有点乱,麻烦大哥复制到记事本中看一下吧,我水平很烂,程序写得很菜,大哥不要笑话啊 -_-!
SteveYoung 2004-12-07
  • 打赏
  • 举报
回复
我把源程序贴上来吧
------------------------
.386
.model flat, stdcall
option casemap:none


include windows.inc
include user32.inc
includelib user32.lib
include kernel32.inc
includelib kernel32.lib
include gdi32.inc
includelib gdi32.lib

IDI_ICON equ 101

.data?

hInstance dd ?
hIcon dd ?
hWinMain dd ?
dwXScreen dd ? ;屏幕分辨率.x
dwYScreen dd ? ;屏幕分辨率.y
stRectAppWnd RECT <> ;程序窗口结构,并非客户区结构

.const

szCustomClassName db 'AutoHide',0
szWndText db 'You should see these characters in the window custom RECT', 0
szWndTitle db 'Auto-hiding', 0
szMsgBoxFormat db '新窗口的坐标为: x = %d, y = %d', 0

.code

_ProcWinMain proc uses ebx esi edi hWnd, uMsg, wParam, lParam

local @stPS:PAINTSTRUCT
local @hDC
LOCAL @stRect:RECT
local @movedX
local @movedY
local @szBuffer[1024]:byte

mov eax, uMsg


.if eax == WM_PAINT

invoke BeginPaint, hWinMain, addr @stPS
mov @hDC, eax
invoke GetClientRect, hWnd, addr @stRect
invoke DrawText, @hDC, addr szWndText, -1, addr @stRect, DT_SINGLELINE or DT_CENTER or DT_VCENTER
invoke EndPaint, hWnd, addr @stPS


.elseif eax == WM_MOVE
push lParam
mov ebx, lParam
and ebx, 0000ffffh ;低 16 位中是 x 坐标
mov @movedX, ebx ;存入移动窗口之后的 x 坐标

pop ebx
and ebx, 0ffff0000h ;高 16 位中是 y 坐标
shr ebx, 16
mov @movedY, ebx ;存入移动窗口之后的 y 坐标
invoke wsprintf, addr @szBuffer, addr szMsgBoxFormat, @movedX, @movedY
invoke MessageBox, NULL, addr @szBuffer, addr @szBuffer, MB_OK or MB_ICONINFORMATION







.elseif eax == WM_CLOSE

invoke DestroyWindow, hWnd
invoke PostQuitMessage, NULL

.else
invoke DefWindowProc, hWnd, uMsg, wParam, lParam
ret
.endif

xor eax, eax
ret

_ProcWinMain endp

SteveYoung 2004-12-07
  • 打赏
  • 举报
回复
谢谢Areslee大哥的解答,非常感谢!可是我还有一些不明白的地方,在创建窗口的时候,我指定的y坐标是2,为什么这里创建之后,却出来了27的坐标呢?
Areslee 2004-12-07
  • 打赏
  • 举报
回复
mov ecx, 16
.while ecx != 0
shr ebx,1
.endw
换成:
shr ebx,16
SteveYoung 2004-12-07
  • 打赏
  • 举报
回复
更迷惑了,我把.while -- .endw 改成了 .repeat --- .until,竟然没有CPU占用率高的情况了,程序也正常了!!!!太奇怪了吧?
消息,就是指Windows发出的一个通知,告诉应用程序某个事情发生了。例如,单击鼠标、改变窗口尺寸、按下键盘上的一个键都会使Windows发送一个消息给应用程序。 消息本身是作为一个记录传递给应用程序的,这个记录包含了消息的类型以及其他信息。例如,对于单击鼠标所产生的消息来说,这个记录包含了单击鼠标时的坐标。这个记录类型叫做TMsg,它在Windows单元是这样声明的: type TMsg = packed record hwnd: HWND; //窗口句柄 message: UINT;//消息常量标识符 wParam: WPARAM ;// 32位消息的特定附加信息 lParam: LPARAM ;// 32位消息的特定附加信息 time: DWORD;//消息创建时的时间 pt: TPoint; //消息创建时的鼠标位置 end ; 消息有什么? 是否觉得一个消息记录的信息像希腊语一样?如果是这样,那么看一看下面的解释:hwnd 32位的窗口句柄。窗口可以是任何类型的屏幕对象,因为Win32能够维护大多数可 视对象的句柄(窗口、对话框、按钮、编辑框等)。message 用于区别其他消息的常量值,这些常量可以是Windows单元预定义的常量,也 可以是自定义的常量。 wParam 通常是一个与消息有关的常量值,也可能是窗口或控件的句柄。 lParam 通常是一个指向内存数据的指针。由于WParam、lParam和Pointer都是32位的,因此,它们之间可以相互转换。 WM_NULL =$0000 // WM_CREATE =$0001 //应用程序创建一个窗口 WM_DESTROY = $0002 //一个窗口被销毁 WM_MOVE = $0003 //移动一个窗口 WM_SIZE= $0005 //改变一个窗口的大小 WM_ACTIVATE= $0006 //一个窗口被激活或失去激活状态; WM_SETFOCUS= $0007 //获得焦点后 WM_KILLFOCUS= $0008 //失去焦点 WM_ENABLE= $000A //改变enable状态 WM_SETREDRAW= $000B //设置窗口是否能重画 WM_SETTEXT= $000C //应用程序发送此消息来设置一个窗口的文本 WM_GETTEXT = $000D //应用程序发送此消息来复制对应窗口的文本到缓冲区 WM_GETTEXTLENGTH = $000E //得到与一个窗口有关的文本的长度(不包含空字符) WM_PAINT = $000F //要求一个窗口重画自己 WM_CLOSE = $0010 //当一个窗口或应用程序要关闭时发送一个信号 WM_QUERYENDSESSION= $0011 //当用户选择结束对话框或程序自己调用ExitWindows函数 WM_QUIT= $0012 //用来结束程序运行或当程序调用postquitmessage函数 WM_QUERYOPEN = $0013 //当用户窗口恢复以前的大小位置时,把此消息发送给某个图标 WM_ERASEBKGND = $0014 //当窗口背景必须被擦除时(例在窗口改变大小时) WM_SYSCOLORCHANGE = $0015 //当系统颜色改变时,发送此消息给所有顶级窗口 WM_ENDSESSION = $0016 // 当系统进程发出WM_QUERYENDSESSION消息后,此消息发送给应用程序,通知它对话是否结束 WM_SYSTEMERROR = $0017 // WM_SHOWWINDOW= $0018 //当隐藏或显示窗口是发送此消息给这个窗口 WM_ACTIVATEAPP = $001C //发此消息给应用程序哪个窗口是激活的,哪个是非激活的; WM_FONTCHANGE= $001D //当系统的字体资源库变化时发送此消息给所有顶级窗口 WM_TIMECHANGE= $001E //当系统的时间变化时发送此消息给所有顶级窗口 WM_CANCELMODE= $001F //发送此消息来取消某种正在进行的摸态(操作) WM_SETCURSOR = $0020 //如果鼠标引起光标在某个窗口移动且鼠标输入没有被捕获时,就发消息给某个窗口 WM_MOUSEACTIVATE = $0021 //当光标在某个非激活的窗口而用户正按着鼠标的某个键发送此消息给当前窗口 WM_CHILDACTIVATE = $0022 //发送此消息给MDI子窗口当用户点击此窗口的标题栏,或当窗口被激活,移动,改变大小 WM_QUEUESYNC= $0023 //此消息由基
Windows消息大全易语言版, 消息,就是指Windows发出的一个通知,告诉应用程序某个事情发生了。例如,单击鼠标、改变窗口尺寸、按下键盘上的一个键都会使Windows发送一个消息给应用程序。消息本身是作为一个记录传递给应用程序的,这个记录包含了消息的类型以及其他信息。例如,对于单击鼠标所产生的消息来说,这个记录包含了单击鼠标时的坐标。这个记录类型叫做TMsg, 它在Windows单元是这样声明的: type TMsg = packed record hwnd: HWND; / /窗口句柄 message: UINT; / /消息常量标识符 wParam: WPARAM ; // 32位消息的特定附加信息 lParam: LPARAM ; // 32位消息的特定附加信息 time: DWORD; / /消息创建时的时间 pt: TPoint; / /消息创建时的鼠标位置 end; 消息有什么? 是否觉得一个消息记录的信息像希腊语一样?如果是这样,那么看一看下面的解释: hwnd 32位的窗口句柄。窗口可以是任何类型的屏幕对象,因为Win32能够维护大多数可视对象的句柄(窗口、对话框、按钮、编辑框等)。 message 用于区别其他消息的常量值,这些常量可以是Windows单元预定义的常量,也可以是自定义的常量。 wParam 通常是一个与消息有关的常量值,也可能是窗口或控件的句柄。 lParam 通常是一个指向内存数据的指针。由于W P a r a m、l P a r a m和P o i n t e r都是3 2位的, 因此,它们之间可以相互转换。 WM_NULL = 0; WM_CREATE = 1; 应用程序创建一个窗口 WM_DESTROY = 2; 一个窗口被销毁 WM_MOVE = 3; 移动一个窗口 WM_SIZE = 5; 改变一个窗口的大小 WM_ACTIVATE = 6; 一个窗口被激活或失去激活状态; WM_SETFOCUS = 7; 获得焦点后 WM_KILLFOCUS = 8; 失去焦点 WM_ENABLE = 10; 改变enable状态 WM_SETREDRAW = 11; 设置窗口是否能重画 WM_SETTEXT = 12; 应用程序发送此消息来设置一个窗口的文本 WM_GETTEXT = 13; 应用程序发送此消息来复制对应窗口的文本到缓冲区 WM_GETTEXTLENGTH = 14; 得到与一个窗口有关的文本的长度(不包含空字符) WM_PAINT = 15; 要求一个窗口重画自己 WM_CLOSE = 16; 当一个窗口或应用程序要关闭时发送一个信号 WM_QUERYENDSESSION = 17; 当用户选择结束对话框或程序自己调用ExitWindows函数 WM_QUIT = 18; 用来结束程序运行或当程序调用postquitmessage函数 WM_QUERYOPEN = 19; 当用户窗口恢复以前的大小位置时,把此消息发送给某个图标 WM_ERASEBKGND = 20; 当窗口背景必须被擦除时(例在窗口改变大小时) WM_SYSCOLORCHANGE = 21; 当系统颜色改变时,发送此消息给所有顶级窗口 WM_ENDSESSION = 22; 当系统进程发出WM_QUERYENDSESSION消息后,此消息发送给应用程序, 通知它对话是否结束 WM_SYSTEMERROR = 23; WM_SHOWWINDOW = 24; 当隐藏或显示窗口是发送此消息给这个窗口 WM_ACTIVATEAPP = 28; 发此消息给应用程序哪个窗口是激活的,哪个是非激活的; WM_FONTCHANGE = 29; 当系统的字体资源库变化时发送此消息给所有顶级窗口 WM_TIMECHANGE = 30; 当系统的时间变化时发送此消息给所有顶级窗口 WM_CANCELMODE = 31; 发送此消息来取消某种正在进行的摸态(操作) WM_SETCURSOR = 32; 如果鼠标引起光标在某个窗口移动且鼠标输入没有被捕获时,就发消息给某个窗口 WM_MOUSEACTIVATE = 33; 当光标在某个非激活的窗口而用户正按着鼠标的某个键发送此消息给当前窗口 WM_CHILDACTIVATE = 34; 发送此消息给MDI子窗口当用户点击此窗口的标题栏,或当窗口被激活,移动,改变大小 WM_QUEUESYNC = 35; 此消息由基于计算机的训练程序发送,通过WH_JOURNALPALYBACK的hook程序 分离出用户输入消息 WM_GETMINMAXINFO = 36; 此消息发送给窗口当它将要改变大小或位置WM_PAINTICON = 38; 发送给最小化窗口当它图标将
自定义窗体的最大化、最小化和关闭按钮, C#移动无标题栏窗体的三种代码: C#移动无标题栏窗体的三种代码:第一种采用,需注意窗体上的控件是否把窗体覆盖了。。。MouseDown、MouseMove、MouseUp事件应该是鼠标所处位置最顶层的控件的事件 在窗体的类声明两个变量 private Point mouseOffset; //记录鼠标指针的坐标 private bool isMouseDown = false; //记录鼠标按键是否按下 创建该窗体 MouseDown、MouseMove、MouseUp事件的相应处理程序 private void Form1_MouseDown(object sender, System.Windows.Forms.MouseEventArgs e) { int xOffset; int yOffset; if (e.Button == MouseButtons.Left) { xOffset = -e.X ; yOffset = -e.Y ; mouseOffset = new Point(xOffset, yOffset); isMouseDown = true; } } private void Form1_MouseMove(object sender, System.Windows.Forms.MouseEventArgs e) { if (isMouseDown) { Point mousePos = Control.MousePosition; mousePos.Offset(mouseOffset.X, mouseOffset.Y); Location = mousePos; } } private void Form1_MouseUp(object sender, System.Windows.Forms.MouseEventArgs e) { // 修改鼠标状态isMouseDown的值 // 确保只有鼠标左键按下并移动时,才移动窗体 if (e.Button == MouseButtons.Left) { isMouseDown = false; } } 第二种调用API 未验证 using System.Runtime.InteropServices; [DllImport("user32.dll")] public static extern bool ReleaseCapture(); [DllImport("user32.dll")] public static extern bool SendMessage(IntPtr hwnd, int wMsg, int wParam, int lParam); public const int WM_SYSCOMMAND = 0x0112; public const int SC_MOVE = 0xF010; public const int HTCAPTION = 0x0002; private void Form1_MouseDown(object sender, MouseEventArgs e) { ReleaseCapture(); SendMessage(this.Handle, WM_SYSCOMMAND, SC_MOVE + HTCAPTION, 0); } 第三种未验证 private bool isMouseDown = false; private Point FormLocation; //form的location private Point mouseOffset; //鼠标的按下位置 [DllImport("user32.dll")] public static extern bool ReleaseCapture(); [DllImport("user32.dll")] public static extern bool SendMessage(IntPtr hwnd, int wMsg, int wParam, int lParam); private const int WM_SYSCOMMAND = 0x0112;//点击窗口左上角那个图标时的系统信息 private const int SC_MOVE = 0xF010;//移动信息 private const int HTCAPTION = 0x0002;//表示鼠标在窗口标题栏时的系统信息 private const int WM_NCHITTEST = 0x84;//鼠标在窗体客户区(除了标题栏和边框以外的部分)时发送的消息 private const int HTCLIENT = 0x1;//表示鼠标在窗口客户区的系统消息 private const int SC_MAXIMIZE = 0xF030;//最大化信息 private const int SC_MINIMIZE = 0xF020;//最小化信息 protected override void WndProc(ref Message m) { switch (m.Msg) { case WM_SYSCOMMAND: if (m.WParam == (IntPtr)SC_MAXIMIZE) { m.WParam = (IntPtr)SC_MINIMIZE; } break; case WM_NCHITTEST: //如果鼠标移动或单击 base.WndProc(ref m);//调用基类的窗口过程——WndProc方法处理这个消息 if (m.Result == (IntPtr)HTCLIENT)//如果返回的是HTCLIENT { m.Result = (IntPtr)HTCAPTION;//把它改为HTCAPTION return;//直接返回退出方法 } break; } base.WndProc(ref m);//如果不是鼠标移动或单击消息就调用基类的窗口过程进行处理 } private void Form1_Load(object sender, EventArgs e) { } ------------------------------- 如何在窗体标题栏左边的控制菜单加入自己的菜单啊? 我们一般在窗口标题栏点右键 或 按Alt+空格 可以弹出那个菜单。 ------解决方案-------------------- using System.Runtime.InteropServices; [DllImport( "user32.dll ")] public static extern IntPtr GetSystemMenu(IntPtr hWnd, bool bRevert); [DllImport( "user32.dll ")] public static extern bool InsertMenu(IntPtr hMenu, uint uPosition, uint uFlags, uint uIDNewItem, string lpNewItem); public const int MF_BYCOMMAND = 0; public const int MF_STRING = 0; public const int MF_BYPOSITION = 0x400; public const int MF_SEPARATOR = 0x800; private const uint SC_ABOUT = 0x0001; public const int WM_SYSCOMMAND = 0x0112; private void Form1_Load(object sender, EventArgs e) { IntPtr vMenuHandle = GetSystemMenu(Handle, false); InsertMenu(vMenuHandle, 255, MF_STRING, SC_ABOUT, "About... "); } protected override void WndProc(ref Message m) { switch (m.Msg) { case WM_SYSCOMMAND: if ((uint)m.WParam == SC_ABOUT) { MessageBox.Show( "Zswang 路过! "); } break; } base.WndProc(ref m); }

21,453

社区成员

发帖
与我相关
我的任务
社区描述
汇编语言(Assembly Language)是任何一种用于电子计算机、微处理器、微控制器或其他可编程器件的低级语言,亦称为符号语言。
社区管理员
  • 汇编语言
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

试试用AI创作助手写篇文章吧