如何获取某个进程的主窗口以及创建进程的程序名?

如何获取某个进程的主窗口以及创建进程的程序名 在编写工具程序以及系统管理程序的时候。常常需要获取某个进程的主窗口以及创建此进程的程序名。获取主窗口的目的是向窗口发送各种消息。获取启动进程的程序名可以控制对进程的操作。但是有些进程往往有多个主窗口。你要的是哪一个主窗口呢?如果你用过Outlook程序,你就会发现它有多个主窗口,一个窗口列出收件箱和其它文件夹。如果你打开e-mail,便会有另外一个窗口显示信息。它们都是没有父窗口(或者说宿主窗口)的主窗口。运行一下Spy程序,你甚至会发现它们的窗口类名都相同:rctrl_renwnd32。资源管理器(Exp 阅读详情

如何获取某个进程的主窗口以及创建进程的程序名?


编译/northtibet

下载源代码

    在编写工具程序以及系统管理程序的时候。常常需要获取某个进程的主窗口以及创建此进程的程序名。获取主窗口的目的是向窗口发送各种消息。获取启动进程的程序名可以控制对进程的操作。但是有些进程往往有多个主窗口。你要的是哪一个主窗口呢?如果你用过Outlook程序,你就会发现它有多个主窗口,一个窗口列出收件箱和其它文件夹。如果你打开e-mail,便会有另外一个窗口显示信息。它们都是没有父窗口(或者说宿主窗口)的主窗口。运行一下Spy程序,你甚至会发现它们的窗口类名都相同:rctrl_renwnd32。资源管理器(Explorer.exe)也有不止一个主窗口。如图一所示,资源管理器有两个主窗口。一般来讲,想要获取主窗口,凭窗口的式样或类名,你没有什么办法知道哪一个窗口是真正意义上的主窗口。
首先我们讨论如何从多个窗口中获取主窗口?其实很容易。利用两个API函数便可以实现。这两个API是 EnumWindows 和 GetWindowThreadProcessId。如果你对这两个函数不熟悉,不要怕,本文提供了一个C++类来对这两个API进行封装。这个类叫 CMainWindowIterator,用它可以枚举某个进程(已知进程ID)的所有主窗口。这正是我们想要的东西。其使用方法如下:

DWORD pid = // 已知某个进程的ID
CMainWindowIterator itw(pid);
for (HWND hwnd = itw.First(); hwnd; hwnd=itw.Next()) {
  // do something
}    
    就这么简单,CMainWindowIterator派生于一个更通用的类:CWindowIterator,CWindowIterator负责将::EnumWindows函数打包以隐藏回调细节。它有一个虚拟函数OnWindow,你可以在派生类中重写这个函数,从而可以用任何方式来枚举窗口。CMainWindowIterator就是重写了OnWindow函数,让它只获取属于某个给定进程的主窗口:
// (在构造函数中设置m_pid)
BOOL CMainWindowIterator::OnWindow(HWND hwnd)
{
  if ((GetWindowLong(hwnd,GWL_STYLE) & WS_VISIBLE)) {
    DWORD pidwin;
    GetWindowThreadProcessId(hwnd, &pidwin);
    if (pidwin==m_pid)
      return TRUE;
  }
  return FALSE;
}
这两个类的定义如下:(对应的文件是 EnumProc.h 和 EnumProc.cpp)
//////////////////////////////////////////////////////
// 这个类主要是封装::EnumWindows,列举顶层窗口
//
class CWindowIterator {
protected:
	HWND*	m_hwnds;		// 隶属于某个进程PID窗口句柄数组
	DWORD m_nAlloc;			// 数组大小
	DWORD m_count;			// 找到的窗口句柄数
	DWORD m_current;		// 当前的窗口句柄
	static BOOL CALLBACK EnumProc(HWND hwnd, LPARAM lp);

	// 虚拟枚举函数
	virtual BOOL OnEnumProc(HWND hwnd);

	// 在派生中改写此函数来过滤不同种类的窗口
	virtual BOOL OnWindow(HWND hwnd) {
		return TRUE;
	}

public:
	CWindowIterator(DWORD nAlloc=1024);
	~CWindowIterator();
	
	DWORD GetCount() { return m_count; }
	HWND First();
	HWND Next() {
		return m_hwnds && m_current <m_count ? m_hwnds[m_current++] : NULL;
	}
};

////////////////////////////////////
// 列举某个进程的顶层窗口
//
class CMainWindowIterator : public CWindowIterator  {
protected:
	DWORD m_pid;		// 进程ID
	virtual BOOL OnWindow(HWND hwnd);
public:
	CMainWindowIterator(DWORD pid, DWORD nAlloc=1024);
	~CMainWindowIterator();
};
图一是用上述C++类编写的一个控制台程序lp.exe的输出画面。最后两栏分别是对应进程的“窗口句柄”和“类名/窗口标题”。其命令行开关“/ct”表示列出窗口类名(c)和窗口标题(t)。

图一

    一般来讲,如果隶属于某个进程的窗口没有可见的父窗口,那么这个窗口就可以认为是此进程的主窗口。对WS_VISIBLE的检查很重要,因为有些应用创建多个不可见的顶层窗口。关于CMainWindowIterator类的使用细节请参见本文的例子源代码。 
接下来我们来讨论如何获取创建进程的程序文件名。有人用各种方法尝试过,比如:GetModuleFileName,GetModuleInstance 和 GetModuleHandle,好像都不行。为什么呢?其实,方法是没错,但调用这些函数得到的只是当前正在运行的这个进程已经加载的模块名(modules),不能用于获取其它进程所加载的模块。因此,必须想别的办法,首先要考虑两种情况,一种是如果你写的程序在Windows NT,Windows 2000,Windows XP环境运行,则可以使用PSAPI,这是一个Windows操作系统中比较新的DLL,利用其中输出的API函数可以获取进程和模块的详细信息。另一种是如果你写的程序在Windows 9x或者Windows Me中运行,则必须借助于ToolHelp,限于本文的篇幅,我在这里不介绍如何使用ToolHelp,如果你感兴趣的话可以参考,MSDN的技术支持文章Q175030,题目为“如何在Win32中枚举应用程序”。
    PSAPI中有一个函数是GetModuleFileNameEx。它通过某个进程和模块句柄作为参数来获得模块名。那么对于某个进程来说,你怎么知道哪个模块是启动进程的执行文件呢呢?PSAPI中的另一个函数EnumProcessModules将某个进程中所有模块的模块句柄填充到一个数组中。这个数组的第一个元素便是主模块的句柄,所以你用下面的代码来得到第一个HMODULE:
DWORD count;
HMODULE hm[1];
EnumProcessModules(hProcess, hm, 1, &count);      
然后调用GetModuleFileNameEx。
实际上从前面的图一中可以看到,在lp.exe程序中我们已经实现了罗列进程及其对应的模块名。程序的实现细节中还用到了PSAPI输出的API函数EnumProcesses来枚举所有运行进程,为了对具体的细节进行封装,我如法炮制编写了与CWindowIterator 和CMainWindowIterator类似的两个C++类:CProcessIterator 和 CProcessModuleIterator ,它们分别对EnumProcesses 和EnumProcessModules API函数进行了封装。有了这两个打包类,一切都变得如此简单。
CProcessIterator itp;
for (DWORD pid=itp.First(); pid; pid=itp.Next()) {
  // 处理每一个进程
}
下面是获取创建进程的EXE文件名的方法:
CProcessModuleIterator itm(pid);
HMODULE hModule = itm.First(); // .EXE
TCHAR modname[_MAX_PATH];
GetModuleBaseName(itm.GetProcessHandle(), hModule, modname, _MAX_PATH);
    因为lp显示出来的并不是一个含全路径的模块文件名,所以我用另外一个PSAPI函数GetModuleBaseName来代替GetModuleFileNameEx从而获取全路径名。此外,由于CProcessModuleIterator自己会打开进程枚举模块,所以不必调用OpenProcess。用CProcessModuleIterator::GetProcessHandle可以得到已打开进程的句柄。lp程序还用CMainWindowIterator来显示每个特定进程的所有主窗口。下面是CProcessIterator 和 CProcessModuleIterator的定义:
////////////////////////////////////////////////////////////////////////////////////////
// 进程列举类 -- 列举出系统中的所有进程,但总是跳过第一个PID=0的进程,即空闲进程(IDLE)
//
class CProcessIterator {
protected:
	DWORD*	m_pids;			// 包含进程IDs的数祖
	DWORD		m_count;	// 数组大小
	DWORD		m_current;	// 当前数组项
public:
	CProcessIterator();
	~CProcessIterator();

	DWORD GetCount() { return m_count; }
	DWORD First();
	DWORD Next() {
		return m_pids && m_current <m_count ? m_pids[m_current++] : 0;
	}
};

/////////////////////////////////////////////////////////////////
// 列举某个进程的模块,第一个模块就是创建此进程的主exe程序
//
class CProcessModuleIterator {
protected:
	HANDLE	m_hProcess;			// 进程句柄
	HMODULE*	m_hModules;		// 模块句柄数组
	DWORD		m_count;		// 数组大小
	DWORD		m_current;		// 当前模块的句柄
public:
	CProcessModuleIterator(DWORD pid);
	~CProcessModuleIterator();

	HANDLE GetProcessHandle()	{ return m_hProcess; }
	DWORD GetCount()				{ return m_count; }
	HMODULE First();
	HMODULE Next() {
		return m_hProcess && m_current < m_count ? m_hModules[m_current++] : 0;
	}
};   

通过进程名查找窗口句柄并杀死进程 如何获取某个进程的主窗口以及创建进程的程序名? 编译/northtibet 下载源代码 在编写工具程序以及系统管理程序的时候。常常需要获取某个进程的主窗口以及创建此进程的程序名。获取主窗口的目的是向窗口发送各种消息。获取启动进程的程序名可以控制对进程的操作 阅读详情

相关推荐

根据进程id查找主窗口

根据网上代码描述修改实现 根据进程id查找主窗口 不指定id,则查找全部的顶层窗口 指定进程id,则查找该进程的顶层窗口

获取窗口标题

一个关于获得窗口标题的问题, 不过只是针对部分窗口出现错误, 望高手指教.  我使用方法1:  ZeroMemory(szWndTitle, sizeof(szWndTitle));  GetWindowText(hWnd, szWndTitle, sizeof(TCHAR)*MAX_PATH);  或SendMessage(hWnd, WM_GETTEXT, (WPARAM)MAX_

yazi1297的专栏 1107

在 CentOS7 下安装 Cadence IC验证平台 INCISIVE152

前言 本文所使用的软件 虚拟机软件:VMware Workstation 15 PRO 如何安装? 操作系统:CentOS-7, CentOS-7-x86_64-DVD-1810.iso 如何安装? 简介 INCISIVE Incisive是nc_verilog, nc_sim, nc_lauch,以及ABV,TBV的集合,用于仿真和验证。 InstallScape InstallSc...

沈醉不知的博客 2万+

电脑cmd指令大全

FOR /参数 %variable IN (set) DO command [command_parameters] %variable:指定一个单一字母可替换的参数,如:%i ,而指定一个变量则用:%%i ,而调用变量时用:%i% ,变量是区分大小写的(%i 不等于 %I)。(set):指定一个或一组文件,可使用通配符,如:(D:user.txt)和(1 1 254)(1 -1 254),{ “(1 1 254)”第一个"1"指起始值,第二个"1"指增长量,第三个"254"指结束值,即:从1到254;

xiaoqixiaoguai的博客 1万+

保姆级教程:用GPU-Burn给你的NVIDIA Tesla服务器做个“压力体检”(附温度功耗监控脚本)

本文提供了一份详细的GPU服务器压力测试指南,重点介绍如何使用GPU-Burn工具对NVIDIA Tesla服务器进行全面的性能测试和温度功耗监控。从环境部署、多GPU测试策略到专业级监控指标解析,帮助运维人员构建标准化的GPU健康评估体系,确保AI训练和科学计算等关键业务的稳定性。

weixin_30619101的博客 395

深度学习(Deep Learning, DL)简介

深度学习(Deep Learning, DL)是机器学习的一个子领域,主要使用多层神经网络来处理复杂的数据和任务。深度学习通过模拟人脑的神经网络结构,能够自动提取特征并进行高效的模式识别和预测。

qq_28791753的博客 1万+

如何获取某个进程的主窗口以及创建进程的程序名(进程映像名)

在编写工具程序以及系统管理程序的时候。常常需要获取某个进程的主窗口以及创建此进程的程序名。获取主窗口的目的是向窗口发送各种消息。获取启动进程的程序名可以控制对进程的操作。但是有些进程往往有多个主窗口。你要的是哪一个主窗口呢?如果你用过Outlook程序,你就会发现它有多个主窗口,一个窗口列出收件箱和其它文件夹。如果你打开e-mail,便会有另外一个窗口显示信息。它们都是没有父窗口(或者说宿主窗口)

System Architect 2686

从零开始安装pytorch(包含GPU和CPU版本的安装)

Pytorch是。

qiaoxinyu1989的博客 8万+

历史经验之如何获取某个进程的主窗口以及创建进程的程序名

日期:2003-6-20 操作环境 Windows2000 Server;VC6.0 问题描述 在系统启动时,老是弹出一个广告窗口,想把它删除,但又找不到该窗口执行文件的位置;在服务里也找不到相关的程序;在任务管理器中有但分不清是哪一个。 解决办法 先用VC工具“Spy++”,查找到该程序的进程ID,然后在网上(http://www.vckbase.com/document/viewdoc.asp?id=404)找到这样一篇文章《如何获取某个进程的主窗口以及创建进程的程序名》,并下载源代码,并编译执行该程序

上善若水的博客 370

AI智算-K8s+vLLM & Ray:DeepSeek-r1 671B 满血版分布式推理部署实践

自从上次发布 【AI-智算】K8s+SGLang实战:DeepSeek-r1:671b满血版多机多卡私有化部署全攻略] 文章后,本次将演示另一个主流推理引擎工具——vLLM,结合K8s、LWS、Ray、Volcano等技术栈,部署DeepSeek-r1 671b 满血版分布式推理集群,并对比其与SGLang推理引擎的性能表现。

Kason_iWiki 1823

【Unity工具篇】| Unity项目中如何使用LuBan插件,详细集成步骤

前面写了一篇文章用于介绍LuBan的下载及快速使用方法:【Unity实战篇】| 实用插件LuBan,快速上手使用 本篇文章就来介绍一下将LuBan集成到自己的Unity项目的方法。 看完本篇文章之后,就可以直接把LuBan插件放到自己项目中进行配表和使用。

努力前行,总会成为自己心中的那道光 2万+

通过进程ID获取进程主窗口句柄

typedef struct tagWNDINFO { DWORD dwProcessId; HWND hWnd; }WNDINFO, *LPWNDINFO; BOOL CALLBACK YourEnumProc(HWND hWnd, LPARAM lParam) { DWORD dwProcessId; GetWindow

baggiowangyu的专栏 5066

C# 上位机内存泄漏排查指南:3 个工具 + 4 个技巧,从 GC 频繁到稳定运行 720 小时

C# 上位机内存泄漏排查的核心是「先定位泄漏存在,再追溯引用根源,最后修复验证通过「Visual Studio 诊断工具(快速定位)+ dotMemory(深度分析)+ PerfView(生产监控)」三个工具的配合,结合「复现场景、排查静态成员+事件、检查非托管资源、GC 日志验证」四个技巧,可高效解决绝大多数泄漏问题。

这里只有干货:从 Modbus 通信到 MES 对接,从 YOLO 训练到工控机部署,带你搞定工业软件开发全流程。 735

1.创建进程

1.创建进程实验目的为什么要创建进程?实验内容程序框架父进程框架子进程框架需要用到的函数CreateProcess 实验目的 学会通过基本的Windows进程控制函数,由父进程创建子进程。 为什么要创建进程? 我们设计一个应用程序时,有时候需要另外一段代码做一些其他工作,方法如下: 函数调用或者子程序: 但是我们调用函数后只能等待函数返回。 在进程内创建一个新线程: 但在一个复杂应用系统中,我们有可能不慎改写了进程地址空间中的某些数据(例如某些引用数据),导致其它工作不能正确地进行。 创建新进程(子进程)

qinian1841128521的博客 1298

如何使用PostgreSQL数据库进行数据仓库的ETL操作

本文旨在为数据工程师、数据库管理员和分析师提供使用PostgreSQL进行数据仓库ETL操作的全面指南。ETL流程的基本原理PostgreSQL在ETL中的独特优势实际ETL实现的技术细节性能优化和最佳实践常见问题的解决方案首先介绍ETL和PostgreSQL的基本概念然后深入探讨核心技术和实现方法接着提供实际案例和代码示例最后讨论优化技巧和未来趋势ETL:提取(Extract)、转换(Transform)、加载(Load)的缩写,描述数据从源系统移动到目标数据仓库的过程。

2502_91592937的博客 873

怀旧版电脑GBC模拟器

再现原版GBC掌机的界面,电脑运行连游戏界面都一样大小,很怀旧,很真实,(英文版)强烈推荐,很小的文件,很难才找到的。

window下启动另外一个进程和给进程发送消息

判断一个程序是否启动,并给一个进程发送信息 #include "Switch2.h" #include <tchar.h> #include <psapi.h> /// /// 判断软件是否已经启动 /// /// struct ProcessWindow { DWORD dwProcessId; HWND hWnd; }; // 查找进程主窗口的回调函数 BOOL CALLBACK EnumWindowCallBack(HWND hWnd, LPARAM lParam)

simple_core的博客 1375

Data-Structures-and-Algorithm-Analysis-in-Java.pdf

作者: Weiss, Mark A. 出版社: Addison Wesley Data Structures and Algorithm Analysis in Java is an “advanced algorithms” book that fits between traditional CS2 and Algorithms Analysis courses. In the old ACM Curriculum Guidelines, this course was known as CS7. This text is for readers who want to learn good programming and algorithm analysis skills simultaneously so that they can develop such programs with the maximum amo...

根据进程名称获取窗口句柄

// WinWnd.cpp : 定义 DLL 应用程序的导出函数。 // #include "stdafx.h" #include "WinWnd.h" #include&lt;stdio.h&gt; #include&lt;Windows.h&gt; #include&lt;TlHelp32.h&gt; #include&lt;iostream&gt; using namespace std...

xzpblog 7775

IDEA的使用指南

IDEA基于java的使用手册,可以最快速的上手,在使用中不断的丰富自己的使用技巧.

TMS_WebGMaps_1.9.8.0_Full_Source

TMS_WebGMaps_1.9.8.0_Full_Source 全源码 delphi cbuilder

VC中通过程序名称找到窗口句…

原文地址:VC中通过程序名称找到窗口句柄作者:Sloovy最近实在是忙的……上班太忙,下班回来不想写东西,光想玩游戏,我彻底成程序员了?而且为什么我这个本来想做游戏关卡设计师的人会和进程现程句柄死磕上了呢……郁闷死我了,这就是要自己承担未来的条件吗? 废话再少也多,贴代码…… 更新的附带一提 在新写的MfcLayout的程序里面有这套Utils源代码了。http://blog.sina.co

daregone_3824的专栏 552

遍历指定程序名窗口上的所有控件

using System; using System.Collections.Generic; using System.ComponentModel; using System.Data; using System.Drawing; using System.Linq; using System.Text; using System.Windows.Forms; using ...

weixin_30858241的博客 837

C++ 判断进程是否存在

一、判断指定程序名的进程是否存在 BOOL EnumWindows( WNDENUMPROC lpEnumFunc, // pointer to callback function LPARAM lParam // application-defined value); The EnumWindows function enumerates all top-level windows on the screen by passing the handle to each window, in turn

顺其自然~专栏 6918

在VC++应用程序中彻底清除进程

在VC++应用程序中彻底清除进程读者朋友们可能经常会碰到这样一个问题,想对某些进行操作时,发现这些文件正在被其它程序使用,处于打开状态,而且是被独占打开,这时是没法对文件进行操作的。因此,要想操作这些文件,必须将打开这些文件的进程清除掉。那么如何干净地清除进程呢?其实,在Windows2000操作系统版本中有一个工具程序叫tskill.exe,用它就可以清除掉某个程序的进程,在输入“tskil

jiangxinyu的专栏 1065
上一篇: boost源码剖析之:多重回调机制signal(下)
下一篇: 获得 Win32 窗口句柄的更好的方法 ----动态生成并显示 HTML 文档 ----再谈禁用HTML的上下文菜单...
ShenRui
博客等级 码龄20年 63粉丝 36原创
评论 1
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值