描述
- 学习了下windows编程的知识,写了一个用于判断系统中只有一个进程的demo
预备知识
windows句柄
- win32 api中定义了多种句柄,本质上是指针,用于访问线程、文件、图片等系统资源,如
typedef void *HANDLE
动态库的加载方式
- 分为显式加载和隐式加载,链接
- 显式加载:在程序运行过程中,主动调用loadLibrary函数加载动态库,这种方式需要h文件和dll文件
- 隐式加载:在程序开始运行前,将库文件加载到内存中,使用pragma comment来加载lib文件,这种方式需要h文件、dll文件和lib文件
- 隐式加载配合延迟加载(更改vs设置),可以达到运行过程中加载的效果
- 当系统启动或终止进程或线程时,它会使用进程的第一个线程为每个加载的dll调用入口点函数(即dllMain);当使用loadlibrary或freelibrary函数加载或卸载dll时,系统也会调用入口点函数
win32 api编程
- 微软为了保护操作系统的安全性和稳定性,不允许运行在用户层的进程随意操控系统内核,而是必须按照一定方式。我们用户层要与系统内核层交互(比如对内存、进程操作),只能通过调用Windows内核层提供的接口函数,也就是Win32API来操控。这些API以DLL(动态链接库)的形式保存(在SYSTEM32文件夹中,你可以发现许多DLL文件),最常用的是kernel32.dll、user32.dll和gdi32.dll。实际上在Windows系统上的C/C++的运行库内部也是封装了Win32API。进一步说,所有运行在Windows用户层的程序必须得调用Win32API。
- 最常用的三个dll,微软就是靠这三个模块起家的,Windows SDK只利用这三个模块就能构建基本的Windows程序。
- user32.dll: 是Windows用户界面相关应用程序接口,用于包括Windows处理,基本用户界面等特性,如创建窗口和发送消息
- gdi32.dll: gdi32.dll是Windows GDI图形用户界面相关程序,包含的函数用来绘制图像和显示文字
- kernel32.dll: 控制着系统的内存管理、数据的输入输出操作和中断处理
C++作用域符
- 不加冒号:表示当前作用域
- 加冒号:表示只使用类或命名空间中的变量或函数
- 双冒号前不加东西是全局变量或函数的意思
windows共享内存
- 方式一:通过CreateFileMapping创建指定命名的内存映射文件对象
- 方式二:借助链接器#pragma,建立共享dll
windows会话隔离机制
- 第一个登录到控制台的用户来启动服务和应用程序,该会话被认为是服务会话,它包含了宿纳系统的服务的进程,该会话就称为session0,普通用户进程运行在session1以上会话
- 位于Session0会话的服务程序在Win7及以上(通常是NT内核6.0以上)是无法进行与UI进行通信的,想要与普通桌面进程通信需要借助WTS开头的函数
唯一实例demo
代码
#include "stdafx.h"
#include <Windows.h>
BOOL IsAlreadyRun()
{
HANDLE hMutex = NULL;
hMutex = ::CreateMutex(NULL, FALSE, "TEST");
if (hMutex)
{
if (ERROR_ALREADY_EXISTS == ::GetLastError())
{
return TRUE;
}
}
return FALSE;
}
int _tmain(int argc, _TCHAR* argv[])
{
if (IsAlreadyRun())
{
printf("This Program already have a process running!\n");
}
else
{
printf("NOT Already Running!\n");
}
system("pause");
return 0;
}
配置
- 平台工具集包含了msvc编译器,windows sdk包含了win32 api必要的dll和lib文件
- 动态库的配置
- 字符集的选择:不要使用unicode字符集,字符串类型转化会报错
运行结果
- 生成64位exe,只有61KB,依赖的user32.dll是系统自带的,只要把这个exe拷贝到目标机器就能运行,这就是win32 api编程得天独厚的优势!
- 运行多个实例的结果