当前位置: 首页 > news >正文

地铁公司招聘信息网站搜索公司信息的软件

地铁公司招聘信息网站,搜索公司信息的软件,网站开发工具的选择,余姚网站建设哪家好目录 进程间通信概述 发送消息 WM_COPYDATA DLL共享段 文件映射 文件相关API CreateFile ReadFile WriteFile CloseHandle SetFilePointerEx 设置文件指针 获取文件大小 GetFileSize 结构体 LARGE_INTEGER 文件映射用于读写文件数据 文件映射用于进程间通信(带文…目录 进程间通信概述 发送消息 WM_COPYDATA DLL共享段 文件映射 文件相关API CreateFile ReadFile WriteFile CloseHandle SetFilePointerEx 设置文件指针 获取文件大小 GetFileSize 结构体 LARGE_INTEGER 文件映射用于读写文件数据 文件映射用于进程间通信(带文件) 文件映射用于进程间通信(无文件) 管道 父子进程之间的匿名管道通信 GetStdHandle 设置安全属性子进程继承父进程 STARTUPINFO指定句柄 模拟CMD 进程间通信概述 进程间通信Inter-Process CommunicationIPC是指不同进程之间进行数据交换、信息共享、同步互斥等操作的机制。 在 Windows 操作系统中实现进程间通信的方法有多种包括但不限于 管道Pipe管道是一种半双工的通信机制可以实现两个进程之间的通信支持同步和异步通信。命名管道Named Pipe与管道类似但可以通过命名方式在进程间共享。共享内存Shared Memory可以在多个进程之间共享数据可以用来实现高效的数据传输。消息队列Message Queue提供了异步、无关的进程间通信方式支持发送和接收消息每个消息都有一个优先级。套接字Socket可用于不同计算机间的进程间通信提供了可靠的数据传输支持 TCP 和 UDP 协议。WM_COPYDATA 消息是一种基于 Windows 消息传递机制的进程间通信方式可以实现小量数据的传输。Windows 消息队列Window Message QueueWindows 操作系统提供了一种基于消息队列的通信机制可以在不同的进程间传递消息。它通过SendMessage和PostMessage函数向其他进程发送Windows消息其他进程则可以通过相应的消息回调函数来处理这些消息。 这些方法各有优缺点具体应该根据实际场景选择合适的通信方式。 发送消息 WM_COPYDATA 不建议使用 SendMessage 函数发送消息 使用SendMessage函数实现进程间最简单的数据传输。SendMessage是Windows API中的一个函数它可以将消息发送到指定窗口的消息队列中并等待接收该消息的线程处理完毕。因为Windows中每个进程都至少拥有一个主窗口所以可以通过在不同的进程中创建主窗口来实现进程间的通信。 使用 SendMessage 发送消息虽然简单但也有一些缺陷 同步阻塞SendMessage 函数会阻塞发送消息的进程直到接收到回应为止。如果接收进程无响应发送进程就会一直阻塞。这种同步阻塞的方式可能会导致进程之间的通信效率较低。只能在同一个桌面窗口之间进行通信SendMessage 函数只能在同一个桌面窗口中的不同线程之间进行通信不能跨越不同的桌面窗口进行通信。数据大小限制SendMessage 函数发送的数据大小不能超过 WPARAM 类型的数据大小即 32 位系统下最大只能传输 4 字节的数据64 位系统下最大只能传输 8 字节的数据。 WM_COPYDATA是一个Windows消息用于在进程之间传递数据。它使用的结构体是COPYDATASTRUCT其中包含了以下三个参数 dwData一个可以自定义的数据值可以用于标识传递的数据类型或其他用途。cbData传递数据的字节数不能超过64KB。lpData指向实际数据的指针。 使用通过SendMessage发送 缺点 数据的传输是单向的。效率低从A进程拷贝到B进程 数据拷贝了 2 次。先将数据拷贝到高 2 G内存中然后再从 高 2 G拷贝到目标进程中发生两次拷贝所以效率比较低必须是带有窗口之间才能通信且必须有标题; 原理通过系统的高2G内存来达到传输因为高 2 G的内存是所有引用共享的。 适用场景数据小发送频繁等不建议使用大小不限制。 SendMessage( (HWND) hWnd, // handle to destination window WM_COPYDATA, // message to send(WPARAM) wParam, // handle to window (HWND)(LPARAM) lParam // data (PCOPYDATASTRUCT)); 参数解析 目的地窗口句柄消息ID传递数据的窗口句柄。你也可以不填指向包含要传递的数据的COPYDATASTRUCT结构体的指针。 当一个进程发送WM_COPYDATA消息给另一个进程时它需要填充COPYDATASTRUCT结构体的这三个参数并使用SendMessage或PostMessage函数将消息发送给目标进程的窗口句柄。接收进程在处理WM_COPYDATA消息时可以使用CopyMemory或其他函数从COPYDATASTRUCT结构体中读取传递的数据。 需要注意的是因为数据是通过拷贝传递的所以当接收进程修改数据时不会对发送进程产生影响。另外由于数据拷贝的性质WM_COPYDATA在传递大量数据时可能会导致性能问题因此需要注意数据大小的限制。 typedef struct tagCOPYDATASTRUCT { ULONG_PTR dwData; //对缓冲区类型的描述【相当于一个标志】DWORD cbData; //缓冲区地址PVOID lpData; //缓冲区大小 二者合二为一描述一个缓冲区 } COPYDATASTRUCT, *PCOPYDATASTRUCT; 创建两个工程一个发送、一个接收 发送端 接收端 在接收方使用类向导选择消息创建WM_COPYDATA消息 BOOL CMFCTestDlg::OnCopyData(CWnd* pWnd, COPYDATASTRUCT* pCopyDataStruct) {CString strFmt;strFmt.Format(Size:%d,:%s, pCopyDataStruct-cbData,pCopyDataStruct-lpData);AfxMessageBox(strFmt);return CDialogEx::OnCopyData(pWnd, pCopyDataStruct); }发送方 void CMFCTestDlg::OnBnClickedButton1() {//获取编辑框内容CString strText;GetDlgItemText(EDT_SEND, strText);//获取窗口句柄HWND hWnd ::FindWindow(NULL,接收标题);COPYDATASTRUCT cds;cds.dwData NULL;cds.cbData strText.GetLength()1;cds.lpData strText.GetBuffer();::SendMessage(hWnd,WM_COPYDATA,(WPARAM)GetSafeHwnd(),(LPARAM)cds); }使用WM_COPYDATA消息进行进程间通信我修改A进程的发送数据B进程接收到数据会受影响吗如果A进程通过WM_COPYDATA消息向B进程发送数据那么B进程接收到的数据不会受到A进程后续的修改影响。因为WM_COPYDATA消息是将A进程的数据拷贝一份并发送给B进程的之后B进程操作的是自己的一份拷贝和A进程的数据无关。所以A进程修改数据不会影响B进程接收到的数据。 其中发送进程通过发送WM_COPYDATA消息向接收进程发送数据。在接收进程接收到数据后发生了两次内存拷贝第一次是将数据拷贝至共享内存中第二次是从共享内存中读取数据。最后接收进程向发送进程发送响应消息。WM_COPYDATA可以携带少量数据效率比较低 是因为WM_COPYDATA先将数据拷贝到高2G系统内存中,再从高2G内存中拷贝到目标进程中发生两次拷贝。 WM_COPYDATA 消息进行进程间通信的主要缺陷有 消息大小受限WM_COPYDATA 消息传递的数据大小受到系统限制默认为 4MB。如果需要传递更大的数据就需要将数据分成多个块来传递。性能问题WM_COPYDATA 消息需要进行两次内存拷贝一次是从发送进程的地址空间复制数据到内核缓冲区另一次是从内核缓冲区复制数据到接收进程的地址空间这可能会影响系统性能。安全性问题WM_COPYDATA 消息传递的数据不进行加密如果传递的数据包含敏感信息可能会被非法获取。 DLL共享段 当不同的进程加载同一个 DLL 时该 DLL 的代码和数据将在每个进程的虚拟地址空间中有所不同但是该 DLL 的所有实例都共享同一份物理内存。这就是所谓的共享 DLL可以在多个进程中重用。 当一个进程加载一个 DLL 时该进程会将该 DLL 的实例映射到该进程的虚拟地址空间中。如果多个进程加载同一个 DLL则每个进程都将其映射到其自己的虚拟地址空间中。虽然每个进程都有自己的虚拟地址空间但是它们共享同一个物理内存这样就可以实现共享代码和数据的目的。 共享 DLL 的一个主要好处是节省了内存空间因为多个进程可以共享同一份物理内存这可以减少系统资源的消耗。此外共享 DLL 还可以提高系统的性能和稳定性因为它们可以在多个进程中重用而不需要每个进程都加载自己的 DLL 实例。这可以减少系统资源的浪费提高系统的性能和可靠性。 发消息有局限性用sendMessage第一个参数限制了只能给带有窗口的进程发送消息所以用dll共享段。 关于dll在之前的学习中如果dll导出一个全局变量给不同的进程使用的时候这个全局变量在不同的进程中是不会相互影响的因为有写时拷贝dll共享段:允许全局变量在不同的进程之间操作那时候数据是共享的 创建了一个包含共享变量和函数的 DLL 文件的基本流程 创建一个 DLL 文件其中包含定义在共享段中的变量和函数。使用 #pragma data_seg 指令指定变量在共享段中的位置使用 #pragma comment(linker, “/SECTION:,READ,WRITE,SHARED”) 指令将共享段导出。 注意#pragma comment 语句不能有中文空格注意: dll里面可以共享结构体和类但是不能共享指针编写应用程序将 DLL 文件加载到内存中。在应用程序中定义与 DLL 中共享变量相同的变量并将其放置在共享段中。调用 DLL 中的函数以读取或修改共享变量。 下面是一个示例其中创建了一个包含共享变量和函数的 DLL 文件并在应用程序中加载该 DLL从而实现进程间通信 1. 定义共享段并定义导出变量注意导出需要初始化未初始化不给实际内存。 #pragma data_seg(CR40SharedSection) //开始 __declspec(dllexport) DWORD g_dwVal 0; #pragma data_seg()//结束的位置2. 链接选项将此共享段声明为可共享。 #pragma comment(linker, /SECTION:CR40SharedSection,RWS)3. 使用方加上extern且不能给值。只是单纯的声明声明该变量在其他文件中找 __declspec(dllimport) extern DWORD g_dwVal;在上面的代码中使用 #pragma data_seg 将** g_nVal** 变量放置在名为 dll_share 的共享段中。使用 #pragma comment(linker, /SECTION:dll_share ,RWS) 指令将共享段导出并使其可读、可写和可共享。 dll共享段的变量不能通过监视窗口查看查看方法给个中间变量进行中转查看。 使用方 #pragma comment(lib,DLLShare.lib) __declspec(dllimport) int g_nVal; void CMFCTestDlg::OnBnClickedButton1() {SetDlgItemInt(EDT_SHOW,g_nVal); }void CMFCTestDlg::OnBnClickedButton2() {g_nVal GetDlgItemInt(EDT_WRITE);}如果全局变量不初始化的话进程间不共享。 在DLL共享段中已经初始化为0的全局变量和未初始化的全局变量之间的主要区别在于它们被处理的方式不同。已经初始化为0的全局变量通常被编译器放在数据段.data段中因此它们在DLL加载到内存时已经被初始化为0。因为它们已经被初始化所以它们的值可以被不同的进程共享而且不同进程中的值都是相同的。未初始化的全局变量通常被编译器放在BSS段.bss段中这些变量在程序加载时会被清零。因为它们在程序加载时才被初始化所以它们的值在不同的进程中是不同的不能被不同进程共享。 因此在使用DLL共享段时我们应该尽可能地将全局变量初始化为0以确保它们可以被不同进程共享并且在不同进程中的值都是相同的。 未初始化的全局变量默认值是0存放在BSS段中是为了节省空间因为它们的默认值已经是0可以在程序运行时清零不需要在程序文件中存储它们的初始值。 已经初始化为0的全局变量在程序文件中需要存储它们的初始值所以它们通常会被编译器放在数据段.data段中而不是BSS段。但是存放在数据段中的全局变量通常不需要在程序运行时进行初始化因为它们的初始值已经被编译器放在程序文件中了。因此在程序加载到内存时数据段中的全局变量已经被初始化为它们的初始值其中初始化为0的全局变量的值也已经是0了。 需要注意的是如果在使用DLL共享段时全局变量初始化为0的话通常建议将它们放在数据段中以确保它们可以被不同进程共享并且在不同进程中的值都是相同的。但是在一些特定的场景中全局变量初始化为0的话也可以放在BSS段中这取决于具体的实现方式和编译器设置。 文件映射 进程间通信中的文件映射是一种共享内存的方式通过将一个文件映射到多个进程的虚拟地址空间实现进程之间的数据共享。 文件映射是一种进程间通信的机制可以通过将一个文件映射到多个进程的虚拟地址空间来实现数据的共享。在文件映射中可以分为有文件和无文件的区别。 有文件的文件映射是指将一个实际的文件映射到多个进程的虚拟地址空间中。这意味着映射的数据源是一个文件进程可以通过读取、写入共享内存区域来访问和修改文件的内容。在这种情况下文件映射的数据是持久的即文件的内容在进程结束后仍然存在。 无文件的文件映射是指在进程间通信中使用文件映射的机制但并不依赖于实际的文件。相反进程可以通过创建一个匿名的文件映射对象将其映射到多个进程的虚拟地址空间中。在这种情况下映射的数据源并不是一个实际的文件而是系统内存中的一块共享内存区域。进程可以通过读取、写入共享内存区域来进行进程间的数据交换。与有文件的文件映射相比无文件的文件映射的数据是临时的即在进程结束后会被释放。 无文件的文件映射通常用于临时共享数据、进程间通信等场景不需要将数据持久保存在文件中。相比起有文件的文件映射无文件的文件映射更加灵活和高效因为它不需要文件的读写操作而是直接在内存中进行数据的交换。然而无文件的文件映射也需要注意数据同步和共享内存的管理以确保数据的一致性和安全性。 文件相关API CreateFile 函数是 Win32 API 中用于打开或创建文件或设备的主要函数之一还有一些与之相关的函数如下所示 OpenFile 函数与 CreateFile 函数类似用于打开文件但是它比 CreateFile 函数更受限制只能打开一些预定义的文件类型。ReadFile 函数用于从文件或设备中读取数据。WriteFile 函数用于向文件或设备中写入数据。CloseHandle 函数用于关闭已打开的文件或设备句柄。FlushFileBuffers 函数用于将文件或设备的缓冲区中的数据刷新到磁盘或设备中。SetFilePointer 函数用于设置文件或设备指针的位置。GetFileSize 函数用于获取文件或设备的大小。CreateFileMapping 函数用于创建文件映射对象实现进程间共享内存的目的。 CreateFile HANDLE CreateFile(LPCTSTR lpFileName, // 文件或设备的名称DWORD dwDesiredAccess, // 访问权限DWORD dwShareMode, // 共享模式LPSECURITY_ATTRIBUTES lpSecurityAttributes, // 安全描述符DWORD dwCreationDisposition, // 文件的创建方式DWORD dwFlagsAndAttributes, // 文件属性HANDLE hTemplateFile // 模板文件句柄 );参数说明 lpFileName文件名或设备名可以是一个字符串指针或一个字符数组表示要创建或打开的文件或设备的名称。可以是绝对路径名也可以是相对路径名。dwDesiredAccess访问权限是一个32位的无符号整数指定要对文件或设备进行的访问类型。其值可以是以下常量之一或它们的组合如果需要打开文件或设备以读取它们的内容则必须将 dwDesiredAccess 设置为 GENERIC_READ 或 GENERIC_ALL如果需要向文件或设备写入数据则必须将其设置为 GENERIC_WRITE 或 GENERIC_ALL如果需要同时进行读写则必须将其设置为 GENERIC_READ | GENERIC_WRITE 或 GENERIC_ALL。 GENERIC_READ读取文件数据或从设备读取数据。GENERIC_WRITE向文件写入数据或向设备写入数据。GENERIC_EXECUTE运行文件或设备。GENERIC_ALL具有完全访问权限的文件或设备。dwShareMode共享模式是一个32位的无符号整数指定其他进程可以对文件或设备进行哪些类型的访问。其值可以是以下常量之一或它们的组合如果要允许其他进程访问文件或设备则必须将 dwShareMode 设置为 FILE_SHARE_READ、FILE_SHARE_WRITE 或它们的组合如果要防止其他进程访问文件或设备则可以将其设置为 0。 FILE_SHARE_READ其他进程可以读取文件或设备。FILE_SHARE_WRITE其他进程可以写入文件或设备。FILE_SHARE_DELETE其他进程可以删除文件。0不共享文件或设备。lpSecurityAttributes安全描述符是一个指向 SECURITY_ATTRIBUTES 结构体的指针用于指定文件或设备的安全属性。该参数可以为 NULL表示不需要安全属性。dwCreationDisposition创建方式是一个32位的无符号整数指定要创建或打开的文件或设备的行为。其值可以是以下常量之一通常如果要创建新文件则应将 dwCreationDisposition 设置为 CREATE_NEW 或 CREATE_NEW如果文件不存在则创建文件如果文件存在则打开失败。CREATE_ALWAYS如果文件不存在则创建文件如果文件存在则覆盖原文件。OPEN_EXISTING如果文件存在则打开文件如果文件不存在则打开失败。OPEN_ALWAYS如果文件存在则打开文件如果文件不存在则创建文件。TRUNCATE_EXISTING如果文件存在则将其截断为零长度如果文件不存在则打开失败。 通常如果要创建新文件则应将 dwCreationDisposition 设置为 CREATE_NEW 或不完整以下是剩余的参数解释 dwFlagsAndAttributes文件或设备属性是一个32位的无符号整数用于指定文件或设备的属性。其值可以是以下常量之一或它们的组合可以将以上常量按位或组合在一起以指定文件或设备的多个属性。 FILE_ATTRIBUTE_ARCHIVE文件或目录是存档文件或目录。FILE_ATTRIBUTE_COMPRESSED文件或目录已压缩。FILE_ATTRIBUTE_DIRECTORY文件或目录是目录。FILE_ATTRIBUTE_HIDDEN文件或目录是隐藏的。FILE_ATTRIBUTE_NORMAL文件或目录没有其他属性。FILE_ATTRIBUTE_READONLY文件或目录是只读的。FILE_ATTRIBUTE_SYSTEM文件或目录是系统文件或目录。hTemplateFile模板文件句柄是一个用于指定要创建的文件或设备的模板文件的句柄。该参数通常为 NULL。 返回值如果函数调用成功则返回一个文件句柄该句柄可用于读取、写入、关闭、重命名或删除文件。如果函数调用失败则返回 INVALID_HANDLE_VALUE。函数调用失败后可以调用 GetLastError() 函数来获取错误代码。 使用CreateFile函数创建文件时需要注意以下几点 在创建文件之前需要确保路径名和文件名的格式是正确的。在指定访问权限和共享模式时需要根据实际需求进行设置以便其他进程能够访问需要共享的部分。在指定文件的创建方式时需要考虑文件是否存在以及是否需要覆盖已有文件。在指定文件属性时需要根据实际需求进行设置例如是否需要将文件设置为只读、隐藏等。在指定模板文件句柄时需要确保模板文件的属性和新文件的属性相匹配。 ReadFile ReadFile 函数用于从文件中读取数据并将读取的结果存储在指定的缓冲区中。如果读取成功函数将返回实际读取的字节数并将该值存储在 lpNumberOfBytesRead 参数中。 BOOL ReadFile(HANDLE hFile,//文件句柄即文件的唯一标识符用于标识需要读取的文件。LPVOID lpBuffer,//缓冲区指针指向用于存放读取结果的缓冲区。DWORD nNumberOfBytesToRead,//要读取的字节数。LPDWORD lpNumberOfBytesRead,//实际读取的字节数由函数返回。LPOVERLAPPED lpOverlapped//异步操作参数用于指定异步操作的相关信息。 ); 下面是每个参数的解释 hFile要读取的文件的句柄。句柄是一个标识文件或其他对象的唯一整数值它允许操作系统跟踪对象的状态和位置。句柄可以由调用CreateFile或OpenFile函数返回。lpBuffer指向用于接收读取数据的缓冲区的指针。读取的数据将被存储在这个缓冲区中。nNumberOfBytesToRead要读取的字节数。这个参数指定从文件中读取的字节数最大为DWORD类型的最大值。lpNumberOfBytesRead指向实际读取的字节数的指针。这个参数用于返回实际读取的字节数。如果没有读取任何字节则此参数的值为零。lpOverlapped指向异步I/O操作的重叠结构体的指针。如果要进行异步I/O操作则必须传递指向重叠结构体的指针。否则此参数应为NULL。 总之ReadFile函数的作用是从指定的文件中读取指定数量的字节并将读取的数据存储到指定的缓冲区中。如果读取成功函数将返回TRUE并且实际读取的字节数将存储在lpNumberOfBytesRead参数中。如果读取失败则返回FALSE。 返回值 如果函数调用成功返回值为非零TRUE。如果函数调用失败返回值为零FALSE。此时可以使用 GetLastError 函数获取错误码 注意事项 在调用 ReadFile 函数之前需要通过 CreateFile 函数打开需要读取的文件并获取文件句柄。要确保缓冲区足够大能够存储 nNumberOfBytesToRead 个字节的数据。如果读取的字节数小于 nNumberOfBytesToRead可能是因为到达了文件末尾或者遇到了错误。此时需要检查 GetLastError 函数返回的错误码来判断出现了什么问题。 WriteFile WriteFile函数是一个非常常用的函数用于实现数据的写入操作。它是Windows操作系统中文件和设备操作的重要组成部分可以帮助我们方便地读写文件和设备实现数据交换和通信。 BOOL WriteFile(HANDLE hFile, // 文件或设备对象的句柄LPCVOID lpBuffer, // 待写入数据的缓冲区DWORD nNumberOfBytesToWrite,// 待写入数据的长度LPDWORD lpNumberOfBytesWritten, // 实际写入的数据长度LPOVERLAPPED lpOverlapped // 重叠操作结构指针 ); 参数说明 hFile指定文件或设备对象的句柄必须是使用CreateFile函数创建或打开的句柄。lpBuffer指向待写入数据的缓冲区可以是一个字符数组、结构体、或者其他类型的数据。nNumberOfBytesToWrite指定待写入数据的长度以字节数为单位。lpNumberOfBytesWritten指向一个DWORD类型的变量用于接收实际写入的数据长度。lpOverlapped指向一个OVERLAPPED结构体用于指定重叠操作的相关信息通常设置为NULL。 返回值函数返回一个BOOL类型的值表示是否成功写入数据。如果函数执行成功返回值为TRUE否则返回FALSE。使用WriteFile函数可以向已经打开的文件、设备或管道中写入数据。它可以用于写入二进制数据、文本数据等各种类型的数据 注意事项 写入的数据不能超过文件或设备的可用空间如果文件或设备已经被其他程序打开可能会发生访问冲突需要进行异常处理如果需要进行异步写入操作需要使用重叠操作和异步I/O技术写入数据时需要保证数据的正确性和完整性。 CloseHandle BOOL CloseHandle(HANDLE hObject // 待关闭句柄 ); 参数说明 HANDLE hObject待关闭句柄。该参数是一个HANDLE类型的句柄指定要关闭的句柄。句柄是操作系统为每个打开的对象分配的唯一标识符用于引用该对象。返回值BOOL类型表示是否成功关闭句柄。如果函数执行成功返回值为TRUE否则返回值为FALSE。 注意事项 CloseHandle函数只是关闭句柄并释放相关的系统资源并不会对句柄所代表的对象进行其他的操作。例如如果关闭了一个文件的句柄该文件并不会被删除或关闭。因此在使用CloseHandle函数关闭句柄之前需要确保相关的对象已经完成了所需的操作。 此外CloseHandle函数只能关闭通过CreateFile等打开对象的句柄。如果使用其他方式获得了句柄例如使用malloc函数分配内存后得到的指针这些句柄不能用CloseHandle函数关闭。 总之CloseHandle函数是Windows操作系统中一个重要的API函数用于关闭一个句柄并释放相关的系统资源。我们应该在使用完句柄后及时调用CloseHandle函数以确保程序的正常运行。 SetFilePointerEx 设置文件指针 文件指针 SetFilePointer/SetFilePointerEx 【可以指定大于4G的文件】 DWORD SetFilePointer( HANDLE hFile, // handle to fileLONG lDistanceToMove, // 低 4G 地址PLONG lpDistanceToMoveHigh, // 高 4G 地址两个DWORD拼接成一个32位DWORD dwMoveMethod // 文件指针偏移【或从标志中选择】 );设置文件指针 BOOL SetFilePointerEx( HANDLE hFile, // handle to fileLARGE_INTEGER liDistanceToMove, // 64位的地址值PLARGE_INTEGER lpNewFilePointer, // new file pointerDWORD dwMoveMethod // starting point); 获取文件大小 GetFileSize 获取文件大小 GetFileSize/GetFileSizeEx BOOL GetFileSizeEx( HANDLE hFile, // handle to filePLARGE_INTEGER lpFileSize // file size ); DWORD GetFileSize( HANDLE hFile, // handle to fileLPDWORD lpFileSizeHigh // high-order word of file size ); 结构体 LARGE_INTEGER 结构体 LARGE_INTEGER PS共用体可以直接用QuadPart同时也可以拿高8位和低8位 typedef union _LARGE_INTEGER { struct {DWORD LowPart; LONG HighPart; };LONGLONG QuadPart; } LARGE_INTEGER, *PLARGE_INTEGER; 测试代码 // FileOpt.cpp : 此文件包含 main 函数。程序执行将在此处开始并结束。 //#include iostream #include Windows.h using namespace std; int main() {HANDLE hFile CreateFile(R(E:\CR41\第2阶段\Windows\07-进程间通信\FIleMap\test.txt),GENERIC_READ | GENERIC_WRITE,FILE_SHARE_READ,NULL, //安全属性OPEN_EXISTING, //打开已经存在的文件FILE_ATTRIBUTE_NORMAL, //文件属性 默认NULL);if (hFile INVALID_HANDLE_VALUE){cout 打开文件失败 endl;return 0;}char aryBuf[MAXBYTE] {};DWORD dwBytesReaded 0;BOOL bRet ReadFile(hFile,aryBuf,sizeof(aryBuf),dwBytesReaded,NULL);if (!bRet){cout 读取文件失败 endl;}DWORD dwRet SetFilePointer(hFile, 0x2000, NULL, FILE_BEGIN);if (dwRet INVALID_SET_FILE_POINTER){cout 移动文件指针失败 endl;}BYTE aryBufForWrite[] { hello world file hahahahaha. };DWORD dwBytesWrited 0;bRet WriteFile(hFile,aryBufForWrite,sizeof(aryBufForWrite),dwBytesWrited,NULL);if (!bRet){cout 写入文件失败 endl;}//关闭文件CloseHandle(hFile);return 0; } 文件映射用于读写文件数据 使用文件映射File Mapping操作文件的具体步骤如下 打开文件首先需要打开需要操作的文件可以使用标准的文件操作函数如CreateFile等来打开文件。创建文件映射对象使用CreateFileMapping函数创建一个文件映射对象该函数会返回一个句柄该句柄可以用于后续的文件映射操作。映射文件到内存使用MapViewOfFile函数将文件映射到内存中该函数也会返回一个指针该指针指向文件在内存中的起始位置。执行读写操作通过操作内存中的数据来进行读写操作内存中的数据会自动同步到文件中。取消文件映射使用UnmapViewOfFile函数取消文件映射释放内存空间。关闭文件句柄使用CloseHandle函数关闭文件句柄和文件映射对象句柄。 CreateFileMapping HANDLE CreateFileMapping( HANDLE hFile, // handle to fileLPSECURITY_ATTRIBUTES lpAttributes, // 安全属性DWORD flProtect, // 保护属性从表中选【对象用途】DWORD dwMaximumSizeHigh, // high-order DWORD of size【通常填 0】DWORD dwMaximumSizeLow, // low-order DWORD of size 【通常填 0】LPCTSTR lpName // 进程间共享就填值否则填NULL【映射对象的名字用于打开映射对象】 ); 功能创建一个文件映射对象。参数 hFile要映射的文件句柄。 lpAttributes安全性属性用于控制该文件映射对象的访问权限。 flProtect访问保护方式可以是 PAGE_READONLY、PAGE_READWRITE 等。 dwMaximumSizeHigh 和 dwMaximumSizeLow文件映射对象的最大大小以字节为单位。可以使用GetFileSize函数获取文件的大小。 lpName文件映射对象的名称可以为 NULL。 返回值如果函数执行成功则返回文件映射对象的句柄如果执行失败则返回 NULL。dwMaximumSizeHigh 和 dwMaximumSizeLow 填 0 文件多大文件映射对象就有多大。--------------------------- 保护属性表 ---------------------------------- PAGE_READONLY 只读 PAGE_READWRITE 读写--------------------------- 保护属性表 ---------------------------------- MapViewOfFile LPVOID MapViewOfFile(HANDLE hFileMappingObject, //文件映射对象句柄DWORD dwDesiredAccess, // 映射进内存的保护属性【读写可读可写】DWORD dwFileOffsetHigh, //从文件的哪个位置开始映射两个DWORD拼接成一个QWordDWORD dwFileOffsetLow, // SIZE_T dwNumberOfBytesToMap // 指定映射文件的大小 ); 功能将一个文件映射到进程的地址空间。参数hFileMappingObject文件映射对象的句柄。 dwDesiredAccess访问权限可以是 FILE_MAP_READ读取权限、FILE_MAP_WRITE写入权限等。 dwFileOffsetHigh 和 dwFileOffsetLow文件偏移量表示文件映射的起始位置以字节为单位。 dwNumberOfBytesToMap映射的字节数。 lpBaseAddress指向映射的起始地址。如果指定为 NULL则由系统自动分配地址。 返回值如果函数执行成功则返回映射视图的指针如果执行失败则返回 NULL。 --------------------------- 内存属性表 ---------------------------------- FILE_MAP_WRITE 写可读可写只需给写 FILE_MAP_READ 读 FILE_MAP_ALL_ACCESS 所有 FILE_MAP_WRITE FILE_MAP_COPY 拷贝 OpenFileMapping HANDLE OpenFileMapping(DWORD dwDesiredAccess, // access modeBOOL bInheritHandle, // 是否继承句柄LPCTSTR lpName // 打开已经映射到内存的对象【必须是已经映射的对象名称】 );BOOL UnmapViewOfFile( LPCVOID lpBaseAddress ); // 映射视图的首地址通过Map ViewOfFile获取。UnmapViewOfFile BOOL UnmapViewOfFile( LPCVOID lpBaseAddress ); // 映射视图的首地址通过MapViewOfFile获取。 进程最大内存是4G 但是3 环的最大内存从理论讲是2G当文件大于2G的时候就不够了所以需要将文件一段一段的映射这段内存将由我们指定。 测试代码 HANDLE hFile CreateFile(E:\\CR40\\windows\\05\\Dll共享段\\Debug\\Use.exe,GENERIC_READ | GENERIC_WRITE,FILE_SHARE_READ,//共享读NULL,OPEN_EXISTING,FILE_ATTRIBUTE_NORMAL,NULL);shared_ptrHANDLE pFileHandle(hFile, [](HANDLE hFile) {CloseHandle(hFile); });if (pFileHandle.get() INVALID_HANDLE_VALUE){std::cout 打开文件失败 std::endl;return 0;}//创建文件映射对象HANDLE hFileMap CreateFileMapping(hFile, NULL,PAGE_READWRITE,0, 0,//整个文件CR40SharedMappingFile);shared_ptrHANDLE pFileMap(hFileMap, [](HANDLE hFileMap) {CloseHandle(hFileMap); });if (pFileMap.get() NULL){std::cout 创建文件映射对象失败 std::endl;return 0;}LPVOID pBuff MapViewOfFile(hFileMap,FILE_MAP_ALL_ACCESS, //可读可写0, 0, //从文件头开始0x1000);//映射0x1000到内存if (pBuff NULL){std::cout 创建文件映射对象失败 std::endl;return 0;}//使用示例打开同一个文件。A修改B也被修改B修改A里面也被修改。//取消映射UnmapViewOfFile(pBuff);//由于使用了智能指针所以不需要手动释放。 文件映射用于进程间通信(带文件) 将A进程已经映射进虚拟内存B通过打开映射对象对齐进行操作使用。 PS安全属性需注意容易出错。 A方 A创建文件映射对象第五个参数需要填写文件对象名称。 B方 1. 打开文件已经映射的对象CreateFileMapping/OpenFileMapping2. 将文件映射到内存MapViewOfFile3. 使用4. 将文件从内存撤销映射UnmapViewOfFile5. 关闭文件映射对象Closehandle6. 关闭文件CloseHandle测试代码 A 方//打开文件//创建映射文件对象,注意需要填写映射对象名称方便B方使用//将文件对象映射进内存//对文件操作//撤销映射等反初始化操作B方 //打开文件映射对象HANDLE hFileMap OpenFileMapping(FILE_MAP_ALL_ACCESS, FALSE, CR40SharedMappingFile);shared_ptrHANDLE pFileMap(hFileMap, [](HANDLE hFileMap) {CloseHandle(hFileMap); }); //智能指针。if (pFileMap.get() NULL){std::cout 创建文件映射对象失败 std::endl;return 0;}//将对象指的文件映射进内存LPVOID pBuff MapViewOfFile(hFileMap,FILE_MAP_ALL_ACCESS, //可读可写0, 0, //从文件头开始0x1000);//映射0x1000到内存if (pBuff NULL){std::cout 创建文件映射对象失败 std::endl;return 0;}//使用//取消映射UnmapViewOfFile(pBuff); 文件映射用于进程间通信(无文件) 创建步骤 创建文件映射对象CreateFileMapping将文件映射到内存MapViewOfFile使用。。。。将文件从内存撤销映射UnmapViewOfFile关闭文件映射对象Closehandle关闭文件CloseHandle 使用步骤 打开文件映射对象CreateFileMapping/OpenFileMapping将文件映射到内存MapViewOfFile使用。。。。将文件从内存撤销映射UnmapViewOfFile关闭文件映射对象Closehandle关闭文件CloseHandle 测试代码 A 方 唯一区别创建文件映射对象时候的参数不同//创建文件映射对象HANDLE hFileMap CreateFileMapping(INVALID_HANDLE_VALUE,NULL,PAGE_READWRITE, //保护属性0, 0x1000, //注意点必须添值CR40SharedMappingFile);if (hFileMap NULL){std::cout 创建文件映射对象失败 std::endl;return 0;}LPVOID pBuff MapViewOfFile(hFileMap,FILE_MAP_ALL_ACCESS, //可读可写0, 0, //从文件头开始0x1000);//映射0x1000到内存if (pBuff NULL){std::cout 创建文件映射对象失败 std::endl;return 0;}//使用//取消映射UnmapViewOfFile(pBuff);return 0;B方 //打开文件映射对象HANDLE hFileMap OpenFileMapping(FILE_MAP_ALL_ACCESS, FALSE, CR40SharedMappingFile);shared_ptrHANDLE pFileMap(hFileMap, [](HANDLE hFileMap) {CloseHandle(hFileMap); }); //智能指针。if (pFileMap.get() NULL){std::cout 创建文件映射对象失败 std::endl;return 0;}//将对象指的文件映射进内存LPVOID pBuff MapViewOfFile(hFileMap,FILE_MAP_ALL_ACCESS, //可读可写0, 0, //从文件头开始0x1000);//映射0x1000到内存if (pBuff NULL){std::cout 创建文件映射对象失败 std::endl;return 0;}//使用//取消映射UnmapViewOfFile(pBuff); 管道 概念可跨进程的队列。实现进程之间的数据传输。 种类命名管道匿名管道。 命名管道主要用于服务器。【双向传输】 匿名管道主要用于父子进程之间的数据传输。【单向传输】 命名管道命名管道是一种有名字的管道它可以被多个进程同时使用。命名管道在创建时必须指定一个唯一的名称其他进程可以通过该名称来访问管道。命名管道使用CreateNamedPipe()函数创建使用CreateFile()函数打开。命名管道适用于本地进程之间的通信和远程进程之间的通信。 匿名管道匿名管道是一种无名的管道它只能被创建它的进程和它的子进程使用。匿名管道使用CreatePipe()函数创建它返回两个句柄一个是读句柄一个是写句柄。这两个句柄只能被创建它们的进程和它的子进程使用。 创建匿名管道,首先你要明白什么是管道. 管道你可以想象成一个管子。我们通过这个管子发送数据. 通过上图,我们就知道其实创建了两个管道分别是父进程读取的管道以及子进程读取的管道相应的子进程也可以对父进程读取的管道进行传输数据父进程就可以读取了这段话可能难以理解你可以这样想我父进程读取子进程使用第一个管道那么反过来正子进程的话也是使用第一个管道因为子进程写我们父进程才能读。 相关API BOOL CreatePipe(PHANDLE hReadPipe,管道读取句柄PHANDLE hWritePipe,管道写入矩形LPSECURITY_ATTRIBUTES lpPipeAttributes, 安全属性结构体决定是否能够继承管道DWORD nSize填NULL使用默认缓冲区大小 );hReadPipe一个指向用于保存管道的读端句柄的指针。 hWritePipe一个指向用于保存管道的写端句柄的指针。 lpPipeAttributes用于设置管道的安全属性一般为 NULL表示使用默认安全属性。 nSize用于设置管道的缓冲区大小一般为 0表示使用系统默认值。功能为各种函数创建对象提供安全设置。 例如CreateFile、CreatePipe、CreateProcess、RegCreateKeyEx或RegSaveKeyEx。 typedef struct _SECURITY_ATTRIBUTES {DWORD nLength; //此结构体大小必填LPVOID lpSecurityDescriptor; //BOOL bInheritHandle; //决定是否能够被继承 } SECURITY_ATTRIBUTES, *PSECURITY_ATTRIBUTES, *LPSECURITY_ATTRIBUTES;读ReadFile写WriteFile获取句柄:GetStdHandle HANDLE GetStdHandle( DWORD nStdHandle // input, output, or error device );STD_INPUT_HANDLE 标准输入 STD_OUTPUT_HANDLE 标准输出 STD_ERROR_HANDLE 标准错误 查看管道是否有数据可读PeekNamedPipe BOOL PeekNamedPipe( HANDLE hNamedPipe, // handle to pipeLPVOID lpBuffer, // data bufferDWORD nBufferSize, // size of data bufferLPDWORD lpBytesRead, // number of bytes readLPDWORD lpTotalBytesAvail, // number of bytes availableLPDWORD lpBytesLeftThisMessage // unread bytes ); hNamedPipe一个命名管道或匿名管道的句柄。 lpBuffer一个指向缓冲区的指针用于存储从管道中读取的数据。如果为 NULL则不读取数据。 nBufferSize缓冲区的大小。 lpBytesRead一个指向变量的指针用于存储已读取的字节数。 lpTotalBytesAvail一个指向变量的指针用于存储当前管道中可用的字节数。 lpBytesLeftThisMessage一个指向变量的指针用于存储当前消息中剩余的字节数。该参数只对消息式管道有效对字节流式管道没有意义。 CreatePipe函数创建一个匿名管道并返回两个句柄管道的读取句柄和管道的写入句柄。读取句柄对管道具有只读访问权限并且写入句柄对管道具有只写访问权限。若要使用管道进行通信管道服务器必须将管道句柄传递到另一个进程。 通常这是通过继承完成的;也就是说进程允许子进程继承句柄。 该过程还可以使用 DuplicateHandle 函数复制管道句柄并使用某种形式的进程间通信例如 DDE 或共享内存将其发送到无关的进程。 管道服务器可以将读取句柄或写入句柄发送到管道客户端具体情况取决于客户端是否应使用匿名管道来发送信息或接收信息。 若要从管道读取请在调用 ReadFile 函数时使用管道的读取句柄。 当另一个进程写入管道时 ReadFile 调用返回。 如果管道的所有写入句柄已关闭或在完成读取操作之前发生错误则 ReadFile 调用也可以返回。 若要写入管道请在调用 WriteFile 函数时使用管道的写入句柄。 WriteFile 调用在向管道写入指定的字节数或发生错误之前不会返回。 如果管道缓冲区已满并且有更多的字节需要写入则 WriteFile 不会返回直到另一个进程从管道中读取内容从而提供更多的缓冲区空间。 管道服务器在调用 CreatePipe时指定管道的缓冲区大小。 匿名管道不支持异步 (重叠) 读和写操作。 这意味着不能将 ReadFileEx 和 WriteFileEx 函数与匿名管道一起使用。 此外当将这些函数与匿名管道一起使用时将忽略 ReadFile和 WriteFile的 lpOverlapped 参数。 匿名管道存在直到所有管道句柄都已关闭。 进程可以使用 CloseHandle 函数关闭其管道句柄。进程终止时所有管道句柄也会关闭。使用具有唯一名称的命名管道实现匿名管道。 因此通常可以将句柄传递给需要命名管道的句柄的函数。 测试代码 //创建管道 void CMyTestPipDlg::OnClickedBtnCreate() {SECURITY_ATTRIBUTES sa {};sa.nLength sizeof(sa);sa.bInheritHandle TRUE;if (!CreatePipe(m_hRead, m_hWrite, sa, 0)){AfxMessageBox(管道创建失败);} }//写按钮 void CMyTestPipDlg::OnClickedBtnWrite() {CString str;GetDlgItemText(EDT_WRITE, str);DWORD dwBytesWrited 0;if (!WriteFile(m_hWrite, str.GetBuffer(), str.GetLength(), dwBytesWrited, NULL)){AfxMessageBox(管道写入失败);} } //读按钮 void CMyTestPipDlg::OnClickedBtnRead() { //检查管道中是否有数据可读DWORD dwBytesAvail 0;if (!PeekNamedPipe(m_hRead, NULL, 0, NULL, dwBytesAvail, NULL)){return;}//如果管道中有数据则读出if (dwBytesAvail 0){CString str;DWORD dwBytesRead 0;if (!ReadFile(m_hRead,str.GetBufferSetLength(dwBytesAvail), dwBytesAvail, dwBytesRead,NULL)){AfxMessageBox(管道读取失败);}str.ReleaseBuffer(dwBytesRead);SetDlgItemText(EDT_READ, str);} }管道读取被阻塞的问题  在父进程读取管道的操作之前先往管道中写入一些数据这样可以确保在读取操作执行时管道中已经有数据可以读取。使用非阻塞读取操作这样可以避免读取操作被阻塞。可以使用 Windows API 函数 PeekNamedPipe() 来查询管道中是否有数据可以读取。如果返回值为 0表示管道中没有数据可以读取如果返回值不为 0则可以调用 ReadFile() 函数来读取管道中的数据。在父进程中创建一个线程让这个线程负责读取管道中的数据。这样可以避免读取操作阻塞主线程从而避免程序无响应的问题。可以使用 Windows API 函数 CreateThread() 来创建线程然后在线程中调用 ReadFile() 函数来读取管道中的数据。同时主线程可以继续执行其他操作不必等待管道中的数据读取完成。 父子进程之间的匿名管道通信 基本步骤 获取标准输入输出的句柄继承句柄创建管道的时候创建子窗口的时候创建进程时需要STARTUPINFO指定句柄 GetStdHandle GetStdHandle函数获取标准输入、标准输出或标准错误设备的句柄。 参数指定要为其返回句柄的标准设备。该参数可以是以下值之一 STD_INPUT_HANDLE——标准输入处理STD_OUTPUT_HANDLE——标准输出处理STD_ERROR_HANDLE——标准错误处理 设置安全属性子进程继承父进程 两个地方的继承属性设置为TRUE: 创建管道的时候创建子窗口的时候 //创建管道 void CMFCTestDlg::OnBnClickedCreate() {SECURITY_ATTRIBUTES sa {};sa.nLength sizeof(sa);sa.bInheritHandle TRUE; if (!CreatePipe(m_hRead, m_hWrite, sa, 0)){AfxMessageBox(管道创建失败);} }STARTUPINFO指定句柄 结构体中下图中三个参数 测试代码如下 父进程源码 void CMFCTestDlg::OnBnClickedCreate() {SECURITY_ATTRIBUTES sa {};sa.nLength sizeof(sa);sa.bInheritHandle TRUE;if (CreatePipe(m_hChildRead, m_hParentWrite, sa, 0)){AfxMessageBox(创建管道成功);}else{AfxMessageBox(创建失败);}if (CreatePipe(m_hParentRead, m_hChildWrite, sa, 0)){AfxMessageBox(创建管道成功);}else{AfxMessageBox(创建失败);}//创建子进程STARTUPINFO si;PROCESS_INFORMATION pi;ZeroMemory(si, sizeof(si));si.cb sizeof(si);si.dwFlags STARTF_USESTDHANDLES; //使用句柄si.hStdInput m_hChildRead;si.hStdOutput m_hChildWrite;si.hStdError m_hChildWrite;ZeroMemory(pi, sizeof(pi));// Start the child process. if (!CreateProcess(NULL, // No module name (use command line). MyChildProcess, // Command line. NULL, // Process handle not inheritable. NULL, // Thread handle not inheritable. TRUE, // Set handle inheritance to FALSE. 0, // No creation flags. NULL, // Use parents environment block. NULL, // Use parents starting directory. si, // Pointer to STARTUPINFO structure.pi) // Pointer to PROCESS_INFORMATION structure.){AfxMessageBox(CreateProcess failed.);}else{AfxMessageBox(CreateProcess sucess.);}// Close process and thread handles. CloseHandle(pi.hProcess);CloseHandle(pi.hThread);}void CMFCTestDlg::OnBnClickedRead() {//判断管道中是否有数据可读DWORD dwBytesAvail 0;if (PeekNamedPipe(m_hParentRead, NULL, 0, NULL, dwBytesAvail, NULL)){if (dwBytesAvail 0){//从管道读取数据char szBuff[MAXBYTE] {};DWORD dwBytesReaded 0;BOOL bRet ReadFile(m_hParentRead, szBuff, dwBytesAvail, dwBytesReaded, NULL);if (!bRet){AfxMessageBox(读取文件失败);}//显示到界面SetDlgItemText(EDT_SHOW, szBuff);}}} void CMFCTestDlg::OnBnClickedWrite() {//获取数据CString strData;this-GetDlgItemText(EDT_DATA, strData);//从管道写入数据DWORD dwBytesReaded 0;BOOL bRet WriteFile(m_hParentWrite, strData.GetBuffer(), strData.GetLength(), dwBytesReaded, NULL);if (!bRet){AfxMessageBox(写入文件失败);}}子进程源码 void CMFCTestDlg::OnBnClickedRead() {//获取父进程句柄 GetstdHandleHANDLE hRead GetStdHandle(STD_INPUT_HANDLE);//判断管道中是否有数据可读DWORD dwBytesAvail 0;if (PeekNamedPipe(hRead, NULL, 0, NULL, dwBytesAvail, NULL)){if (dwBytesAvail 0){//从管道读取数据char szBuff[MAXBYTE] {};DWORD dwBytesReaded 0;BOOL bRet ReadFile(hRead, szBuff, dwBytesAvail, dwBytesReaded, NULL);if (!bRet){AfxMessageBox(读取文件失败);}//显示到界面SetDlgItemText(EDT_SHOW, szBuff);}} }void CMFCTestDlg::OnBnClickedWrite() {//获取父进程句柄 GetstdHandleHANDLE hWrite GetStdHandle(STD_OUTPUT_HANDLE);//获取数据CString strData;this-GetDlgItemText(EDT_DATA, strData);//从管道写入数据DWORD dwBytesReaded 0;BOOL bRet WriteFile(hWrite, strData.GetBuffer(), strData.GetLength(), dwBytesReaded, NULL);if (!bRet){AfxMessageBox(写入文件失败);} }管道创建与使用 1. 创建管道并传给子进程 void CParentDlg::OnBnClickedButton1() {//管道的读写句柄一般作为成员变量HANDLE m_hRead NULL;HANDLE m_hWrite NULL;//创建管道SECURITY_ATTRIBUTES sa {}; //管道安全属性结构体sa.nLength sizeof(sa);sa.bInheritHandle TRUE; //指定该管道句柄可以继承BOOL bRet ::CreatePipe(m_hRead, m_hWrite, sa, 0); //使用默认缓冲区大小if (!bRet){AfxMessageBox(创建管道失败);return;}//创建子进程STARTUPINFO si {};si.cb sizeof(si);si.dwFlags STARTF_USESTDHANDLES; //指明标准输入输出句柄si.hStdInput m_hRead; //给将继承的输入句柄赋值PROCESS_INFORMATION pi; //ZeroMemory(pi, sizeof(pi)); //等同于 PROCESS_INFORMATION pi {};// Start the child process. if (!CreateProcess(NULL, // No module name (use command line). Child.exe, // Command line. NULL, // Process handle not inheritable. NULL, // Thread handle not inheritable. TRUE, // Set handle inheritance to FALSE. 0, // No creation flags. NULL, // Use parents environment block. NULL, // Use parents starting directory. si, // Pointer to STARTUPINFO structure.pi) // Pointer to PROCESS_INFORMATION structure.){AfxMessageBox(CreateProcess failed.);return;}CloseHandle(pi.hProcess); //释放进程句柄CloseHandle(pi.hThread); //释放线程句柄 } 向管道写入数据【WriteFile】 3. 通过写入句柄向管道写入数据 void CParentDlg::OnBnClickedButton2() {CString strBuf;GetDlgItemText(EDT_WRITE, strBuf);BOOL bRet WriteFile(m_hWrite, strBuf.GetBuffer(), strBuf.GetLength(), NULL, NULL);if (!bRet){AfxMessageBox(写入管道失败);} }子进程的读取和写入 void CChildDlg::OnBnClickedButton1() {//1.获取管道读取或泽写入句柄HANDLE hInput ::GetStdHandle(STD_INPUT_HANDLE);DWORD dwBytesAvail 0;//2. 检查管道内是否有数据。BOOL bRet ::PeekNamedPipe(hInput, NULL, 0, NULL, dwBytesAvail, NULL);if (!bRet){AfxMessageBox(无法查看管道剩余数据);return;}//3. 管道中有数据再读if (dwBytesAvail 0){CString strBuf;DWORD dwBytesToRead 0;BOOL bRet ::ReadFile(hInput,strBuf.GetBufferSetLength(MAXBYTE),MAXBYTE,dwBytesToRead,NULL);if (!bRet){AfxMessageBox(读取数据失败);return;}strBuf.ReleaseBuffer(dwBytesToRead);SetDlgItemText(EDT_READ, strBuf);} } 模拟CMD void CMFCTestDlg::OnBnClickedCreate() {SECURITY_ATTRIBUTES sa {};sa.nLength sizeof(sa);sa.bInheritHandle TRUE;if (!CreatePipe(m_hChildRead, m_hParentWrite, sa, 0)){AfxMessageBox(创建失败);}if (!CreatePipe(m_hParentRead, m_hChildWrite, sa, 0)){AfxMessageBox(创建失败);}//创建子进程STARTUPINFO si;PROCESS_INFORMATION pi;ZeroMemory(si, sizeof(si));si.cb sizeof(si);si.dwFlags STARTF_USESTDHANDLES; //使用句柄si.hStdInput m_hChildRead;si.hStdOutput m_hChildWrite;si.hStdError m_hChildWrite;ZeroMemory(pi, sizeof(pi));// Start the child process. if (!CreateProcess(NULL, // No module name (use command line). cmd.exe, // Command line. NULL, // Process handle not inheritable. NULL, // Thread handle not inheritable. TRUE, // Set handle inheritance to FALSE. CREATE_NO_WINDOW, // No creation flags. NULL, // Use parents environment block. NULL, // Use parents starting directory. si, // Pointer to STARTUPINFO structure.pi) // Pointer to PROCESS_INFORMATION structure.){AfxMessageBox(CreateProcess failed.);}// Close process and thread handles. CloseHandle(pi.hProcess);CloseHandle(pi.hThread);}void CMFCTestDlg::OnBnClickedRead() {//判断管道中是否有数据可读DWORD dwBytesAvail 0;if (PeekNamedPipe(m_hParentRead, NULL, 0, NULL, dwBytesAvail, NULL)){if (dwBytesAvail 0){//从管道读取数据char szBuff[MAXBYTE] {};DWORD dwBytesReaded 0;BOOL bRet ReadFile(m_hParentRead, szBuff, sizeof(szBuff)-1, dwBytesReaded, NULL);if (!bRet){AfxMessageBox(读取文件失败);}//显示到界面m_strOutData szBuff;SetDlgItemText(EDT_SHOW, m_strOutData);}}} void CMFCTestDlg::OnBnClickedWrite() {//获取数据CString strData;this-GetDlgItemText(EDT_DATA, strData);strData \r\n;//从管道写入数据DWORD dwBytesReaded 0;BOOL bRet WriteFile(m_hParentWrite, strData.GetBuffer(), strData.GetLength(), dwBytesReaded, NULL);if (!bRet){AfxMessageBox(写入文件失败);}}
http://wiki.neutronadmin.com/news/335592/

相关文章:

  • 怎样创建网站或网页深圳包装设计公司有哪些呢
  • 福州公司建站站长之家最新网站
  • 网站怎么推广运营dedecms购物网站模板下载
  • 网站建设前的需求分析如何查询网络服务商
  • 域名注册服务网站网站建设 开发 模板
  • ps做网站字体用多大的淮安做网站
  • 网站出现建设中开广告公司利润大吗
  • 企业网站建设费入什么科目现代广告创意设计
  • 哪个网站做二手车抵押网页微信注册新号怎么注册
  • 中国建设银行征信中心网站深圳外包企业网站
  • 网站地址查询ip无极电影网评
  • 免费做企业网站网络科技网站有哪些方面
  • 刷赞网站怎么做的网页设计与制作张苏中素材
  • 网站模板中企动力wordpress 视频分集
  • 成都网站开发定制已申请域名怎么做网站
  • 网站开发做什么费用茂名网站建设方案书
  • 做电器的集团网站网站怎么做json数据
  • 游戏网站制作模板太原工程建设招投标信息网站
  • 南通网站建设方案托管视频课程网站建设
  • 网站不用域名上海欣扬集团 网站建设
  • 湛江制作网站学校竹子建站教程
  • 个人网站建设规划深圳高端做网站公司
  • 海口网站建设兼职poi player wordpress
  • 把自己做的网站传到网上网页制作工具的选择与网站整体风格是有关系吗
  • 惠州网站建设排名vps搭建网站需要空间
  • 建网站首页图片哪里找品牌推广网络公司
  • 如何查询网站备案信息查询淘宝客网站开发
  • 芗城区建设局网站做一个网站需要哪些
  • 网站高转化页面网站中文名要注册的吗
  • 邢台做wap网站多少钱品牌建设心得体会