这篇文章更绝,没有使用非托管代码就安装上了鼠标键盘钩子
摘要: 本文对Windows剪贴板机制作了深入、全面的阐述,具体内容包括:文本、位图、DSP、自定义格式剪贴板的使用和多数据项和延迟提交技术。
关键词: VC++6.0; 剪贴板机制;数据格式;延迟提交
Windows剪贴板
Windows剪贴板是一种比较简单同时也是开销比较小的IPC(InterProcess Communication,进程间通讯)机制。Windows系统支持剪贴板IPC的基本机制是由系统预留的一块全局共享内存,用来暂存在各进程间进行交换的数据:提供数据的进程创建一个全局内存块,并将要传送的数据移到或复制到该内存块;接受数据的进程(也可以是提供数据的进程本身)获取此内存块的句柄,并完成对该内存块数据的读取。
为使剪贴板的这种IPC机制更加完善和便于使用,需要解决好如下三个问题:提供数据的进程在结束时Windows系统将删除其创建的全局内存块,而接受数据的进程则希望在其退出后剪贴板中的数据仍然存在,可以继续为其他进程所获取;能方便地管理和传送剪贴板数据句柄;能方便设置和确定剪贴板数据格式。为完善上述功能,Windows提供了存在于USER32.dll中的一组API函数、消息和预定义数据格式等,并通过对这些函数、消息的使用来管理在进程间进行的剪贴板数据交换。
Windows系统为剪贴板提供了一组API函数和多种消息,基本可以满足编程的需要。而且Windows还为剪贴板预定义了多种数据格式。通过这些预定义的格式,可以使接收方正确再现数据提供方放置于剪贴板中的数据内容。
文本剪贴板和位图剪贴板的使用
这两种剪贴板是比较常用的。其中,文本剪贴板是包含具有格式CF_TEXT的字符串的剪贴板,是最经常使用的剪贴板之一。在文本剪贴板中传递的数据是不带任何格式信息的ASCII字符。若要将文本传送到剪贴板,可以先分配一个可移动全局内存块,然后将要复制的文本内容写入到此内存区域。最后调用剪贴板函数将数据放置到剪贴板:
DWORD dwLength = 100; // 要复制的字串长度 HANDLE hGlobalMemory = GlobalAlloc(GHND, dwLength + 1); // 分配内存 LPBYTE lpGlobalMemory = (LPBYTE)GlobalLock(hGlobalMemory); // 锁定内存 for (int i = 0; i 〈 dwLength; i++) // 将"*"复制到全局内存块 *lpGlobalMemory++ = '*'; GlobalUnlock(hGlobalMemory); // 锁定内存块解锁 HWND hWnd = GetSafeHwnd(); // 获取安全窗口句柄 ::OpenClipboard(hWnd); // 打开剪贴板 ::EmptyClipboard(); // 清空剪贴板 ::SetClipboardData(CF_TEXT, hGlobalMemory); // 将内存中的数据放置到剪贴板 ::CloseClipboard(); // 关闭剪贴板 |
这里以OpenClipboard()打开剪贴板,并在调用了EmptyClipboard()后使hWnd指向的窗口成为剪贴板的拥有者,一直持续到CloseClipboard()函数的调用。在此期间,剪贴板为拥有者所独占,其他进程将无法对剪贴板内容进行修改。
从剪贴板获取文本的过程与之类似,首先打开剪贴板并获取剪贴板的数据句柄,如果数据存在就拷贝其数据到程序变量。由于GetClipboardData()获取的数据句柄是属于剪贴板的,因此用户程序必须在调用CloseClipboard()函数之前使用它:
HWND hWnd = GetSafeHwnd(); // 获取安全窗口句柄 ::OpenClipboard(hWnd); // 打开剪贴板 HANDLE hClipMemory = ::GetClipboardData(CF_TEXT);// 获取剪贴板数据句柄 DWORD dwLength = GlobalSize(hClipMemory); // 返回指定内存区域的当前大小 LPBYTE lpClipMemory = (LPBYTE)GlobalLock(hClipMemory); // 锁定内存 m_sMessage = CString(lpClipMemory); // 保存得到的文本数据 GlobalUnlock(hClipMemory); // 内存解锁 ::CloseClipboard(); // 关闭剪贴板 |
大多数应用程序对图形数据采取的是位图的剪贴板数据格式。位图剪贴板的使用与文本剪贴板的使用是类似的,只是数据格式要指明为CF_BITMAP,而且在使用SetClipboardData()或GetClipboardData()函数时交给剪贴板或从剪贴板返回的是设备相关位图句柄。下面这段示例代码将把存在于剪贴板中的位图数据显示到程序的客户区:
HWND hWnd = GetSafeHwnd(); // 获取安全窗口句柄 ::OpenClipboard(hWnd); // 打开剪贴板 HANDLE hBitmap = ::GetClipboardData(CF_BITMAP); // 获取剪贴板数据句柄 HDC hDC = ::GetDC(hWnd); // 获取设备环境句柄 HDC hdcMem = CreateCompatibleDC(hDC); // 创建与设备相关的内存环境 SelectObject(hdcMem, hBitmap); // 选择对象 SetMapMode(hdcMem, GetMapMode(hDC)); // 设置映射模式 BITMAP bm; // 得到位图对象 GetObject(hBitmap, sizeof(BITMAP), &bm); BitBlt(hDC, 0, 0, bm.bmWidth, bm.bmHeight, hdcMem, 0, 0, SRCCOPY); //位图复制 ::ReleaseDC(hWnd, hDC); // 释放设备环境句柄 DeleteDC(hdcMem); // 删除内存环境 ::CloseClipboard(); // 关闭剪贴板 |
要把数据放入剪贴板,在打开剪贴板后一定要调用EmptyClipboard()函数清除当前剪贴板中的内容,而不可以在原有数据项基础上追加新的数据项。但是,可以在EmptyClipboard()和CloseClipboard()调用之间多次调用SetClipboardData()函数来放置多个不同格式的数据项。例如:
OpenClipboard(hWnd); EmptyClipboardData(); SetClipboardData(CF_TEXT, hGMemText); SetClipboardData(CF_BITMAP, hBitmap); CloseClipboard(); |
这时如果用CF_TEXT或CF_BITMAP等格式标记去调用IsClipboardFormatAvailable()都将返回TRUE,表明这几种格式的数据同时存在于剪贴板中。以不同的格式标记去调用GetClipboardData()函数可以得到相应的数据句柄。
对于多数据项的剪贴板数据,还可以用CountClipboardFormats()和EnumClipboardFormats()函数得到当前剪贴板中存在的数据格式数目和具体的数据格式。EnumClipboardFormats()的函数原型为:
UINT EnumClipboardFormats(UINT format); |
参数format指定了剪贴板的数据格式。如果成功执行将返回format指定的格式的下一个数据格式值,如果format为最后的数据格式值,那么将返回0。由此不难写出处理剪贴板中所有格式数据项的程序段代码:
UINT format = 0; // 从第一种格式值开始枚举 OpenClipboard(hWnd); while(format = EnumClipboardFormats(format)) { …… // 对相关格式数据的处理 } CloseClipboard(); |
在数据提供进程创建了剪贴板数据后,一直到有其他进程获取剪贴板数据前,这些数据都要占据内存空间。如在剪贴板放置的数据量过大,就会浪费内存空间,降低对资源的利用率。为避免这种浪费,可以采取延迟提交(Delayed rendering)技术,即由数据提供进程先创建一个指定数据格式的空(NULL)剪贴板数据块,直到有其他进程需要数据或自身进程要终止运行时才真正提交数据。
延迟提交的实现并不复杂,只需剪贴板拥有者进程在调用SetClipboardData()将数据句柄参数设置为NULL即可。延迟提交的拥有者进程需要做的主要工作是对WM_RENDERFORMAT、WM_DESTORYCLIPBOARD和WM_RENDERALLFORMATS等剪贴板延迟提交消息的处理。
当另一个进程调用GetClipboardData()函数时,系统将会向延迟提交数据的剪贴板拥有者进程发送WM_RENDERFORMAT消息。剪贴板拥有者进程在此消息的响应函数中应使用相应的格式和实际的数据句柄来调用SetClipboardData()函数,但不必再调用OpenClipboard()和EmptyClipboard()去打开和清空剪贴板了。在设置完数据有也无须调用CloseClipboard()关闭剪贴板。如果其他进程打开了剪贴板并且调用EmptyClipboard()函数去清空剪贴板的内容,接管剪贴板的拥有权时,系统将向延迟提交的剪贴板拥有者进程发送WM_DESTROYCLIPBOARD消息,以通知该进程对剪贴板拥有权的丧失。而失去剪贴板拥有权的进程在收到该消息后则不会再向剪贴板提交数据。另外,在延迟提交进程在提交完所有要提交的数据后也会收到此消息。如果延迟提交剪贴板拥有者进程将要终止,系统将会为其发送一条WM_RENDERALLFORMATS消息,通知其打开并清除剪贴板内容。在调用SetClipboardData()设置各数据句柄后关闭剪贴板。
下面这段代码将完成对数据的延迟提交,WM_RENDERFORMAT消息响应函数OnRenderFormat()并不会立即执行,当有进程调用GetClipboardData()函数从剪贴板读取数据时才会发出该消息。在消息处理函数中完成对数据的提交:
进行延迟提交:
HWND hWnd = GetSafeHwnd(); // 获取安全窗口句柄 ::OpenClipboard(hWnd); // 打开剪贴板 ::EmptyClipboard(); // 清空剪贴板 ::SetClipboardData(CF_TEXT, NULL); // 进行剪贴板数据的延迟提交 ::CloseClipboard(); // 关闭剪贴板 |
在WM_RENDERFORMAT消息的响应函数中:
DWORD dwLength = 100; // 要复制的字串长度 HANDLE hGlobalMemory = GlobalAlloc(GHND, dwLength + 1); // 分配内存块 LPBYTE lpGlobalMemory = (LPBYTE)GlobalLock(hGlobalMemory); // 锁定内存块 for (int i = 0; i 〈 dwLength; i++) // 将"*"复制到全局内存块 *lpGlobalMemory++ = '*'; GlobalUnlock(hGlobalMemory); // 锁定内存块解锁 ::SetClipboardData(CF_TEXT, hGlobalMemory); // 将内存中的数据放置到剪贴板 |
Windows系统预定义了三个带“DSP”前缀的数据格式:CF_DSPTEXT、CF_DSPBITMAP和CF_DSPMETAFILEPICT。这是一些伪标准格式,用于表示在程序中定义的私有剪贴板数据格式。对于不同的程序,这些格式的规定是不同的,因此这些格式只针对某一具体程序的不同实例才有意义。
为使用DSP数据格式,必须确保进程本身与剪贴板拥有者进程同属一个程序。可以调用GetClipboardOwner()函数来获取剪贴板拥有者窗口句柄,并调用GetClassName()来获取窗口类名:
HWND hClipOwner = GetClipboardOwner(); GetClassName(hClipOwner, &ClassName, 255); |
如果剪贴板拥有者窗口类名同本进程的窗口类名一致,就可以使用带有DSP前缀的剪贴板数据格式了。
除了使用Windows预定义的剪贴板数据格式外,也可以在程序中使用自定义的数据格式。对于自定义的数据格式lpszFormat,可以调用RegisterClipboardFormat()函数来登记,并获取其返回的格式标识值:
UINT format = RegisterClipboardFormat(lpszFormat); |
对此返回的格式标识值的使用与系统预定义的格式标识是一样的。可以通过GetClipboardFormatName()函数来获取自定义格式的ASCII名。
小结
本文主要对Windows编程中的剪贴板机制作了较为深入的讨论,对其中常用的文本、位图、DSP和自定义数据格式的使用方法以及多数据项和延迟提交等重要技术一并做了阐述。并给出了具体的程序示例代码,使读者能够更好的掌握剪贴板机制的使用。
它在 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 = $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;
当用户选择结束对话框或程序自己调用Exit Windows函数
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;
此 消息由基于计算机的训练程序发送,通过WH_JOURNALPALYBACK的hook程序
分离出用户输入 消息
WM_GETMINMAXINFO = $0024;
此 消息发送给窗口当它将要改变大小或位置;
WM_PAINTICON = $0026;
发送给最小化窗口当它图标将要被重画
WM_ICONERASEBKGND = $0027;
此 消息发送给某个最小化窗口,仅当它在画图标前它的背景必须被重画
WM_NEXTDLGCTL = $0028;
发送此 消息给一个对话框程序去更改焦点位置
WM_SPOOLERSTATUS = $002A;
每当打印管理列队增加或减少一条作业时发出此 消息
WM_DRAWITEM = $002B;
当button,combobox,listbox,menu的可视外观改变时发送
此 消息给这些空件的所有者
WM_MEASUREITEM = $002C;
当button, combo box, list box, list view control, or menu item 被创建时
发送此 消息给控件的所有者
WM_DELETEITEM = $002D;
当the list box 或 combo box 被销毁 或 当 某些项被删除通过LB_DELETESTRING, LB_RESETCONTENT, CB_DELETESTRING, or CB_RESETCONTENT 消息
WM_VKEYTOITEM = $002E;
此 消息有一个LBS_WANTKEYBOARDINPUT风格的发出给它的所有者来响应WM_KEYDOWN 消息
WM_CHARTOITEM = $002F;
此 消息由一个LBS_WANTKEYBOARDINPUT风格的列表框发送给他的所有者来响应WM_CHAR 消息
WM_SETFONT = $0030;
当绘制文本时程序发送此 消息得到控件要用的颜色
WM_GETFONT = $0031;
应用程序发送此 消息得到当前控件绘制文本的字体
WM_SETHOTKEY = $0032;
应用程序发送此 消息让一个窗口与一个热键相关连
WM_GETHOTKEY = $0033;
应用程序发送此 消息来判断热键与某个窗口是否有关联
WM_QUERYDRAGICON = $0037;
此 消息发送给最小化窗口,当此窗口将要被拖放而它的类中没有定义图标,应用程序能返回一个图标或光标的句柄,当用户拖放图标时系统显示这个图标或光标
WM_COMPAREITEM = $0039;
发送此 消息来判定combobox或listbox新增加的项的相对位置
WM_GETOBJECT = $003D;
WM_COMPACTING = $0041;
显示内存已经很少了
WM_WINDOWPOSCHANGING = $0046;
发送此 消息给那个窗口的大小和位置将要被改变时,来调用setwindowpos函数或其它窗口管理函数
WM_WINDOWPOSCHANGED = $0047;
发送此 消息给那个窗口的大小和位置已经被改变时,来调用setwindowpos函数或其它窗口管理函数
WM_POWER = $0048;(适用于16位的windows)
当系统将要进入暂停状态时发送此 消息
WM_COPYDATA = $004A;
当一个应用程序传递数据给另一个应用程序时发送此 消息
WM_CANCELJOURNAL = $004B;
当某个用户取消程序日志激活状态,提交此 消息给程序
WM_NOTIFY = $004E;
当某个控件的某个事件已经发生或这个控件需要得到一些信息时,发送此 消息给它的父窗口
WM_INPUTLANGCHANGEREQUEST = $0050;
当用户选择某种输入语言,或输入语言的热键改变
WM_INPUTLANGCHANGE = $0051;
当平台现场已经被改变后发送此 消息给受影响的最顶级窗口
WM_TCARD = $0052;
当程序已经初始化windows帮助例程时发送此 消息给应用程序
WM_HELP = $0053;
此 消息显示用户按下了F1,如果某个菜单是激活的,就发送此 消息个此窗口关联的菜单,否则就
发送给有焦点的窗口,如果当前都没有焦点,就把此 消息发送给当前激活的窗口
WM_USERCHANGED = $0054;
当用户已经登入或退出后发送此 消息给所有的窗口,当用户登入或退出时系统更新用户的具体
设置信息,在用户更新设置时系统马上发送此 消息;
WM_NOTIFYFORMAT = $0055;
公用控件,自定义控件和他们的父窗口通过此 消息来判断控件是使用ANSI还是UNICODE结构
在WM_NOTIFY 消息,使用此控件能使某个控件与它的父控件之间进行相互通信
WM_CONTEXTMENU = $007B;
当用户某个窗口中点击了一下右键就发送此 消息给这个窗口
WM_STYLECHANGING = $007C;
当调用SETWINDOWLONG函数将要改变一个或多个 窗口的风格时发送此 消息给那个窗口
WM_STYLECHANGED = $007D;
当调用SETWINDOWLONG函数一个或多个 窗口的风格后发送此 消息给那个窗口
WM_DISPLAYCHANGE = $007E;
当显示器的分辨率改变后发送此 消息给所有的窗口
WM_GETICON = $007F;
此 消息发送给某个窗口来返回与某个窗口有关连的大图标或小图标的句柄;
WM_SETICON = $0080;
程序发送此 消息让一个新的大图标或小图标与某个窗口关联;
WM_NCCREATE = $0081;
当某个窗口第一次被创建时,此 消息在WM_CREATE 消息发送前发送;
WM_NCDESTROY = $0082;
此 消息通知某个窗口,非客户区正在销毁
WM_NCCALCSIZE = $0083;
当某个窗口的客户区域必须被核算时发送此 消息
WM_NCHITTEST = $0084;//移动鼠标,按住或释放鼠标时发生
WM_NCPAINT = $0085;
程序发送此 消息给某个窗口当它(窗口)的框架必须被绘制时;
WM_NCACTIVATE = $0086;
此 消息发送给某个窗口 仅当它的非客户区需要被改变来显示是激活还是非激活状态;
WM_GETDLGCODE = $0087;
发送此 消息给某个与对话框程序关联的控件,widdows控制方位键和TAB键使输入进入此控件
通过响应WM_GETDLGCODE 消息,应用程序可以把他当成一个特殊的输入控件并能处理它
WM_NCMOUSEMOVE = $00A0;
当光标在一个窗口的非客户区内移动时发送此 消息给这个窗口 //非客户区为:窗体的标题栏及窗
的边框体
WM_NCLBUTTONDOWN = $00A1;
当光标在一个窗口的非客户区同时按下鼠标左键时提交此 消息
WM_NCLBUTTONUP = $00A2;
当用户释放鼠标左键同时光标某个窗口在非客户区十发送此 消息;
WM_NCLBUTTONDBLCLK = $00A3;
当用户双击鼠标左键同时光标某个窗口在非客户区十发送此 消息
WM_NCRBUTTONDOWN = $00A4;
当用户按下鼠标右键同时光标又在窗口的非客户区时发送此 消息
WM_NCRBUTTONUP = $00A5;
当用户释放鼠标右键同时光标又在窗口的非客户区时发送此 消息
WM_NCRBUTTONDBLCLK = $00A6;
当用户双击鼠标右键同时光标某个窗口在非客户区十发送此 消息
WM_NCMBUTTONDOWN = $00A7;
当用户按下鼠标中键同时光标又在窗口的非客户区时发送此 消息
WM_NCMBUTTONUP = $00A8;
当用户释放鼠标中键同时光标又在窗口的非客户区时发送此 消息
WM_NCMBUTTONDBLCLK = $00A9;
当用户双击鼠标中键同时光标又在窗口的非客户区时发送此 消息
WM_KEYFIRST = $0100;
WM_KEYDOWN = $0100;
//按下一个键
WM_KEYUP = $0101;
//释放一个键
WM_CHAR = $0102;
//按下某键,并已发出WM_KEYDOWN, WM_KEYUP 消息
WM_DEADCHAR = $0103;
当用translatemessage函数翻译WM_KEYUP 消息时发送此 消息给拥有焦点的窗口
WM_SYSKEYDOWN = $0104;
当用户按住ALT键同时按下其它键时提交此 消息给拥有焦点的窗口;
WM_SYSKEYUP = $0105;
当用户释放一个键同时ALT 键还按着时提交此 消息给拥有焦点的窗口
WM_SYSCHAR = $0106;
当WM_SYSKEYDOWN 消息被TRANSLATEMESSAGE函数翻译后提交此 消息给拥有焦点的窗口
WM_SYSDEADCHAR = $0107;
当WM_SYSKEYDOWN 消息被TRANSLATEMESSAGE函数翻译后发送此 消息给拥有焦点的窗口
WM_KEYLAST = $0108;
WM_INITDIALOG = $0110;
在一个对话框程序被显示前发送此 消息给它,通常用此 消息初始化控件和执行其它任务
WM_COMMAND = $0111;
当用户选择一条菜单命令项或当某个控件发送一条 消息给它的父窗口,一个快捷键被翻译
WM_SYSCOMMAND = $0112;
当用户选择窗口菜单的一条命令或当用户选择最大化或最小化时那个窗口会收到此 消息
WM_TIMER = $0113; //发生了定时器事件
WM_HSCROLL = $0114;
当一个窗口标准水平滚动条产生一个滚动事件时发送此 消息给那个窗口,也发送给拥有它的控件
WM_VSCROLL = $0115;
当一个窗口标准垂直滚动条产生一个滚动事件时发送此 消息给那个窗口也,发送给拥有它的控件 WM_INITMENU = $0116;
当一个菜单将要被激活时发送此 消息,它发生在用户菜单条中的某项或按下某个菜单键,它允许程序在显示前更改菜单
WM_INITMENUPOPUP = $0117;
当一个下拉菜单或子菜单将要被激活时发送此 消息,它允许程序在它显示前更改菜单,而不要改变全部
WM_MENUSELECT = $011F;
当用户选择一条菜单项时发送此 消息给菜单的所有者(一般是窗口)
WM_MENUCHAR = $0120;
当菜单已被激活用户按下了某个键(不同于加速键),发送此 消息给菜单的所有者;
WM_ENTERIDLE = $0121;
当一个模态对话框或菜单进入空载状态时发送此 消息给它的所有者,一个模态对话框或菜单进入空载状态就是在处理完一条或几条先前的 消息后没有 消息它的列队中等待
WM_MENURBUTTONUP = $0122;
WM_MENUDRAG = $0123;
WM_MENUGETOBJECT = $0124;
WM_UNINITMENUPOPUP = $0125;
WM_MENUCOMMAND = $0126;
WM_CHANGEUISTATE = $0127;
WM_UPDATEUISTATE = $0128;
WM_QUERYUISTATE = $0129;
WM_CTLCOLORMSGBOX = $0132;
在windows绘制 消息框前发送此 消息给 消息框的所有者窗口,通过响应这条 消息,所有者窗口可以通过使用给定的相关显示设备的句柄来设置 消息框的文本和背景颜色
WM_CTLCOLOREDIT = $0133;
当一个编辑型控件将要被绘制时发送此 消息给它的父窗口;通过响应这条 消息,所有者窗口可以通过使用给定的相关显示设备的句柄来设置编辑框的文本和背景颜色
WM_CTLCOLORLISTBOX = $0134;
当一个列表框控件将要被绘制前发送此 消息给它的父窗口;通过响应这条 消息,所有者窗口可以通过使用给定的相关显示设备的句柄来设置列表框的文本和背景颜色
WM_CTLCOLORBTN = $0135;
当一个按钮控件将要被绘制时发送此 消息给它的父窗口;通过响应这条 消息,所有者窗口可以通过使用给定的相关显示设备的句柄来设置按纽的文本和背景颜色
WM_CTLCOLORDLG = $0136;
当一个对话框控件将要被绘制前发送此 消息给它的父窗口;通过响应这条 消息,所有者窗口可以通过使用给定的相关显示设备的句柄来设置对话框的文本背景颜色
WM_CTLCOLORSCROLLBAR= $0137;
当一个滚动条控件将要被绘制时发送此 消息给它的父窗口;通过响应这条 消息,所有者窗口可以通过使用给定的相关显示设备的句柄来设置滚动条的背景颜色
WM_CTLCOLORSTATIC = $0138;
当一个静态控件将要被绘制时发送此 消息给它的父窗口;通过响应这条 消息,所有者窗口可以通过使用给定的相关显示设备的句柄来设置静态控件的文本和背景颜色
WM_MOUSEFIRST = $0200;
WM_MOUSEMOVE = $0200;
// 移动鼠标
WM_LBUTTONDOWN = $0201;
//按下鼠标左键
WM_LBUTTONUP = $0202;
//释放鼠标左键
WM_LBUTTONDBLCLK = $0203;
//双击鼠标左键
WM_RBUTTONDOWN = $0204;
//按下鼠标右键
WM_RBUTTONUP = $0205;
//释放鼠标右键
WM_RBUTTONDBLCLK = $0206;
//双击鼠标右键
WM_MBUTTONDOWN = $0207;
//按下鼠标中键
WM_MBUTTONUP = $0208;
//释放鼠标中键
WM_MBUTTONDBLCLK = $0209;
//双击鼠标中键
WM_MOUSEWHEEL = $020A;
当鼠标轮子转动时发送此 消息个当前有焦点的控件
WM_MOUSELAST = $020A;
WM_PARENTNOTIFY = $0210;
当MDI子窗口被创建或被销毁,或用户按了一下鼠标键而光标在子窗口上时发送此 消息给它的父窗口
WM_ENTERMENULOOP = $0211;
发送此 消息通知应用程序的主窗口that已经进入了菜单循环模式
WM_EXITMENULOOP = $0212;
发送此 消息通知应用程序的主窗口that已退出了菜单循环模式
WM_NEXTMENU = $0213;
WM_SIZING = 532;
当用户正在调整窗口大小时发送此 消息给窗口;通过此 消息应用程序可以监视窗口大小和位置也可以修改他们
WM_CAPTURECHANGED = 533;
发送此 消息 给窗口当它失去捕获的鼠标时;
WM_MOVING = 534;
当用户在移动窗口时发送此 消息,通过此 消息应用程序可以监视窗口大小和位置也可以修改他们;
WM_POWERBROADCAST = 536;
此 消息发送给应用程序来通知它有关电源管理事件;
WM_DEVICECHANGE = 537;
当设备的硬件配置改变时发送此 消息给应用程序或设备驱动程序
WM_IME_STARTCOMPOSITION = $010D;
WM_IME_ENDCOMPOSITION = $010E;
WM_IME_COMPOSITION = $010F;
WM_IME_KEYLAST = $010F;
WM_IME_SETCONTEXT = $0281;
WM_IME_NOTIFY = $0282;
WM_IME_CONTROL = $0283;
WM_IME_COMPOSITIONFULL = $0284;
WM_IME_SELECT = $0285;
WM_IME_CHAR = $0286;
WM_IME_REQUEST = $0288;
WM_IME_KEYDOWN = $0290;
WM_IME_KEYUP = $0291;
WM_MDICREATE = $0220;
应用程序发送此 消息给多文档的客户窗口来创建一个MDI 子窗口
WM_MDIDESTROY = $0221;
应用程序发送此 消息给多文档的客户窗口来关闭一个MDI 子窗口
WM_MDIACTIVATE = $0222;
应用程序发送此 消息给多文档的客户窗口通知客户窗口激活另一个MDI子窗口,当客户窗口收到此 消息后,它发出WM_MDIACTIVE 消息给MDI子窗口(未激活)激活它;
WM_MDIRESTORE = $0223;
程序 发送此 消息给MDI客户窗口让子窗口从最大最小化恢复到原来大小
WM_MDINEXT = $0224;
程序 发送此 消息给MDI客户窗口激活下一个或前一个窗口
WM_MDIMAXIMIZE = $0225;
程序发送此 消息给MDI客户窗口来最大化一个MDI子窗口;
WM_MDITILE = $0226;
程序 发送此 消息给MDI客户窗口以平铺方式重新排列所有MDI子窗口
WM_MDICASCADE = $0227;
程序 发送此 消息给MDI客户窗口以层叠方式重新排列所有MDI子窗口
WM_MDIICONARRANGE = $0228;
程序 发送此 消息给MDI客户窗口重新排列所有最小化的MDI子窗口
WM_MDIGETACTIVE = $0229;
程序 发送此 消息给MDI客户窗口来找到激活的子窗口的句柄
WM_MDISETMENU = $0230;
程序 发送此 消息给MDI客户窗口用MDI菜单代替子窗口的菜单
WM_ENTERSIZEMOVE = $0231;
WM_EXITSIZEMOVE = $0232;
WM_DROPFILES = $0233;
WM_MDIREFRESHMENU = $0234;
WM_MOUSEHOVER = $02A1;
WM_MOUSELEAVE = $02A3;
WM_CUT = $0300;
程序发送此 消息给一个编辑框或combobox来删除当前选择的文本
WM_COPY = $0301;
程序发送此 消息给一个编辑框或combobox来复制当前选择的文本到剪贴板
WM_PASTE = $0302;
程序发送此 消息给editcontrol或combobox从剪贴板中得到数据
WM_CLEAR = $0303;
程序发送此 消息给editcontrol或combobox清除当前选择的内容;
WM_UNDO = $0304;
程序发送此 消息给editcontrol或combobox撤消最后一次操作
WM_RENDERFORMAT = $0305;
WM_RENDERALLFORMATS = $0306;
WM_DESTROYCLIPBOARD = $0307;
当调用ENPTYCLIPBOARD函数时 发送此 消息给剪贴板的所有者
WM_DRAWCLIPBOARD = $0308;
当剪贴板的内容变化时发送此 消息给剪贴板观察链的第一个窗口;它允许用剪贴板观察窗口来
显示剪贴板的新内容;
WM_PAINTCLIPBOARD = $0309;
当剪贴板包含CF_OWNERDIPLAY格式的数据并且剪贴板观察窗口的客户区需要重画;
WM_VSCROLLCLIPBOARD = $030A;
WM_SIZECLIPBOARD = $030B;
当剪贴板包含CF_OWNERDIPLAY格式的数据并且剪贴板观察窗口的客户区域的大小已经改变是此 消息通过剪贴板观察窗口发送给剪贴板的所有者;
WM_ASKCBFORMATNAME = $030C;
通过剪贴板观察窗口发送此 消息给剪贴板的所有者来请求一个CF_OWNERDISPLAY格式的剪贴板的名字
WM_CHANGECBCHAIN = $030D;
当一个窗口从剪贴板观察链中移去时发送此 消息给剪贴板观察链的第一个窗口;
WM_HSCROLLCLIPBOARD = $030E;
此 消息通过一个剪贴板观察窗口发送给剪贴板的所有者 ;它发生在当剪贴板包含CFOWNERDISPALY格式的数据并且有个事件在剪贴板观察窗的水平滚动条上;所有者应滚动剪贴板图象并更新滚动条的值;
WM_QUERYNEWPALETTE = $030F;
此 消息发送给将要收到焦点的窗口,此 消息能使窗口在收到焦点时同时有机会实现他的逻辑调色板
WM_PALETTEISCHANGING= $0310;
当一个应用程序正要实现它的逻辑调色板时发此 消息通知所有的应用程序
WM_PALETTECHANGED = $0311;
此 消息在一个拥有焦点的窗口实现它的逻辑调色板后发送此 消息给所有顶级并重叠的窗口,以此来改变系统调色板
WM_HOTKEY = $0312;
当用户按下由REGISTERHOTKEY函数注册的热键时提交此 消息
WM_PRINT = 791;
应用程序发送此 消息仅当WINDOWS或其它应用程序发出一个请求要求绘制一个应用程序的一部分;
WM_PRINTCLIENT = 792;
WM_HANDHELDFIRST = 856;
WM_HANDHELDLAST = 863;
WM_PENWINFIRST = $0380;
WM_PENWINLAST = $038F;
WM_COALESCE_FIRST = $0390;
WM_COALESCE_LAST = $039F;
WM_DDE_FIRST = $03E0;
WM_DDE_INITIATE = WM_DDE_FIRST + 0;
一个DDE客户程序提交此 消息开始一个与服务器程序的会话来响应那个指定的程序和主题名;
WM_DDE_TERMINATE = WM_DDE_FIRST + 1;
一个DDE应用程序(无论是客户还是服务器)提交此 消息来终止一个会话;
WM_DDE_ADVISE = WM_DDE_FIRST + 2;
一个DDE客户程序提交此 消息给一个DDE服务程序来请求服务器每当数据项改变时更新它
WM_DDE_UNADVISE = WM_DDE_FIRST + 3;
一个DDE客户程序通过此 消息通知一个DDE服务程序不更新指定的项或一个特殊的剪贴板格式的项
WM_DDE_ACK = WM_DDE_FIRST + 4;
此 消息通知一个DDE(动态数据交换)程序已收到并正在处理WM_DDE_POKE, WM_DDE_EXECUTE, WM_DDE_DATA, WM_DDE_ADVISE, WM_DDE_UNADVISE, or WM_DDE_INITIAT 消息
WM_DDE_DATA = WM_DDE_FIRST + 5;
一个DDE服务程序提交此 消息给DDE客户程序来传递个一数据项给客户或通知客户的一条可用数据项
WM_DDE_REQUEST = WM_DDE_FIRST + 6;
一个DDE客户程序提交此 消息给一个DDE服务程序来请求一个数据项的值;
WM_DDE_POKE = WM_DDE_FIRST + 7;
一个DDE客户程序提交此 消息给一个DDE服务程序,客户使用此 消息来请求服务器接收一个未经同意的数据项;服务器通过答复WM_DDE_ACK 消息提示是否它接收这个数据项;
WM_DDE_EXECUTE = WM_DDE_FIRST + 8;
一个DDE客户程序提交此 消息给一个DDE服务程序来发送一个字符串给服务器让它象串行命令一样被处理,服务器通过提交WM_DDE_ACK 消息来作回应;
WM_DDE_LAST = WM_DDE_FIRST + 8;
WM_APP = $8000;
WM_USER = $0400;
此 消息能帮助应用程序自定义私有 消息;
/////////////////////////////////////////////////////////////////////
通知 消息(Notification message)是指这样一种 消息,一个窗口内的子控件发生了一些事情,需要通知父窗口。通知 消息只适用于标准的窗口控件如按钮、列表框、组合框、编辑框,以及 Windows 95公共控件如树状视图、列表视图等。例如,单击或双击一个控件、在控件中选择部分文本、操作控件的滚动条都会产生通知 消息。
按扭
B N _ C L I C K E D //用户单击了按钮
B N _ D I S A B L E //按钮被禁止
B N _ D O U B L E C L I C K E D //用户双击了按钮
B N _ H I L I T E //用户加亮了按钮
B N _ PA I N T按钮应当重画
B N _ U N H I L I T E加亮应当去掉
组合框
C B N _ C L O S E U P组合框的列表框被关闭
C B N _ D B L C L K用户双击了一个字符串
C B N _ D R O P D O W N组合框的列表框被拉出
C B N _ E D I T C H A N G E用户修改了编辑框中的文本
C B N _ E D I T U P D AT E编辑框内的文本即将更新
C B N _ E R R S PA C E组合框内存不足
C B N _ K I L L F O C U S组合框失去输入焦点
C B N _ S E L C H A N G E在组合框中选择了一项
C B N _ S E L E N D C A N C E L用户的选择应当被取消
C B N _ S E L E N D O K用户的选择是合法的
C B N _ S E T F O C U S组合框获得输入焦点
编辑框
E N _ C H A N G E编辑框中的文本己更新
E N _ E R R S PA C E编辑框内存不足
E N _ H S C R O L L用户点击了水平滚动条
E N _ K I L L F O C U S编辑框正在失去输入焦点
E N _ M A X T E X T插入的内容被截断
E N _ S E T F O C U S编辑框获得输入焦点
E N _ U P D AT E编辑框中的文本将要更新
E N _ V S C R O L L用户点击了垂直滚动条 消息含义
列表框
L B N _ D B L C L K用户双击了一项
L B N _ E R R S PA C E列表框内存不够
L B N _ K I L L F O C U S列表框正在失去输入焦点
L B N _ S E L C A N C E L选择被取消
L B N _ S E L C H A N G E选择了另一项
L B N _ S E T F O C U S列表框获得输入焦点
WINDOWS的消息处理机制为了能在应用程序中监控系统的各种事件消息,提供了挂接 各种反调函数(HOOK)的功能。这种挂钩函数(HOOK)类似扩充中断驱动程序,挂钩上 可以挂接多个反调函数构成一个挂接函数链。系统产生的各种消息首先被送到各种 挂接函数,挂接函数根据各自的功能对消息进行监视、修改和控制等,然后交还控 制权或将消息传递给下一个挂接函数以致最终达到窗口函数。WINDOW系统的这种反 调函数挂接方法虽然会略加影响到系统的运行效率,但在很多场合下是非常有用 的,通过合理有效地利用键盘事件的挂钩函数监控机制可以达到预想不到的良好效 果。
一、在WINDOWS键盘事件上挂接监控函数的方法
WINDOW下可进行挂接的过滤函数包括11种:
WH_CALLWNDPROC 窗口函数的过滤函数
WH_CBT 计算机培训过滤函数
WH_DEBUG 调试过滤函数
WH_GETMESSAGE 获取消息过滤函数
WH_HARDWARE 硬件消息过滤函数
WH_JOURNALPLAYBACK 消息重放过滤函数
WH_JOURNALRECORD 消息记录过滤函数
WH_MOUSE 鼠标过滤函数
WH_MSGFILTER 消息过滤函数
WH_SYSMSGFILTER 系统消息过滤函数
WH_KEYBOARD 键盘过滤函数
其中键盘过滤函数是最常用最有用的过滤函数类型,不管是哪一种类型的过滤函 数,其挂接的基本方法都是相同的。 WINDOW调用挂接的反调函数时总是先调用挂接链首的那个函数,因此必须将键盘挂 钩函数利用函数SetWindowsHookEx()将其挂接在函数链首。至于消息是否传递给函 数链的下一个函数是由每个具体函数功能确定的,如果消息需要传统给下一个函 数,可调用API函数的CallNextHookEx()来实现,如果不传递直接返回即可。 挂接函数可以是用来监控所有线程消息的全局性函数,也可以是单独监控某一线程 的局部性函数。如果挂接函数是局部函数,可以将它放到一个.DLL动态链接库中, 也可以放在一个局部模块中;如果挂接函数是全局的,那么必须将其放在一个.DLL 动态链接库中。挂接函数必须严格按照下述格式进行声明,以键盘挂钩函数为例:
int FAR PASCAL KeyboardProc( int nCode,WORD wParam,DWORD lParam) 其中KeyboardProc为定义挂接函数名,该函数必须在模块定义文件中利用EXPORTS命 令进行说明;nCode决定挂接函数是否对当前消息进行处理;wParam和lParam为具体 的消息内容。
二、键盘事件挂接函数的安装与下载 在程序中可以利用函数SetWindowsHookEx()来挂接过滤函数,在挂接函数时必须指 出该挂接函数的类型、函数的入口地址以及函数是全局性的还是局部性的,挂接函 数的具体调用格式如下:
SetWindowsHookEx(iType,iProc,hInst,iCode) 其中iType为挂接函数类型,键盘类型为WH_KEYBOARD,iProc为挂接函数地址,hInst 为挂接函数链接库实例句柄,iCode为监控代码-0表示全局性函数。 如果挂接函数需要将消息传递给下一个过滤函数,则在该挂接函数返回前还需要调 用一次CallNextHookEx()函数,当需要下载挂接函数时,只要调用一次 UnhookWindowsHookEx(iProc)函数即可实现。 如果函数是全局性的,那么它必须放在一个.DLL动态链接库中,这时该函数调用方 法可以和其它普通.DLL函数一样有三种:
1.在DEF定义文件中直接用函数名或序号说明: EXPORTS WEP @1 RESIDENTNAME InitHooksDll @2 InstallFilter @3 KeyboardProc @4 用序号说明格式为:链接库名.函数名(如本例中说明方法为KEYDLL.KeyboardProc)。
2.在应用程序中利用函数直接调用: 首先在应用程序中利用LoadLibrary(LPSTR "链接库名")将动态链接库装入,并取得 装载库模块句柄hInst,然后直接利用GetProcAddress(HINSTANCE hInst,LPSTR "函 数过程名")获取函数地址,然后直接调用该地址即可,程序结束前利用函数 FreeLibrary( )释放装入的动态链接库即可。
3.利用输入库.LIB方法 利用IMPLIB.EXE程序在建立动态链接库的同时建立相应的输入库.LIB,然后直接在 项目文件中增加该输入库。
三、WINDOWS挂钩监控函数的实现步骤 WINDOWS挂钩函数只有放在动态链接库DLL中才能实现所有事件的监控功能。在.DLL 中形成挂钩监控函数基本方法及其基本结构如下:
1、首先声明DLL中的变量和过程;
2、然后编制DLL主模块LibMain(),建立模块实例;
3、建立系统退出DLL机制WEP()函数;
4、完成DLL初始化函数InitHooksDll(),传递主窗口程序句柄;
5、编制挂钩安装和下载函数InstallFilter();
6、编制挂钩函数KeyboardProc(),在其中设置监控功能,并确定继续调下一个钩 子函数还是直接返回WINDOWS应用程序。
7、在WINDOWS主程序中需要初始化DLL并安装相应挂钩函数,由挂接的钩子函数负 责与主程序通信;
8、在不需要监控时由下载功能卸掉挂接函数。
四、WINDOWS下键盘挂钩监控函数的应用技术 目前标准的104 键盘上都有两个特殊的按键,其上分别用WINDOW程序徽标和鼠标下 拉列表标识,本文暂且分别称为Micro左键和Micro右键,前者用来模拟鼠标左键激 活开始菜单,后者用来模拟鼠标右键激活属性菜单。这两个特殊按键只有在按下后 立即抬起即完成 CLICK过程才能实现其功能,并且没有和其它按键进行组合使用。 由于WINDOWS 系统中将按键划分得更加详细,使应用程序中很难灵活定义自己的专 用快捷键,比如在开发.IME等应用程序时很难找到不与WORD8.0等其它应用程序冲突 的功能按键。如果将标准104键盘中的这两个特殊按键作为模拟CTRL和ALT 等专用按 键,使其和其它按键组合,就可以在自己的应用程序中自由地设置专用功能键,为 应用程序实现各种功能快捷键提供灵活性。正常情况下WINDOWS 键盘事件驱动程序 并不将这两个按键的消息进行正常解释,这就必须利用键盘事件的挂钩监控函数来 实现其特定的功能。其方法如下:
1、首先编制如下一个简单动态链接库程序,并编译成DLL文件。 #include "windows.h"
int FAR PASCAL LibMain(HANDLE hModule,UINT wDataSeg, UINT cbHeapSize,LPSTR lpszCmdLine);
int WINAPI WEP(int bSystemExit);
int WINAPI InitHooksDll(HWND hwndMainWindow);
int WINAPI InstallFilter(BOOL nCode);
LRESULT CALLBACK KeyHook(int nCode,WORD wParam,DWORD lParam);
static HANDLE hInstance; // 全局句柄
static HWND hWndMain; // 主窗口句柄
static int InitCalled=0; // 初始化标志
static HHOOK hKeyHook;
FARPROC lpfnKeyHook=(FARPROC)KeyHook;
BOOL HookStates=FALSE;
int FAR PASCAL LibMain( HANDLE hModule, UINT wDataSeg, UINT cbHeapSize, LPSTR lpszCmdLine)
{
if (cbHeapSize!=0)
UnlockData(0);
hInstance = hModule;
return 1;
}
int WINAPI WEP (int bSystemExit)
{ return 1;}
int WINAPI InitHooksDll(HWND hwndMainWindow)
{
hWndMain = hwndMainWindow;
InitCalled = 1;
return (0);
}
int WINAPI InstallFilter(BOOL nCode)
{ if (InitCalled==0)
return (-1);
if (nCode==TRUE)
{
hKeyHook=SetWindowsHookEx(WH_KEYBOARD, (HOOKPROC)lpfnKeyHook,hInstance,0);
HookStates=TRUE;
}
else
{
UnhookWindowsHookEx(hKeyHook);
HookStates=FALSE;
}
return(0);
}
LRESULT CALLBACK KeyHook(int nCode,WORD wParam,DWORD lParam)
{
static BOOL msflag=FALSE;
if(nCode>=0)
{
if(HookStates==TRUE)
{
if((wParam==0xff)|| //WIN3.X下按键值
(wParam==0x5b)||(wParam==0x5c)){//WIN95下按键值
if((i==0x15b)||(i==0x15c)){ //按键按下处理
msflag=TRUE;
PostMessage(hWndMain,0x7fff,0x1,0x3L);
}
else if((i==0xc15b)||(i==0xc15c)){//按键抬起处理 msflag=FALSE;
PostMessage(hWndMain,0x7fff,0x2,0x3L);
}
}
}
}
return((int)CallNextHookEx
(hKeyHook,nCode,wParam,lParam));
}
该程序的主要功能是监控键盘按键消息,将两个特殊按键Micro按下和抬起消息转换 成自定义类型的消息,并将自定义消息发送给应用程序主窗口函数。
2、在应用程序主函数中建立窗口后,调用InitHooksDll()函数来初始化动态链接 库,并将应用程序主窗口句柄传递给链接库,然后调用InstallFilter()函数挂接键 盘事件监控回调函数。
InitHooksDll(hIMEWnd); //初始化DLL
InstallFilter(TRUE); //安装键盘回调函数
3、在应用程序主窗口函数处理自定义消息时,保存Micro按键的状态,供组合按键 处理时判断使用。
switch (iMessage)
{
case 0x7fff: //自定义消息类型
if(lParam==0x3L)
{//设置Micro键的状态
if(wParam==0x1)
MicroFlag=TRUE;
else if(wParam==0x2)
MicroFlag=FALSE;
}
break;
4、在进行按键组合处理时,首先判断Micro键是否按下,然后再进行其它按键的判 断处理。
case WM_KEYDOWN: // 按键按下处理
if(MicroFlag==TRUE)
{
//Micro键按下
if((BYTE)HIBYTE(wParam)==0x5b)
{
//Micro+"["组合键 ......//按键功能处理 }
else if((BYTE)HIBYTE(wParam)==0x5d)
{
//Micro+"]"组合键 ......//按键功能处理 } } break;
5、当应用程序退出时应注意下载键盘监控函数,即调用InstallFilter(FALSE)函 数一次。
6、利用本文提供的方法设置自己的应用程序功能按键,在保证程序功能按键不会 与其它系统发生冲突的同时,有效地利用了系统中现有资源,而且在实现应用程序 功能的同时灵活应用了系统中提供的各种功能调用。
cron服务配置祥解
作者:Fred Huang 出处:www.xiaoxiang.net
刚做了一个备份的模块,后来师傅提示最好再加一个自动备份的功能,于是研究起来cron这个服务来。
cron 是linux的内置服务,但它不自动起来,可以用以下的方法启动、关闭这个服务:
引用: |
/sbin/service crond start //启动服务 /sbin/service crond stop //关闭服务 /sbin/service crond restart //重启服务 /sbin/service crond reload //重新载入配置 |
引用: |
在/etc/rc.d/rc.local这个脚本的末尾加上: /sbin/service crond start |
现在cron这个服务已经在进程里面了,我们就可以用这个服务了,cron服务提供以下几种接口供大家使用:
1.直接用crontab命令编辑
cron服务提供crontab命令来设定cron服务的,以下是这个命令的一些参数与说明:
引用: |
crontab -u //设定某个用户的cron服务,一般root用户在执行这个命令的时候需要此参数 crontab -l //列出某个用户cron服务的详细内容 crontab -r //删除没个用户的cron服务 crontab -e //编辑某个用户的cron服务 |
比如说root查看自己的cron设置:
引用: |
crontab -u root -l |
引用: |
crontab -u fred -r |
引用: |
crontab -u root -e |
引用: |
*/1 * * * * ls >> /tmp/ls.txt |
引用: |
分钟 (0-59) 小時 (0-23) 日期 (1-31) 月份 (1-12) 星期 (0-6)//0代表星期天 |
引用: |
每天早上6点 0 6 * * * echo "Good morning." >> /tmp/test.txt //注意单纯echo,从屏幕上看不到任何输出,因为cron把任何输出都email到root的信箱了。 每两个小时 0 */2 * * * echo "Have a break now." >> /tmp/test.txt 晚上11点到早上8点之间每两个小时,早上八点 0 23-7/2,8 * * * echo "Have a good dream:)" >> /tmp/test.txt 每个月的4号和每个礼拜的礼拜一到礼拜三的早上11点 0 11 4 * 1-3 command line 1月1日早上4点 0 4 1 1 * command line |
2.编辑/etc/crontab 文件配置cron
cron服务每分钟不仅要读一次/var/spool/cron内的所有文件,还需要读一次/etc/crontab,因此我们配置这个文件也能运用cron服务做一些事情。用crontab配置是针对某个用户的,而编辑/etc/crontab是针对系统的任务。此文件的文件格式是:
引用: |
SHELL=/bin/bash PATH=/sbin:/bin:/usr/sbin:/usr/bin MAILTO=root //如果出现错误,或者有数据输出,数据作为邮件发给这个帐号 HOME=/ # run-parts 01 * * * * root run-parts /etc/cron.hourly //每个小时去执行一遍/etc/cron.hourly内的脚本 02 4 * * * root run-parts /etc/cron.daily //每天去执行一遍/etc/cron.daily内的脚本 22 4 * * 0 root run-parts /etc/cron.weekly //每星期去执行一遍/etc/cron.weekly内的脚本 42 4 1 * * root run-parts /etc/cron.monthly //每个月去执行一遍/etc/cron.monthly内的脚本 使用者 运行的路径 |
import java.io.*;
public class TestRead {
public static void main(String[] args)
throws IOException//是系统提示才写上的。不懂为什么。
{
byte f = 1;
byte b = 2;
byte c = 3;
byte[] a={f,b,c};
File file = new File("c://MyClass.txt");
FileOutputStream out=new FileOutputStream("c://MyClass.txt");
out.write(a);// 这个方法只能接受数组形式。
out.close();
}
}
写的不像是面象对象的东西。~:(