跨进程使用句柄和文件操作
使用句柄
1. 跨进程使用句柄
1)子进程继承父进程句柄的方式
将父进程的句柄放到子进程的句柄表里
1- 句柄本身可以被继承
2- Createprocess的参数bInheritHandles为TRUE
3- 继承已经打开的句柄
SECURITY_ATTRIBUTES sa;
sa.nLength = sizeof(sa);
sa.lpSecurityDescriptor = NULL;
2) 非父子进程使用句柄或者,在创建子进程之后打开的句柄
复制句柄 -- DuplicateHandle
HANDLE hTargetHandle;
DuplicateHandle(
GetCurrentProcess(),//源进程的进程句柄
hProcess, //拷贝的句柄
hProcessDst, //目标进程的进程句柄
&hTargetHandle, //给目标进程使用的值
0, //忽略
FALSE,
DUPLICATE_SAME_ACCESS); //目标进程的句柄和源进程的句柄有相同的权限
3) 窗口句柄可以直接跨进程使用
2. 进程间的通信
2.1 消息和WM_COPYDATA
1) 自定义消息 --参数不够用
2) WM_COPYDATA
通过WM_COPYDATA传递消息,操作系统会首先将发送的数据拷贝到高2GB共享区,然后再拷贝到接收方的用户空间中,所以会有两次拷贝,因此在数据量不大的时候,可以使用此方法。
使用 WM_COPYDATA 在进程间共享数据
消息作用:
在进程间共享数据(内部通过创建内存映射文件)
消息介绍:
需要用到的数据结构/类型:
typedef struct tagCOPYDATASTRUCT {
ULONG_PTR dwData;
DWORD cbData;
PVOID lpData;
} COPYDATASTRUCT, *PCOPYDATASTRUCT;
结构体参数说明:
dwData(ULONG) 保存一个数值, 可以用来作标志等
lpData(void*) 待发送的数据的起始地址(可以为NULL)
cbData(DWORD) 待发送的数据的长度
消息的参数:
hWnd: 接收数据的窗口的句柄
wParam: 传送该数据的窗口句柄(NULL也无所谓)
lParam: COPYDATASTRUCT类型变量的地址
使用示例:
COPYDATASTRUCT cds;
char msg[] = "女孩不哭";
cds.dwData = 0;
cds.lpData = msg;
cds.cbData = strlen(msg)+1; //字符串请记得把'\0'加上, 不然就错了, 这里是ANSI字符串
SendMessage(FindWindow("nbsg_class", NULL), WM_COPYDATA, 0, (LPARAM)&cds);
接收端对该消息的一种可能处理:
case WM_COPYDATA:
{
//这里的消息应该是以 '\0' 结尾的字符串
COPYDATASTRUCT* pCDS = (COPYDATASTRUCT*)lParam;
MessageBox(hWnd, pCDS->lpData, "", MB_OK);
return TRUE;
}
说明:
发送的数据可以是任意的, 我上面只是为了用MessageBox做测试, 所以发送的是以'\0'的字符串.
如果接收消息的应用程序处理了该消息, 它应该返回 TRUE , 否则返回 FALSE.
lpData 指向的内存应该是一段"数据", 就是说里面不应该有指向该程序某数据的指针. 因为 SendMessage 在处理 WM_COPYDATA 时, 只是把 lpData 指向的 cbData 个字节复制到共享内存中. 当前进程私有的指针就算是被发送到接收程序, 其也是无法访问的.
当该消息正当发送时, 该进程的其它线程不能修改其中的数据.
接收端应用程序应该把这段共享内存作为只读内存来访问. 请不要尝试修改其中的内容.
lParam 指向的数据只有在该消息处理时有效, 消息返回后无效(共享内存已被释放). 且接收端也不能释放该内存. 如果要在消息返回后继续取得数据, 可以把它复制到当前进程的某个位置.
共享段
1) 在dll中创建一个共享段,并在共享段中定义数据
#pragma data_seg( "CR33_DATA" ) //起始位置
int g_nVal = 9;
char szBuff[MAXBYTE] = { "hell world" };
#pragma data_seg() //结束位置
2) 将共享段的属性设置为可读,可写,可共享(重点)
#pragma comment(linker, "/SECTION:CR33_DATA,RWS")
3) 导出共享段中定义的数据
文件操作
打开文件 CreateFile
关闭文件 CloseHandle
读 ReadFile
写 WriteFile
文件指针 SetFilePointer
文件的大小 GetFileSize
1. CreateFile
这个函数的功能是创建或者打开一个文件或者I/O设备,通常使用的I/O形式有文件、文件流、目录、物理磁盘、卷、终端流等。如执行成功,则返回文件句柄。 INVALID_HANDLE_VALUE 表示出错,会设置 GetLastError 。
HANDLE CreateFile(
LPCTSTR lpFileName, //普通文件名或者设备文件名
DWORD dwDesiredAccess, //访问模式(写/读)
DWORD dwShareMode, //共享模式
LPSECURITY_ATTRIBUTES lpSecurityAttributes, //指向安全属性的指针
DWORD dwCreationDisposition, //如何创建
DWORD dwFlagsAndAttributes, //文件属性
HANDLE hTemplateFile //用于复制文件句柄
);
参数 |
类型描述 |
lpFileName |
String ,要打开的文件的名字 |
dwDesiredAccess |
Long ,如果为 GENERIC_READ 表示允许对设备进行读访问;如果为 GENERIC_WRITE 表示允许对设备进行写访问(可组合使用);如果为零,表示只允许获取与一个设备有关的信息 |
dwShareMode |
Long ,零表示不共享; FILE_SHARE_READ 和 / 或 FILE_SHARE_WRITE 表示允许对文件进行共享访问 |
lpSecurityAttributes |
SECURITY_ATTRIBUTES ,指向一个 SECURITY_ATTRIBUTES 结构的指针,定义了文件的安全特性(如果操作系统支持的话) |
dwCreationDisposition |
Long ,下述常数之一: CREATE_NEW 创建文件; 如文件存在则会出错 CREATE_ALWAYS 创建文件,会改写前一个文件;相当于删除原来文件重新写入。文件如果不存在会创建文件。 OPEN_EXISTING 文件必须已经存在。由设备提出要求; OPEN_ALWAYS 如文件不存在则创建它; TRUNCATE_EXISTING 将现有文件缩短为零长度 |
dwFlagsAndAttributes |
Long ,一个或多个下述常数: FLE_ATTRIBUTE_ARCHIVE 标记归档属性; FILE_ATTRIBUTE_COMPRESSED 将文件标记为已压缩,或者标记为文件在目录中的默认压缩方式; FILE_ATTRIBUTE_NORMAL 默认属性; FILE_ATTRIBUTE_HIDDEN 隐藏文件或目录; FILE_ATTRIBUTE_READONLY 文件为只读; FILE_ATTRIBUTE_SYSTEM 文件为系统文件; FILE_FLAG_WRITE_THROUGH 操作系统不得推迟对文件的写操作; FILE_FLAG_OVERLAPPED 允许对文件进行重叠操作;FILE_FLAG_NO_BUFFERING 禁止对文件进行缓冲处理。文件只能写入磁盘卷的扇区块; FILE_FLAG_RANDOM_ACCESS 针对随机访问对文件缓冲进行优化; FILE_FLAG_SEQUENTIAL_SCAN 针对连续访问对文件缓冲进行优化 ; FILE_FLAG_DELETE_ON_CLOSE 关闭了上一次打开的句柄后,将文件删除。特别适合临时文件; |
hTemplateFile |
Long ,如果不为零,则指定一个文件句柄。新文件将从这个文件中复制扩展属性 |
2. ReadFile
从文件指针指向的位置开始将数据读出到一个文件中, 且支持同步和异步操作,如果文件打开方式没有指明FILE_FLAG_OVERLAPPED的话,当程序调用成功时,它将实际读出文件的字节数保存到lpNumberOfBytesRead指明的地址空间中。FILE_FLAG_OVERLAPPED 允许对文件进行重叠操作。
BOOL ReadFile(
HANDLE hFile, //文件的句柄
LPVOID lpBuffer, //用于保存读入数据的一个缓冲区
DWORD nNumberOfBytesToRead, //要读入的字节数
LPDWORD lpNumberOfBytesRead, //指向实际读取字节数的指针
LPOVERLAPPED lpOverlapped
//如文件打开时指定了FILE_FLAG_OVERLAPPED,那么必须,用这个参数引用一个特殊的结构。
//该结构定义了一次异步读取操作。否则,应将这个参数设为NULL
);
WriteFile
BOOL WINAPI WriteFile(
__in HANDLE hFile, // 文件句柄
__in LPCVOID lpBuffer, // 要写入的数据
__in DWORD nNumberOfBytesToWrite, // 要写入的字节数
__out LPDWORD lpNumberOfBytesWritten, // 实际写入的字节数
__in LPOVERLAPPED lpOverlapped // OVERLAPPED 结构,一般设定为 NULL
)