通过进程ID获得该进程主窗口的句柄
     一个进程可以拥有很多主窗口,也可以不拥有主窗口,所以这样的函数是不存在的,所幸的是,相反的函数是有的。所以我们可以调用EnumWindows来判断所有的窗口是否属于这个进程。

typedef struct tagWNDINFO
 ...{
 DWORD dwProcessId;
 HWND hWnd;
 } WNDINFO, *LPWNDINFO;BOOL CALLBACK YourEnumProc(HWND hWnd,LPARAM lParam)
 ...{
 DWORD dwProcessId;
 GetWindowThreadProcessId(hWnd, &dwProcessId);
 LPWNDINFO pInfo = (LPWNDINFO)lParam;
 if(dwProcessId == pInfo->dwProcessId)
 ...{
 pInfo->hWnd = hWnd;
 return FALSE;
 }
 return TRUE;
 }
 HWND GetProcessMainWnd(DWORD dwProcessId)
 ...{
 WNDINFO wi;
 wi.dwProcessId = dwProcessId;
 wi.hWnd = NULL;
 EnumWindows(YourEnumProc,(LPARAM)&wi);
 return wi.hWnd;
 }


如果这个进程没有窗口,函数返回NULL
经试验,在宿主窗口中调用GetProcessMainWnd( GetCurrentProcessId() )后得到的窗口句柄有时确实是该窗口的句柄,但有时得到的却是DLL的窗口的句柄,而在DLL的窗口过程中调用GetProcessMainWnd( GetCurrentProcessId() )只得到DLL窗口的句柄,并不能得到宿主窗口的句柄。【将dll直接注入执行注入代码的exe中进行测试】

将该代码做如下修改后,能得到正确的宿主窗口句柄:

 

typedef struct tagWNDINFO
 {
  DWORD dwProcessId;
  HWND hWnd;
  HWND Dll_hwnd;
 } WNDINFO, *LPWNDINFO;BOOL CALLBACK YourEnumProc(HWND hWnd, LPARAM lParam)
 {
  DWORD dwProcessId;
  GetWindowThreadProcessId(hWnd, &dwProcessId);
  LPWNDINFO pInfo = (LPWNDINFO)lParam;
  if( (dwProcessId == pInfo->dwProcessId) && (hWnd != pInfo->Dll_hwnd) )
   //确认找到的句柄不是DLL窗口的句柄
   //如果找到的是DLL窗口的句柄则返回FALSE以便继续查找宿主的窗口句柄
  {
   pInfo->hWnd = hWnd;
   return FALSE;
  }
  return TRUE;
 }
 HWND GetProcessMainWnd(DWORD dwProcessId, HWND Dll_hwnd)
  //将DLL窗口的句柄传入,以便识别找到的句柄不是DLL窗口的句柄
 {
  WNDINFO wi;
  wi.dwProcessId = dwProcessId;
  wi.hWnd = NULL;
  wi.Dll_hwnd = Dll_hwnd;
  EnumWindows(YourEnumProc,(LPARAM)&wi);
  HWND re_hwnd = wi.hWnd;
  while( GetParent(re_hwnd) != NULL )
   //循环查找父窗口,以便保证返回的句柄是最顶层的窗口句柄
  {
   re_hwnd = GetParent( re_hwnd );
  }
  return re_hwnd;
 }  
 
HWND GetWindowHandleByPID(DWORD dwProcessID)
 {
  HWND h = GetTopWindow(0 );
  TCHAR szText[MAX_PATH] = {0};
  CString strMyText = L"类名";
  while ( h )
  {
   ::GetClassName(h,szText, MAX_PATH);
   if (strMyText != szText)
   {
    h = GetNextWindow( h , GW_HWNDNEXT);
    continue;
   }
   DWORD pid = 0;
   DWORD dwTheardId = GetWindowThreadProcessId( h,&pid);  if (dwTheardId != 0)
   {
    if ( pid == dwProcessID/*your process id*/ )
    {
     // here h is the handle to the window
     return h;
    }
   }
   h = GetNextWindow( h , GW_HWNDNEXT);
  }
  return NULL;
 }


通过进程ID获得该进程主窗口的句柄
     一个进程可以拥有很多主窗口,也可以不拥有主窗口,所以这样的函数是不存在的,所幸的是,相反的函数是有的。所以我们可以调用EnumWindows来判断所有的窗口是否属于这个进程。

typedef struct tagWNDINFO
 ...{
 DWORD dwProcessId;
 HWND hWnd;
 } WNDINFO, *LPWNDINFO;BOOL CALLBACK YourEnumProc(HWND hWnd,LPARAM lParam)
 ...{
 DWORD dwProcessId;
 GetWindowThreadProcessId(hWnd, &dwProcessId);
 LPWNDINFO pInfo = (LPWNDINFO)lParam;
 if(dwProcessId == pInfo->dwProcessId)
 ...{
 pInfo->hWnd = hWnd;
 return FALSE;
 }
 return TRUE;
 }
 HWND GetProcessMainWnd(DWORD dwProcessId)
 ...{
 WNDINFO wi;
 wi.dwProcessId = dwProcessId;
 wi.hWnd = NULL;
 EnumWindows(YourEnumProc,(LPARAM)&wi);
 return wi.hWnd;
 }


如果这个进程没有窗口,函数返回NULL
经试验,在宿主窗口中调用GetProcessMainWnd( GetCurrentProcessId() )后得到的窗口句柄有时确实是该窗口的句柄,但有时得到的却是DLL的窗口的句柄,而在DLL的窗口过程中调用GetProcessMainWnd( GetCurrentProcessId() )只得到DLL窗口的句柄,并不能得到宿主窗口的句柄。【将dll直接注入执行注入代码的exe中进行测试】

将该代码做如下修改后,能得到正确的宿主窗口句柄:

 



typedef struct tagWNDINFO
 {
  DWORD dwProcessId;
  HWND hWnd;
  HWND Dll_hwnd;
 } WNDINFO, *LPWNDINFO;BOOL CALLBACK YourEnumProc(HWND hWnd, LPARAM lParam)
 {
  DWORD dwProcessId;
  GetWindowThreadProcessId(hWnd, &dwProcessId);
  LPWNDINFO pInfo = (LPWNDINFO)lParam;
  if( (dwProcessId == pInfo->dwProcessId) && (hWnd != pInfo->Dll_hwnd) )
   //确认找到的句柄不是DLL窗口的句柄
   //如果找到的是DLL窗口的句柄则返回FALSE以便继续查找宿主的窗口句柄
  {
   pInfo->hWnd = hWnd;
   return FALSE;
  }
  return TRUE;
 }
 HWND GetProcessMainWnd(DWORD dwProcessId, HWND Dll_hwnd)
  //将DLL窗口的句柄传入,以便识别找到的句柄不是DLL窗口的句柄
 {
  WNDINFO wi;
  wi.dwProcessId = dwProcessId;
  wi.hWnd = NULL;
  wi.Dll_hwnd = Dll_hwnd;
  EnumWindows(YourEnumProc,(LPARAM)&wi);
  HWND re_hwnd = wi.hWnd;
  while( GetParent(re_hwnd) != NULL )
   //循环查找父窗口,以便保证返回的句柄是最顶层的窗口句柄
  {
   re_hwnd = GetParent( re_hwnd );
  }
  return re_hwnd;
 }