【windows核心编程】 4 进程
【1】
windows程序分为GUI程序好CUI程序,即Graphical User Interface和Console User Interface
在Visual Studio中,GUI程序的链接开关是/SUBSYSTEM:WINDOWS, GUI程序的链接开关是/SUBSYSTEM:CONSOLE
这是一个控制台程序的设置。
windows程序的入口有以下两种:
1 Int WINAPI _tWinMain( 2 HINSTANCE hInstanceExe, //进程实例句柄 3 HINSTANCE , /*hPreInstance*/ //之前的实例,总为NULL 4 PTSTR, pszCmdLine, //命令行参数,包括exe名称 5 int nCmdShow 6 ); 7 8 9 10 int _tmain( 11 int argc, //参数个数,包含exe 12 TCHAR *argv[], //每个参数字符串 13 TCHAR *envp[] //进程环境变量指针数组 14 );
【2】
但是在调用上述入口函数之前,系统会调用真正的入口函数来做一些初始化的工作,比如初始化全局变量和静态C++对象的构造,下面说明了每种情况下的真正的入口函数
ANSI--------_tWinMain(WinMain)------------WinMainCRTStartup
UNICODE---_tWinMain(wWinMain)-----------wWinMainCRTStartup
ANSI--------_tmain(Main)--------------------mainCRTStartup
UNICODE----_tmain(wMain)------------------wmainCRTStartup
上面四个真正的入口函数的源码在C运行库的crtexe.c文件中。
【3】
HINSTANCE和HMODULE相同,可相互替代,只是在16位windows时代有所不同。
加载到进程地址空间的每个可执行文件和DLL都有一个唯一的实例句柄, HICON LoadIcon(HINSTANCE hInstance, PCTSTR pszZIcon)函数的作用是从实例句柄为hInstance的文件中加载名为pszIcon的图标资源。
可执行文件的实例被当作(w)WinMain函数的第一个参数(见上文),即参数 hInstanceExe, 这个参数的实际值是一个内存基地址,希望将可执行文件的映像加载到进程地址空间中的这个位置。
Visual Studio连接器默认的基地址是0x00400000, 这是在win98下,可执行文件所能加载到的最低的地址。使用MS的连接器/BASE:address开关可以更改基地址。
那么怎么样获得一个可执行文件或DLL被加载到进程地址空间的什么位置呢? 可用下函数:
HMODULE GetModuleHandle(PCTSTR pszModule)
加入A进程调用了一个可执行文件B和一个DLL名为C, 那么可以用这个函数来把B 或 C的名字作为pszModule参数传给它取得B或C在当前进程地址空间中的位置, 如果找到了该参数标明的可执行文件或DLL,那么将返回他们在进程地址空间中的位置,否则返回NULL。
如果给pszModule参数传NULL, 那么将返回调用此函数的进程即A进程的可执行文件的基地址。
1 #include "stdafx.h" 2 #include <iostream> 3 #include "windows.h" 4 5 int _tmain(int argc, _TCHAR* argv[]) 6 { 7 8 HMODULE hModue = GetModuleHandle(NULL); 9 10 printf("当前进程地址为:0x%08x\n", hModue); 11 12 PWSTR lpParams = GetCommandLineW(); //取得命令行参数,包括exe 13 14 int count = 0; 15 16 PWSTR *pRet = CommandLineToArgvW(lpParams, &count); //命令行参数和参数个数,包括exe; 该函数内部分配内存, 返回指针数组(指针的指针) 17 18 for (int i = 0; i < count; ++ i) 19 { 20 std::wcout<<pRet[i]<<std::endl; 21 } 22 23 24 return 0; 25 }
输出如下:
需要注意的是:上面函数CommandLineToArgvW在函数内部分配内存,且不释放,一般情况下是可以接收的,但是如果想要手动释放那部分内存也是可以的
HeapFree函数可以用来释放那部分内存:
HeapFree(GetProcessHeap(), 0, pRet); //pRet为上面CommandLineToArgvW函数的返回值。
1 PTSTR pszValue = NULL; 2 3 DWORD dwResult = GetEnvironmentVariable(_T("path"), pszValue, 0); 4 5 if (0 != dwResult) 6 { 7 pszValue = (PTSTR)malloc(size); 8 GetEnvironmentVariable(_T("path"), pszValue, size); 9 wcout<<pszValue<<endl; 10 11 free(pszValue); 12 }
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· AI与.NET技术实操系列:基于图像分类模型对图像进行分类
· go语言实现终端里的倒计时
· 如何编写易于单元测试的代码
· 10年+ .NET Coder 心语,封装的思维:从隐藏、稳定开始理解其本质意义
· .NET Core 中如何实现缓存的预热?
· 25岁的心里话
· 闲置电脑爆改个人服务器(超详细) #公网映射 #Vmware虚拟网络编辑器
· 零经验选手,Compose 一天开发一款小游戏!
· 通过 API 将Deepseek响应流式内容输出到前端
· AI Agent开发,如何调用三方的API Function,是通过提示词来发起调用的吗