分享

使用EnumWindows找到窗口句柄后再用SetForegroundWindow切换窗口...

 @IT小小鸟@ 2012-03-07

我想实现一个类似ALT+TAB切换程序窗口的功能,但不同的是我在我的程序里面注册几个系统热键,用来快捷切换,比如注册CTRL+ALT+F1是切换Matlab.exe,CTRL+ALT+F2切换出Winword.exe,CTRL+ALT+F3是切换出devenv.exe。。。

 

程序是这样写代码的:

Code Snippet

1、在OnInitDialog()注册热键

 ::RegisterHotKey(m_hWnd,1,MOD_CONTROL|MOD_ALT,VK_F1);
 ::RegisterHotKey(m_hWnd,2,MOD_CONTROL|MOD_ALT,VK_F2);
 ::RegisterHotKey(m_hWnd,3,MOD_CONTROL|MOD_ALT,VK_F3);

 

在OnDestroy()取消注册

 UnregisterHotKey(m_hWnd,1);
 UnregisterHotKey(m_hWnd,2);
 UnregisterHotKey(m_hWnd,3);

2、在OnHotKey事件处理中写处理代码如下

LRESULT CSimWorkBenchDlg::OnHotKey(WPARAM wParam,LPARAM lParam)
{
 PROCESSENTRY32 pe32;
 switch(wParam)
 {
  case 1:
   SwitchWindowByProcessName(_T("matlab.exe"),&pe32);//这个函数的功能是根据程序的进程名切换窗口,具体功能稍后有写
   break;
  case 2:
   SwitchWindowByProcessName(_T("simworkbench.exe"),&pe32);
   break;
  case 3:
   SwitchWindowByProcessName(_T("devenv.exe"),&pe32);
   break;
 }
 return 0;
}

3、GetProcessEntryByProcessName函数根据程序的进程名,利用EnumWindows方法在系统进程中查找相应的窗口句柄,然后再用SetForegroundWindow方法将程序切换到最前面

GetProcessEntryByProcessName(TCHAR* processName,PROCESSENTRY32& pe32)

 HANDLE hProcessSnap;

 // 获取系统进程快照
 hProcessSnap = CreateToolhelp32Snapshot( TH32CS_SNAPPROCESS, 0 );
 if( hProcessSnap == INVALID_HANDLE_VALUE )
 {
  return FALSE;
 }

 // 使用PROCESSENTRY32结构前先设置它的大小
 pe32.dwSize = sizeof( PROCESSENTRY32 );

 // 在快照句柄中获取第一个进程
 if( !Process32First( hProcessSnap, &pe32 ) )
 {
  CloseHandle( hProcessSnap );     // 返回前必须关闭快照句柄
  return false;
 }

 // 遍历快照进程,如果查找到指定进程则返回成功
 do
 {
  if (_tcsicmp(processName, pe32.szExeFile) == 0)
  {
   ::EnumWindows(lpEnumFunc,(LPARAM)pe32.th32ProcessID);//回调函数lpEnumFunc中查找进程的窗口句柄,将进程ID作为参数传递过去
  }

 } while( Process32Next( hProcessSnap, &pe32 ) );

 CloseHandle( hProcessSnap );
 return true;

}

 

4、EnumWindows的回调函数lpEnumFunc中,查找进程窗口句柄,如果查找成功则使用SetForegroundWindow切换至最前面

int CALLBACK lpEnumFunc(HWND hwnd, LPARAM lParam)
{
 DWORD toFindPID = (DWORD)lParam;//获取要查找的目标进程ID
 DWORD processID;
 ::GetWindowThreadProcessId(hwnd, &processID);//获取当前窗口的进程ID
 DWORD curThreadID = ::GetCurrentThreadId();//当前线程ID
 DWORD toFindThreadID = ::GetWindowThreadProcessId(hwnd, &processID);//目标线程ID
 if (processID == toFindPID)//如果查找成功,则切换窗口至最前面
 {
  ::AttachThreadInput(toFindThreadID, curThreadID, TRUE);//这一步好像加不加都没什么影响

  /------------在这里我插入一段测试代码,获取当前窗口句柄的标题,在后面会具体说说作用---------/
  WINDOWINFO info;
  info.cbSize = sizeof(WINDOWINFO);
  TCHAR *pszItemText[1024];

  ::GetWindowInfo(hwnd,&info);

  /--------------完毕------------------/
 ::SetForegroundWindow(hwnd);
  ::AttachThreadInput(toFindThreadID, curThreadID, FALSE);
  return 0;
 }
 else
 {
  return 1;
 }
}

 

 

 

 

Code Snippet

整个程序按照上述方法实现,现在问题来了,就是::SetForegroundWindow(hwnd)这里,有的应用程序可以实现切换,比如matlab、vmware这些软件,而有的不可以,如devenv.exe(也就是VS.NET2005开发环境),有个现象值得注意,那就是matlab切换后这个软件的主窗口标题栏是激活状态(亮的),而vmware虽然切换成功了,但是主窗口标题栏不是激活状态(灰的),除了::SetForegroundWindow,我还试过其他很多种方法: 

有::SetWindowPos(hwnd, HWND_TOPMOST, 0, 0, 0, 0, SWP_NOMOVE|SWP_NOSIZE);
::SetWindowPos(hwnd, HWND_NOTOPMOST, 0, 0, 0, 0, SWP_NOMOVE|SWP_NOSIZE);
还有BringWindowToTop(hwnd)和SetActiveWindow(hwnd);

 

 

 

我在代码中加入了一段测试代码,获取查找成功后的窗口句柄它的标题值,发现有的能获取到标题,matlab就可以,有的是没有标题(但实际上这款软件的程序窗口是有标题的),个人认为很可能是有的程序获取到的这个窗口句柄并不是主窗口句柄,但是用: :GetParent(hwnd)或者: :GetWindow(hwnd,GW_OWNER)之类的方法也获取不到有父窗口句柄。这个问题究竟是怎么回事?请高手们给我指导指导:)

    本站是提供个人知识管理的网络存储空间,所有内容均由用户发布,不代表本站观点。请注意甄别内容中的联系方式、诱导购买等信息,谨防诈骗。如发现有害或侵权内容,请点击一键举报。
    转藏 分享 献花(0

    0条评论

    发表

    请遵守用户 评论公约

    类似文章 更多