进程
# 进程的概念
进程是资源申请,高度和独立运行的单位,因此,它使用系统中的运行资源,而程序不能申请系统资源,不能被系统调度也不能作为独立运行的单位,因此它不占系统运行资源.
进程组成:
<1> 操作系统用来管理进行的内核对象
内核对象也是系统用来存放关于进程的统计信息的地方.内核对象是操作系统内部分配的一个内存块,该内存块是一种数据结构,其成员负责维护该对象的各种信息.
<2> 地址空间
它包含所有可执行模块或 DLL 模块的代码和数据.另外,它也包含动态内存分配的空间,例如线程的栈和堆分配空间
进程从来不执行任何东西,它只是纯种的容器,若要使进程完成某项操作,它必须拥有一个在它的环境中运行的纯种,此线程负责执行包含在进程的地址空间的中的代码.也就是,真正完成代码执行的是线程,而进程只是纯种的容器, 或者说是线程的执行环境。
# 创建进程 CreateProcess 函数
CreateProcessW(
_In_opt_ LPCWSTR lpApplicationName,// 该字符串可以指定要执行的模块的完整路径 和文件名
_Inout_opt_ LPWSTR lpCommandLine, //命令行
_In_opt_ LPSECURITY_ATTRIBUTES lpProcessAttributes, //该 结构确定子进程是否可以继承返回到新进程对象的句柄。如果 lpProcessAttributes为NULL,则不能继承该句柄
_In_opt_ LPSECURITY_ATTRIBUTES lpThreadAttributes, //该 结构确定子进程是否可以继承返回到新线程对象的句柄。如果 lpThreadAttributes为NULL,则不能继承该句柄
_In_ BOOL bInheritHandles, //如果此参数为TRUE,则新进程将继承调用进程中的每个可继承句柄。如果参数为FALSE,则不会继承句柄。请注意,继承的句柄与原始句柄具有相同的值和访问权限
_In_ DWORD dwCreationFlags,// 控制优先级类别和流程创建的标志 CREATE_NEW_CONSOLE
_In_opt_ LPVOID lpEnvironment,// 指向新进程的环境块的指针。如果此参数为NULL,则新进程将使用调用进程的环境
_In_opt_ LPCWSTR lpCurrentDirectory,// 进程当前目录的完整路径
_In_ LPSTARTUPINFOW lpStartupInfo, //设置扩展属性
_Out_ LPPROCESS_INFORMATION lpProcessInformation // 该结构接收有关新进程的标识信息
);
//创建一个用谷歌浏览器打开百度
#include <windows.h>
#include <stdio.h>
#include <tchar.h>
void RunExe()
{
STARTUPINFO strStartupInfo;
memset(&strStartupInfo, 0, sizeof(strStartupInfo));
strStartupInfo.cb = sizeof(strStartupInfo);
PROCESS_INFORMATION szProcessInformation;
memset(&szProcessInformation, 0, sizeof(szProcessInformation));
TCHAR szCommandLine[] =_T("\"D:\\Program Files (x86)\\ChromeCore\\ChromeCore.exe\" http://www.baidu.com/");
int iRet = CreateProcess( NULL, szCommandLine, NULL, NULL, false, CREATE_NEW_CONSOLE, NULL, NULL, &strStartupInfo, &szProcessInformation );
if (iRet)
{
//创建成功
printf_s("Create Success iRet = %d\n", iRet);
WaitForSingleObject(szProcessInformation.hProcess, 3000);
//close进程计数减一,进程结束后,进程计数再减一
CloseHandle(szProcessInformation.hProcess);
CloseHandle(szProcessInformation.hThread);
szProcessInformation.dwProcessId = 0;
szProcessInformation.dwThreadId = 0;
szProcessInformation.hThread = NULL;
szProcessInformation.hProcess = NULL;
}
else
{
printf_s("Create Success iRet = %d\n", iRet);
printf_s("errorcode = %d\n", GetLastError());
}
}
int main()
{
printf("This is Bingo\n");
RunExe();
system("pause");
return 0;
}
# 进程间的通信方式
# 剪切板
void CClipboardDlg::OnBnClickedSendBtn()
{
// 1 打开剪切板
if (OpenClipboard())
{
//2 清空剪切板
EmptyClipboard();
char* szSendBuf;
//3 获取编辑框的内容
CStringW strSendW;
GetDlgItemText(IDC_EDIT_SEND, strSendW);
CStringA strSend = (CStringA)strSendW;
//4 分配一个内存对象,内存对象的句柄就是hClip
HANDLE hClip = GlobalAlloc(GMEM_MOVEABLE, strSend.GetLength() + 1);
//5 将剪切板句柄加锁
szSendBuf = (char*)GlobalLock(hClip);
strcpy(szSendBuf, strSend);
TRACE("szSendBuf = %s", szSendBuf);
GlobalUnlock(hClip);
//6 将数据放入剪切板
SetClipboardData(CF_TEXT, hClip);
//7 关闭剪切板
CloseClipboard();
}
}
void CClipboardDlg::OnBnClickedRecvBtn()
{
if (OpenClipboard())
{
//确认剪切板是否可用
if (IsClipboardFormatAvailable(CF_TEXT))
{
HANDLE hClip;
char* pBuf;
//向剪切板要数据
hClip = GetClipboardData(CF_TEXT);
pBuf = (char*)GlobalLock(hClip);
USES_CONVERSION;
LPCWSTR strBuf = A2W(pBuf);
GlobalUnlock(hClip);
SetDlgItemText(IDC_EDIT_RECV, strBuf);
}
CloseClipboard();
}
}
# WM_COPYDATA
WM_COPYDATA wParam传递数据的窗口的句柄。
指向 COPYDATASTRUCT 结构的指针,该结构包含要传递的数据。 如果接收方应用程序处理此消息,则应返回 TRUE;否则,应返回 FALSE。
//发送端
void CWMCOPYDATASENDDlg::OnBnClickedSend()
{
// 必须要知道标题 句柄
CString strWindowTitle = _T("MFCRecv");
CString strDataToSend = _T("Hello ,this is Bingo WM_COPYDATA");
// 利用标题句柄
HWND hRecvWnd = ::FindWindow(NULL, strWindowTitle.GetBuffer(0));
if (hRecvWnd != NULL && ::IsWindow(hRecvWnd))
{
//数据的封装
COPYDATASTRUCT cpd;
cpd.dwData = 0;
cpd.cbData = strDataToSend.GetLength() * sizeof(TCHAR);
cpd.lpData = (PVOID)strDataToSend.GetBuffer(0); ::SendMessage(hRecvWnd, WM_COPYDATA, (WPARAM)(AfxGetApp()- >m_pMainWnd),(LPARAM)&cpd);
}
strDataToSend.ReleaseBuffer();
}
接收端,界面上右击,点击类向导,消息-WM_COPYDATA,双击,转到其消息响应的函数中
BOOL CWMCOPYDATADlg::OnCopyData(CWnd* pWnd, COPYDATASTRUCT* pCopyDataStruct)
{
//消息响应函数
//解析数据
LPCTSTR szText = (LPCTSTR)(pCopyDataStruct->lpData);
DWORD dwLength = (DWORD)pCopyDataStruct->cbData;
TCHAR szRecvText[1024] = { 0 };
memcpy(szRecvText, szText, dwLength);
MessageBox(szRecvText, _T("Bingo"), MB_OK);
return CDialogEx::OnCopyData(pWnd, pCopyDataStruct);
}
# 油槽
使用邮槽通信的进程分为服务端和客户端。邮槽由服务端创建,在创建时需要指定邮槽名,创建后服务端得到邮槽的句柄。在邮槽创建后,客户端可以通过邮槽名打开邮槽, 在获得句柄后可以向邮槽写入消息。
邮槽通信是单向的,只有服务端才能从邮槽中读取消息,客户端只能写入消息。消息是先入先出的。客户端先写入的消息在服务端先被读取。
通过邮槽通信的数据可以是任意格式的,但是一条消息不能大于 424 字节。
邮槽除了在本机内进行进程间通信外,在主机间也可以通信。但是在主机间进行邮槽通信,数据通过网络传播时使用的是数据报协议(UDP),所以是一种不可靠的通信。通过网络进行邮槽通信时,客户端必须知道服务端的主机名或域名。
// 服务端
void CChildView::OnSlot() {
// "\\\\.\\mailslot\\Mymailslot \\.\mailslot\Mymailslot
// 1 创建一个邮槽
LPCTSTR szSlotName = TEXT("\\\\.\\mailslot\\Mymailslot");
HANDLE hSlot = CreateMailslot(szSlotName,
0, // no maximum message size
MAILSLOT_WAIT_FOREVER, // no time-out for operations NULL
); // default security
if (hSlot == INVALID_HANDLE_VALUE)
{
TRACE("CreateMailslot failed with %d\n", GetLastError());
return ;
}
// 2 读取数据
char szBuf[100] = { 0 };
DWORD dwRead;
TRACE("Begin ReadFile");
if (!ReadFile(hSlot, szBuf, 100, &dwRead, NULL))
{
MessageBox(_T("读取数据失败"));
CloseHandle(hSlot);
return;
}
TRACE("End ReadFile");
MessageBox((CStringW)szBuf);
CloseHandle(hSlot);
}
// 客户端
void CChildView::OnSend()
{
// 创建一个文件句柄
LPCTSTR szSlotName = TEXT("\\\\.\\mailslot\\Mymailslot");
HANDLE hMailSlot = CreateFile(szSlotName, FILE_GENERIC_WRITE, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL,NULL
);
if (hMailSlot == INVALID_HANDLE_VALUE)
{
TRACE("CreateFile failed with %d\n", GetLastError());
return;
}
//写入数据
char szBuf[] = "Bingo is handsome";
DWORD dwWrite;
if (!WriteFile(hMailSlot, szBuf, strlen(szBuf) + 1, &dwWrite, NULL))
{
MessageBox(_T("写入数据失败")); C
loseHandle(hMailSlot);
return;
}
CloseHandle(hMailSlot);
}
# 匿名管道
匿名管道是一个没有命名的单向管道,本质上就是一个共享的内存区域。通常用来在父进程和子进程之间通信。只能实现本地两个进程之间的通信。不能实现网络通信。
CreatePipe(
_Out_ PHANDLE hReadPipe, //该变量接收管道的读取句柄
_Out_ PHANDLE hWritePipe,// 该变量接收管道的写句柄
_In_opt_ LPSECURITY_ATTRIBUTES lpPipeAttributes,//NULL
_In_ DWORD nSize //管道缓冲区的大小 0 :默认缓冲区大小
);
// 父进程
HANDLE hReadPipe;
HANDLE hWritePipe;
// 创建子进程
void CChildView::OnPipeCreate()
{
// TODO: 在此添加命令处理程序代码
//创建匿名管道
SECURITY_ATTRIBUTES sa;
sa.bInheritHandle = TRUE;
sa.lpSecurityDescriptor = NULL;
sa.nLength = sizeof(SECURITY_ATTRIBUTES);
if (!CreatePipe(&hReadPipe, &hWritePipe, &sa, 0))
{
MessageBox(_T("匿名管道创建失败"));
return;
}
//创建子进程
STARTUPINFO strStartupInfo; //用来指定新进程窗口如何显示
memset(&strStartupInfo, 0, sizeof(strStartupInfo));
strStartupInfo.cb = sizeof(strStartupInfo);
strStartupInfo.dwFlags = STARTF_USESTDHANDLES;
strStartupInfo.hStdInput = hReadPipe;
strStartupInfo.hStdOutput = hWritePipe;
strStartupInfo.hStdError = GetStdHandle(STD_ERROR_HANDLE);
PROCESS_INFORMATION szProcessInformation;
memset(&szProcessInformation, 0, sizeof(szProcessInformation));
int iRet = CreateProcess( _T("MailSlotClient.exe"), NULL, NULL, NULL, TRUE, 0,NULL, NULL, &strStartupInfo, &szProcessInformation );
if (iRet)
{
//创建成功
CloseHandle(szProcessInformation.hProcess);
CloseHandle(szProcessInformation.hThread);
szProcessInformation.dwProcessId = 0;
szProcessInformation.dwThreadId = 0;
szProcessInformation.hThread = NULL;
szProcessInformation.hProcess = NULL;
}
else
{
CloseHandle(hReadPipe);
CloseHandle(hWritePipe);
hReadPipe = NULL;
hWritePipe = NULL;
MessageBox(_T("创建子进程失败"));
return;
}
}
void CChildView::OnPipeRead()
{
char szBuf[100] = { 0 };
DWORD dwRead;
TRACE("Begin ReadFile");
if (!ReadFile(hReadPipe, szBuf, 100, &dwRead, NULL))
{
MessageBox(_T("读取数据失败"));
return;
}
TRACE("End PipeReadFile");
MessageBox((CStringW)szBuf);
}
void CChildView::OnPipeWrite()
{
//写入数据
char szBuf[] = "Bingo hen shuai";
DWORD dwWrite;
if (!WriteFile(hWritePipe, szBuf, strlen(szBuf) + 1, &dwWrite, NULL))
{
MessageBox(_T("写入数据失败"));
return;
}
}
// 子进程
hReadCliPipe =GetStdHandle(STD_INPUT_HANDLE);
hWriteCliPipe = GetStdHandle(STD_OUTPUT_HANDLE);
void CChildView::OnCliPipeRead()
{
char szBuf[100] = { 0 };
DWORD dwRead;
TRACE("Begin ReadFile");
//查找所有引用shift + alt + F
if (!ReadFile(hReadCliPipe, szBuf, 100, &dwRead, NULL))
{
MessageBox(_T("读取数据失败"));
return;
}
TRACE("End PipeReadFile");
MessageBox((CStringW)szBuf);
}
void CChildView::OnCliPipeWrite()
{
char szBuf[] = "Bingo Bingo";
DWORD dwWrite;
if (!WriteFile(hWriteCliPipe, szBuf, strlen(szBuf) + 1, &dwWrite, NULL))
{
MessageBox(_T("写入数据失败"));
CloseHandle(hWriteCliPipe);
return;
}
CloseHandle(hWriteCliPipe);
}
# 命名管道
与Socket相似,支持网络之间不同进程的通信
CreateNamedPipe
HANDLE CreateNamedPipeA(
LPCSTR lpName, // \.\pipe<i>pipename
DWORD dwOpenMode,
DWORD dwPipeMode,
DWORD nMaxInstances,
DWORD nOutBufferSize,
DWORD nInBufferSize,
DWORD nDefaultTimeOut,
LPSECURITY_ATTRIBUTES lpSecurityAttributes
);
等待连接
BOOL ConnectNamedPipe(
HANDLE hNamedPipe,
LPOVERLAPPED lpOverlapped
);
WaitNamedPipe(szNamedPipeName, NMPWAIT_WAIT_FOREVER)
HANDLE hNamedPipe;
// 服务端
void CChildView::OnCreateNamedPipe()
{
//1 创建一个命名管道
LPCTSTR szPipeName = TEXT("\\\\.\\pipe\\mypipe");
hNamedPipe = CreateNamedPipe(szPipeName,PIPE_ACCESS_DUPLEX | FILE_FLAG_OVERLAPPED, PIPE_TYPE_BYTE, 1, 1024, 1024, 0, NULL);
if (hNamedPipe == INVALID_HANDLE_VALUE)
{
TRACE("CreateNamedhPipe failed with %d\n", GetLastError());
MessageBox(_T("创建命名管道失败"));
return;
}
// 2 等待客户端的连接
HANDLE hEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
if (NULL == hEvent)
{
MessageBox(_T("创建事件失败"));
CloseHandle(hNamedPipe); hNamedPipe = NULL;
return;
}
OVERLAPPED ovlap;
ZeroMemory(&ovlap, sizeof(OVERLAPPED));
ovlap.hEvent = hEvent;
//等待连接
if (!ConnectNamedPipe(hNamedPipe, &ovlap))
{
if (ERROR_IO_PENDING != GetLastError())
{
MessageBox(_T("等待客户端连接失败"));
CloseHandle(hNamedPipe);
CloseHandle(hEvent);
hNamedPipe = NULL;
hEvent = NULL;
return;
}
}
if (WaitForSingleObject(hEvent,INFINITE) == WAIT_FAILED)
{
MessageBox(_T("等待对象失败"));
CloseHandle(hNamedPipe);
CloseHandle(hEvent);
hNamedPipe = NULL;
hEvent = NULL; return;
}
}
void CChildView::OnSreadNamedPipe()
{
char szBuf[100] = { 0 };
DWORD dwRead;
if (!ReadFile(hNamedPipe, szBuf, 100, &dwRead, NULL))
{
MessageBox(_T("读取数据失败"));
return;
}
MessageBox((CStringW)szBuf);
}
void CChildView::OnSwriteNamedpipe()
{
//写入数据
char szBuf[] = "OnNamedPipe Server";
DWORD dwWrite;
if (!WriteFile(hNamedPipe, szBuf, strlen(szBuf) + 1, &dwWrite, NULL))
{
MessageBox(_T("写入数据失败"));
return;
}
}
// 客户端 连接命名管道
void CChildView::OnConnectNamedPipe()
{
LPCTSTR szNamedPipeName = TEXT("\\\\.\\pipe\\mypipe");
if (0 == WaitNamedPipe(szNamedPipeName, NMPWAIT_WAIT_FOREVER))
{
MessageBox(_T("当前没有可以利用的管道"));
return;
}
hNamedPipe = CreateFile(szNamedPipeName, GENERIC_READ | GENERIC_WRITE, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
if (hNamedPipe == INVALID_HANDLE_VALUE)
{
TRACE("CreateFile failed with %d\n",
GetLastError());
MessageBox(_T("打开命名管道失败!"));
hNamedPipe = NULL;
return;
}
}
void CChildView::OnReadNamedPipe()
{
char szBuf[100] = { 0 };
DWORD dwRead;
if (!ReadFile(hNamedPipe, szBuf, 100, &dwRead, NULL))
{
MessageBox(_T("读取数据失败"));
return;
}
MessageBox((CStringW)szBuf);
}
void CChildView::OnWriteNamedPipe()
{
char szBuf[] = "NAMEDPIPE CLIENT";
DWORD dwWrite;
if (!WriteFile(hNamedPipe, szBuf, strlen(szBuf) + 1, &dwWrite, NULL))
{
MessageBox(_T("写入数据失败"));
CloseHandle(hWriteCliPipe);
return;
}
CloseHandle(hWriteCliPipe);
}