WM

    技术2022-05-11  112

    有些文章拷贝过来上传不了,不知道怎么回是,先给大家这些吧,以后再说!

    这篇虽然比较老,但总有人需要吧,我想,呵呵!要么就当占用大家的磁盘空间了WM_APPCOMMAND和增强输入设备1.0 简介    为创建一个良好的用户记录,硬件供应商现在对打开和控制软件程式的标准输入设备(如键盘和鼠标)增加了附加的按键和按钮。这些附加输入途径可以打开程式、控制音频和媒体程式以及打开和控制互联网浏览器。在Windows 2000发布前,Windows操作系统要求硬件制造商为这些增强功升级硬件标准。Windows 2000操作系统Bata 3版,以名为WM_APPCOMMAND的新Windows API形式,为15种新的多媒体事件提供本地支持。当这些新的多媒体事件发生时,这个新定义的消息用焦点通知程式。2.0 本地操作系统上的WM_APPCOMMAND_Enabled程式Windows 2000 Bata 3中引入的WM_APPCOMMAND API消息,为程式定义了接收增强按键事件通知的直接方式。而后,程式可以初始化任何与特定键事件相连的预定义功能。例如,一个MDI程式可以使用BACKWARD(后退)和FORWARD(前进)事件来循环文档视窗。加入一个WM_APPCOMMAND句柄可以使程式用新增加的键盘、鼠标及其它支持此扩展功能的新HID设备来工作。当按下一个被支持的键或按钮,一系列的事件发生并导致WM_APPCOMMAND消息送往输入焦点视窗。若该视窗不处理WM_APPCOMMAND消息,操作系统将此消息“冒泡”到视窗的父视窗,如此再三直至顶级视窗。如果任一视窗处理消息并返回TRUE,则此过程结束。如果顶级视窗不处理消息,则WM_APPCOMMAND消息被送往外壳钩子(Sheel  hook)。2.1 使用DefwindowProc来进行消息清除WM_APPCOMMAND系列依靠可以适当处理不用的Windows消息的程序。开发者应当不断向DefWindowProc传递不用的键盘、鼠标和WM_APPCOMMAND消息。不用此方式清除无用的消息会中断WM_APPCOMMAND系列。2.2 WM_APPCOMMAND对虚拟键码的处理对大多数编程者,处理键盘按键事件最自然的方式是通过使用WM_KEYDOWN和WM_KEYUP消息传送的虚拟键码(VKs),为了支持新的多媒体键盘键和鼠标按钮,这里极力建议不要使用VKs。这样做有两个原因。首先,使用WM_APPCOMMAND,需要建立能产生此消息(如:键盘和鼠标)的所有HID设备支持。由于所有类型的增强设备的进一步支持添加于Windows 2000,因此将会有不产生VKs而是WM_APPCOMMAND的升级设备列表,;第二,WM_KEYDOWN或WM_KEYUP消息用输入焦点送往视窗,且不会”冒泡”到父视窗。这就造成控件“吃掉”这些键消息,并会中断WM_APPCOMMAND系列。 图1 Windows 2000中的WM_APPCOMMAND3.0 故障诊断问题1:WM_APPCOMMAND-enabled程序,不响应WM_APPCOMMAND消息可能原因1:没有返回正确的返回值。    在进程的每一阶段返回正确的值是非常重要的。当一个WM_KEYDOWN消息被处理时,返回值应为FALSE(或0)。当处理WM_XBUTTON或WM_APPCOMMAND消息时,返回值应为TRUE(或1)。图1提供详细信息,附录A提供例程。可能原因2:没有为DefWindowProc提供未处理的消息。当程序中加入WM_APPCOMMAND支持时,即给DefWindowProc传送未处理的消息,而不是调用DefWindowProc进行消息清除,会产生常见的错误。在Windows 2000中,当知道虚拟键码或有Xbutton消息到达时,由DefWindowProc产生WM_APPCOMMAND消息。图1提供详细信息,附录A提供例程。可能原因3:控件“吃掉”消息。注意:WM_KEYDOWN消息由焦点送往视窗而不是前台视窗,并不会“冒泡”至父视窗。这就意味着,按钮和其它控件可以接收这些消息,并能“吃掉”它们。在所有程序消息处理机制中,使用DefWindowProc进行消息清除很重要。图1提供详细信息,附录A提供例程。4.0 WM_APPCOMMAND需求在Windows 2000中,使用微软IntelliType Pro 1.0 或 IntelliPoint 3.0 软件来增强本地 WM_APPCOMMAND 支持,IntelliType Pro 和 IntelliPoint 在传统微软操作系统上模仿了增强WM_APPCOMMAND 支持。用 Microsoft IntelliType Pro:Windows 2000: 1.0增强版支持Beta 3;. 1.1 增强版支持Windows 2000.最终发行版Windows NT4.0: 由IntelliType Pro 1.0+.提供支持Service Pack 3 及后续版本支持。Windows 95/98: 由IntelliType Pro 1.0+.提供支持。Windows CE: 不支持。用 Microsoft IntelliPoint:Windows 2000: 3.0增强 版支持Beta 3; 3.01 增强版支持Windows 2000.最终发行版。Windows NT4.0: 由IntelliPoint 3.0+提供Service Pack 3 及后续版本支持。Windows 95/98: 由IntelliPoint 3.0+提供支持.Windows CE:不支持。5.0 WM_APPCOMMAND特性参见6.0 如何处理WM_APPCOMMAND消息程式处理此消息的方式如同处理菜单或工具栏命令。例如:菜单命令可在视窗程序中被如下处理:case WM_COMMAND:      switch (wParam)      {      case IDC_PLAYPAUSE:OnPlayPause(hwnd);         return FALSE;

          case IDC_STOP:         OnStop(hwnd);         return FALSE;

          case IDC_PREV:         OnPrev(hwnd);         return FALSE;

          case IDC_NEXT:         OnNext(hwnd);         return FALSE;      [other commands…]}[…]

       return DefWindowProc(hwnd, message, wParam, lParam);键盘命令处理方式与此类似。但有一个重要的不同是:若消息被处理,WM_APPCOMMAND处理程序须返回1,而不是常见返回值0。给DefWindowProc()传递不用的代码也很重要。于是,别的程序可有机会处理它们。 case WM_APPCOMMAND:      switch (GET_APPCOMMAND_LPARAM(lParam))      {      case APPCOMMAND_MEDIA_PLAY_PAUSE:      lr = OnPlayPause(hwnd);      if (lr==NOERROR) return TRUE;      break;

       case APPCOMMAND_MEDIA_STOP:      lr = OnStop(hwnd);      if (lr==NOERROR) return TRUE;      break;

       case APPCOMMAND_MEDIA_PREVIOUSTRACK:      lr = OnPrev(hwnd);      if (lr==NOERROR) return TRUE;      break;

       case APPCOMMAND_MEDIA_NEXTTRACK:      lr = OnNext(hwnd);      if (lr==NOERROR) return TRUE;      break;      }

          return DefWindowProc(hwnd, message, wParam, lParam);

    6 WM_APPCOMMAND_Enabled程序例程见附录A。7 增强键盘的微软IntelliTypePro软件。1999年,微软硬件分部引入了三个新的增强键盘,新键(热键)允许用户控制互联网浏览器、媒体播放器、邮件客户机程序,以及不用鼠标打开程序。在Windows 2000中,IntelliTypePro软件增强了对现存本地操作系统的支持,对早期的微软操作系统IntelliTypePro也提供了新键的支持。7.1 Windows 2000中微软IntelliTypePro的WM_APPCOMMAND在Windows 2000中运行InteliTypePro,由于允许用WM_APPCOMMAND消息(所有媒体消息和“Home”)的子集查询非前台程序,而增强了本地WM_APPCOMMAND。如果正在运行IntelliType和前台视窗,不处理WM_APPCOMMAND产生的消息(且使用DefWindowProc消除此无用消息)。然后IntelliTypePro向当前Z-order中的每个主视窗上传WM_APPCOMMAND消息,直到有视窗使用此消息或所有视窗忽略此消息。7.2 传统Windows上的微软IntelliTypePro的WM_APPCOMMAND为在操作系统上保持应用程序的一致性,在先前的微软操作系统发行版中,IntelliTypePro仿效Windows 2000本地WM_APPCOMMAND支持。IntelliTypePro也提供7.1描述的增强功能。在Win95/98/NT.40中(SP3及以后版本)运行的Win32®程序,若系统安装了IntelliTypePro软件。依靠增强的键盘按键将会收到WM_APPCOMMAND消息。WM_APPCOMMAND-ENABLED程序将如同在本地操作系统上工作。7.3 向IntelliTypePro媒体菜单添加媒体播放器按下媒体按钮会出当前安装在计算机上媒体播放器。菜单只列出本地WM_APPCOMMAND支持的播放器列表。可给此列表增加新播放器,但不能增加自己的播放器,除非列表可用键盘上的所有媒体键进行工作。当媒体键头次按下时,对已知媒体播放器的搜索被初始化。被支持的媒体播放器列表随后出现在注册表键: HKEY_CURRENT_USER/Software/Microsoft/Keyboard下。为给此列表增加媒体播放器,须有新播放器.exe文件的路径和想在媒体菜单显示的名称。7.3.1 何时添加一个新播放器新的播放器在安装到计算机系统上时,由注册表添加到IntelliPro媒体菜单。此进程级需再行执行。注册表本质上是不允许在同一主键的多份复件。所有用此法增加的程式会显示在媒体菜单上,而只有由WM_APPCOMMAND-ENABLED或由IntelliTypePro软件支持的程式可用此增强 键盘键的功能。7.3.2 何时新播放器在媒体菜单中列出新增的播放器在被添加到注册表及“media”(媒体)键被按下后,会立刻显现到媒体菜单中。只有合法的.exe文件被列表。在每个媒体键上,在媒体菜单列表前,按下IntelliTypePro软件未验证.exe文件存在于列表的路径。7.3.3 添加播放器到媒体菜单的步骤① 在注册表主键HKEY_CURRENT_USER/Software/Microsoft/Keyboard下,检查名为“Native Media Players”的主键,若不存在,则创建之(参见附录B创建主键的例子)② 在主键HKCU/Software/Microsoft/Keyboard/Native Media Players下创建有两个串值的主键,此键盘应由新添加的设备来描述。③ 在新创建的键中,添加标为“APPName”的串值,此值应为想在媒体菜单中显示的名字(如“New Player”)。④ 在新创建的键中,添加标为“ExePath”的串值,此值应为播放器的.exe文件的确切路径(如:c:/Program files/Newplayer/newplay.exe)。7.3.4 例程代码附录B包含可向IntelliTypePro媒体菜单添加媒体播放器的代码。8.0 WM_APPCOMMAND和微软鼠标    微软发布了新型的五键IntelliMouse®资源管理器,新的按钮默认为向前和向后,一如在互联网浏览器中的前进与后退按钮。Windows 2000有为这些键内置消息的支持。在传统的微软操作系统中,新的IntelliPoint 3.0软件添加了对新按钮的全部支持。IntelliPoint 3.0也允许在所有微软鼠标产品按钮上指派此功能。8.1 Windows 2000新消息Windows 2000添加新的消息到新的鼠标按钮,即Xbutton消息,与三键按钮消息类似,主要的不同是,两种键的独立消息。在Wparam中设置一个标志位来指定那个键执行动作。若键一是有前进与后退功能的程序,最好处理WM_APPCOMMAND消息。这就认可了前进/后退功能,而不管鼠标、键盘或其它将来的设备是否被连接。若要代替与鼠标有关的行为的按钮的使用,如在CAD程序中的可选工具,好的方法是响应Xbutton消息。当处理Xbutton消息时,切记返回TRUE,以阻止WM_APPCOMMAND消息的产生。若有程序不使用WM_APPCOMMAND消息本身,IntelliPoint将在有未处理WM_APPCOMMAND消息的程序中试图去执行一个前进/后退行为。8.3 在传统操作系统上微软IntelliPoint的WM_APPCOMMAND为在操作系统中保持程序功能的连贯性,IntelliPoint 3.0模仿Windows 2000的本地WM_APPCOMMAND和Xbutton支持。当安装IntelliPoint后,在Windows 95/98/NT4.0上运行的Win32程式将会收到Xbutton和WM_APPCOMMAND消息,如同它们运行在本地操作系统上。9.0 支持五键鼠标的新Windows消息如下:WM_XBUTTONDOWNWM_XBUTTONUPWM_XBUTTONDBLCLKWM_NCXBUTTONDOWNWM_NCXBUTTONUPWM_NCXBUTTONDBLCLK附录A:使用WM_APPCOMMAND的简单媒体播放器此例是简单的媒体播放器且处理来自增强 增强 键盘的所有WM_APPCOMMAND媒体事件。增加增强 鼠标支持将为Xbutton消息简单添加消息句柄:#include <Windows.h>#include "resource.h"

    LPARAM WINAPI MainWndProc( HWND,UINT,WPARAM,LPARAM );BOOL InitDialog( HWND );BOOL OnClose(HWND hwnd);BOOL OnTimer(HWND hwnd);

    BOOL OnPlayPause(HWND hwnd);BOOL OnStop(HWND hwnd);BOOL OnPrev(HWND hwnd);BOOL OnNext(HWND hwnd);

    ////The supported WM_APPCOMMAND events//#ifndef WM_APPCOMMAND

    #define WM_APPCOMMAND               0x319#define APPCOMMAND_MEDIA_NEXTTRACK         11#define APPCOMMAND_MEDIA_PREVIOUSTRACK      12#define APPCOMMAND_MEDIA_STOP            13#define APPCOMMAND_MEDIA_PLAY_PAUSE         14#define FAPPCOMMAND_MASK  0x8000#define GET_APPCOMMAND_LPARAM(lParam) ((short)(HIWORD(lParam) & ~FAPPCOMMAND_MASK))

    #endif

    ////Player constants//const UINT DISPLAY_TIMER_ID = 100;const UINT TIMER_INTERVAL = 1000;const UINT NUM_TRACKS = 10;

    HINSTANCE hInstance = 0;

    UINT trackIndex;UINT trackTime;

    CHAR szTrackIndex[3];CHAR szTrackTime[5];

    BOOL isPlaying;BOOL isBetweenTracks;

    //------------------------------------------------------------//  WinMain()//  //   Main windows routine. All the usual stuff.////-------------------------------------------------------------INT PASCAL WinMain( HINSTANCE hInstance,                     HINSTANCE hPrevInstance,                     LPSTR  lpCmdLine,                     int    nCmdShow ){    ::hInstance = hInstance;

    //// Register the main window class//WNDCLASS  wc;

    wc.style = CS_VREDRAW | CS_HREDRAW;wc.lpfnWndProc = (WNDPROC)MainWndProc;wc.cbClsExtra = 0;wc.cbWndExtra = DLGWINDOWEXTRA;wc.hInstance = hInstance;       wc.hIcon        = 0;wc.hCursor = LoadCursor(NULL, IDC_ARROW);wc.hbrBackground= CreateSolidBrush(GetSysColor(COLOR_BACKGROUND));wc.lpszMenuName =  NULL;wc.lpszClassName= "APP_CMD";

    if(!RegisterClass(&wc))return FALSE;

    // Create the main window as dialog. //HWND hwndMain = CreateDialog(hInstance, "APP_CMD", 0, NULL);   ShowWindow(hwndMain,SW_SHOWNORMAL);

       //initialize   InitDialog(hwndMain);

    MSG msg;   while (GetMessage(&msg, NULL,0,0))    {              TranslateMessage(&msg);              DispatchMessage(&msg);   }   return (msg.wParam);} // end WinMain()

     

    ///*------------------------------------------------------------////   MainWndProc() - Main window callback procedure.//  // -------------------------------------------------------------

    LPARAM WINAPI MainWndProc( HWND hwnd,                            UINT msg,                           WPARAM wParam,                           LPARAM lParam ){   switch (msg){

       //Handle the WM_APPCOMMAND messages here. Return TRUE if we handle the message.//   case WM_APPCOMMAND:      switch (GET_APPCOMMAND_LPARAM(lParam))      {      case APPCOMMAND_MEDIA_PLAY_PAUSE:         OnPlayPause(hwnd);         return TRUE;

          case APPCOMMAND_MEDIA_STOP:         OnStop(hwnd);         return TRUE;

          case APPCOMMAND_MEDIA_PREVIOUSTRACK:         OnPrev(hwnd);         return TRUE;

          case APPCOMMAND_MEDIA_NEXTTRACK:         OnNext(hwnd);         return TRUE;      }      break;

       case WM_CLOSE:      return OnClose(hwnd);

       case WM_TIMER:      return OnTimer(hwnd);

       //Handle the interface messages here. Return FALSE if we handle the message   //   case WM_COMMAND:      switch (wParam)      {      case IDC_PLAY:      case IDC_PAUSE:         OnPlayPause(hwnd);         return FALSE;

          case IDC_STOP:         OnStop(hwnd);         return FALSE;

          case IDC_PREV:         OnPrev(hwnd);         return FALSE;

          case IDC_NEXT:         OnNext(hwnd);         return FALSE;      }      break;   }   //Clean up any unused messages by calling DefWindowProc   //   return DefWindowProc(hwnd,msg,wParam,lParam);}

    ////Initialize the player UI//BOOL InitDialog(HWND hwnd){   // start on first track   trackIndex = 0;

       // start at beginning of track   trackTime = 0;

       // don't play until the user tells us to   isPlaying = FALSE;

       // set the icon for the "play" button   HICON hIcon = LoadIcon(hInstance, MAKEINTRESOURCE(IDI_PLAY));   SendDlgItemMessage(hwnd,IDC_PLAY,BM_SETIMAGE,IMAGE_ICON,(LPARAM)hIcon);

       // set the icon for the "pause" button   hIcon = LoadIcon(hInstance, MAKEINTRESOURCE(IDI_PAUSE));   SendDlgItemMessage(hwnd,IDC_PAUSE,BM_SETIMAGE,IMAGE_ICON,(LPARAM)hIcon);

       // set the icon for the "stop" button   hIcon = LoadIcon(hInstance, MAKEINTRESOURCE(IDI_STOP));   SendDlgItemMessage(hwnd,IDC_STOP,BM_SETIMAGE,IMAGE_ICON,(LPARAM)hIcon);

       // set the icon for the "previous" button   hIcon = LoadIcon(hInstance, MAKEINTRESOURCE(IDI_PREV));   SendDlgItemMessage(hwnd,IDC_PREV,BM_SETIMAGE,IMAGE_ICON,(LPARAM)hIcon);

       // set the icon for the "next" button   hIcon = LoadIcon(hInstance, MAKEINTRESOURCE(IDI_NEXT));   SendDlgItemMessage(hwnd,IDC_NEXT,BM_SETIMAGE,IMAGE_ICON,(LPARAM)hIcon);

       // start a timer to update the track time display   SetTimer(hwnd, DISPLAY_TIMER_ID, TIMER_INTERVAL, NULL);

       return TRUE;}

    ////Close the Application//BOOL OnClose(HWND hwnd){   KillTimer(hwnd, DISPLAY_TIMER_ID);   DestroyWindow(hwnd);   PostQuitMessage(0);   return TRUE;}

    ////Update Track UI//void UpdateTrackInfo(HWND hwnd){   wsprintf(szTrackIndex, "%d", trackIndex+1);   SetDlgItemText(hwnd, IDC_TRACKINDEX, szTrackIndex);

       wsprintf(szTrackTime, "0:d", trackTime);   SetDlgItemText(hwnd, IDC_TRACKTIME, szTrackTime);}

    ////Timer controls how fast the UI "time" display changes//BOOL OnTimer(HWND hwnd){   if (isPlaying)   {      // make sure the display is visible      UpdateTrackInfo(hwnd);      HWND hwndDisplay = GetDlgItem(hwnd, IDC_TRACKTIME);      ShowWindow(hwndDisplay, SW_SHOW);

          // advance the counter      ++trackTime;

          // every track is 60 seconds      if (trackTime >= 60)         OnNext(hwnd);   // advance to the beginning of the next track   }   else   {      // get the track time window      HWND hwndDisplay = GetDlgItem(hwnd, IDC_TRACKTIME);

          // flash the display      if (IsWindowVisible(hwndDisplay))         ShowWindow(hwndDisplay, SW_HIDE);      else         ShowWindow(hwndDisplay, SW_SHOW);   }

       UpdateTrackInfo(hwnd);   return TRUE;}

    ////Start/Pause the UI’s "time" index//BOOL OnPlayPause(HWND hwnd){   // toggle between play and pause   isPlaying = !isPlaying;

       UpdateTrackInfo(hwnd);   return TRUE;}

    ////Stop the UI’s "time" index//BOOL OnStop(HWND hwnd){   // stop playing and move to beginning of track   isPlaying = FALSE;   trackTime = 0;

       UpdateTrackInfo(hwnd);   return TRUE;}

    ////Goto the previous track//BOOL OnPrev(HWND hwnd){   // if the user is at the beginning of a track   if (trackTime<1)   {      // set the track index to the previous track      if (trackIndex==0)         trackIndex = NUM_TRACKS-1;      else         --trackIndex %= NUM_TRACKS;   }

       // go back the beginning of the track   trackTime = 0;

       UpdateTrackInfo(hwnd);   return TRUE;}

    ////Goto the next track//BOOL OnNext(HWND hwnd){   // go to the beginninf of the next track   ++trackIndex %= NUM_TRACKS;   trackTime = 0;

       UpdateTrackInfo(hwnd);   return TRUE;}

    附录B:向IntelliTypePro媒体菜单中添加媒体播放器的例子。#define MSKB_KEY "Software//Microsoft//Keyboard//Native Media Players"

    BOOL AddPlayerToRegistry ( LPSTR szDisplayString, LPSTR szExePath ){   //open Microsoft Keyboard Native Media key OR if it does not exist, create it    HKEY hKey;   DWORD dwDisposition;   if ( ERROR_SUCCESS != RegCreateKeyEx(                   HKEY_CURRENT_USER,             MSKB_KEY,             0, 0,             REG_OPTION_NON_VOLATILE,             KEY_ALL_ACCESS,             0,             &hKey,             &dwDisposition             )    ) return 0;

       //create a key for new media player (using DisplayString as key name)   HKEY hSubKey;   if ( ERROR_SUCCESS != RegCreateKeyEx(                   hKey,             szDisplayString,             0, 0,             REG_OPTION_NON_VOLATILE,             KEY_ALL_ACCESS,             0,             &hSubKey,             &dwDisposition             )    ) return 0;

       //Add AppName string value to new key and copy in the DisplayString   if ( ERROR_SUCCESS != RegSetValueEx(                   hSubKey,             "AppName",             0,             REG_SZ,              (const BYTE*)szDisplayString,             strlen(szDisplayString)             )    ) return 0;

       //Add ExePath string value to new key and copy in the ExePath   if ( ERROR_SUCCESS != RegSetValueEx(                   hSubKey,             "ExePath",             0,             REG_SZ,              (const BYTE*)szExePath,             strlen(szExePath)             )    ) return 0;

       //close reg keys   if ( ERROR_SUCCESS != RegCloseKey(hKey) ) return 0;   if ( ERROR_SUCCESS != RegCloseKey(hSubKey) ) return 0;

       return 1;}


    最新回复(0)