VC++ 環 境 下 利 用 管 道 和 線 程 實 現 進 程 間 通 信

來源:互聯網
上載者:User
電 子 部 第 二 十 八 研 究 所 一 部

張 傑
一. 引 言

----
Windows95 作 為 一 個 優 先 多 任 務 操 作 系 統, 其 重 要 特 征 之 一 是 引 入 了 多 進 程 和 多 線
程 機 制。 其 中 每 個 進 程 都 有 私 有 的 虛 擬 地 址 空 間, 可 以 創 建 多 個 線 程, 每 個 線 程 被 分
配 一 個 時 間 片, 且 當 前 執 行 的 線 程 在 其 時 間 片 耗 盡 時 掛 起, 讓 其 他 線 程 運 行。 由 於 各
時 間 片 很 小, 所 以 這 時 看 起 來 就 象 是 多 個 線 程 在 同 時 工 作。 我 們 這 裡 將 會 在 子 進
程Child 中 產 生 一 個 工 作 線 程, 它 只 在 後 台 處 理 任 務, 而 不 會 影 響 程 序 的 使 用。

---- 有 時 用 戶 運 行 的 進 程 之 間 毫 無 關 系, 但
是 進 程 之 間 信 息 的 交 換 則 能 產 生 協 作 效 果, 這 樣 就 可 以 完 成 某 些 單 個 進 程 所 不 能 完
成 的 任 務。Windows95 可 以 使 用 多 種 通 信 手 段, 包 括 剪 貼 板、DDE、OLE, 而 且 還 增 加 了 一
些 新 的 手 段, 其 中 管 道 是 用 來 在 不 同 程 序 之 間 交 換 信 息 的 另 一 個 新 的 簡 便 的 通 信 機
制。 與 其 它 手 段 不 同, 管 道 沒 有 正 式 的 標 准 或 協 議 來 控 制 信 息 傳 遞, 所 以 與DDE 會 話 這
樣 的 機 制 相 比, 管 道 更 易 於 使 用、 更 加 靈 活。 管 道 實 際 上 是 一 段 共 享 內 存 區, 進 程 把 共
享 消 息 放 在 那 裡。 因 為 管 道 專 用 於 進 程 間 的 通 信, 所 以Win32API 提 供 了 一 組 函 數 以 方
便 信 息 交 換。

---- 本 文 我 們 將 在VC++4.1 環 境 下 介 紹
一 個 父 進 程 和 其 子 進 程 的 通 信 實 例。 在 父 進 程Parent 窗 口 中 按 一 下 鼠 標 左 鍵, 就 會 產
生 一 個Pipe 和 啟 動 子 進 程Child, 並 從Pipe 一 端 發 送 信 息, 同 時Child 啟 動 後 會 創 建 一
個 工 作 線 程, 專 門 用 來 從 管 道 的 另 一 端 讀 入 數 據。 通 過 父 進 程 菜 單 項 的 控 制 來 改 變 圖
形 形 狀 參 數, 並 傳 給Child 使 之 在 自 己 的 窗 口 中 繪 出 響 應 的 圖 形。 下 面 分 別 就 父 進
程Parent 和 子 進 程Child 來 進 行 說 明。

二. 父 進 程Parent

----
在 父 進 程Parent 中, 我 們 將 創 建 管 道 和 啟 動 子 進 程。 首 先 說 明 幾 個 相 關 函 數。 創 建 進 程 函 數:

BOOL CreateProcess(
LPCTSTR lpApplicationName, //應用模式指標
LPTSTR lpCommandLine,//命令列字串
LPSECURITY_ATTRIBUTES lpProcessAttributes,
//進程安全性指標
LPSECURITY_ATTRIBUTES lpThreadAttributes,
//主執行緒安全性指標
BOOL bInheritHandles,//是否繼承控制代碼
DWORD dwCreationFlags, //進程類型與優先順序
LPVOID lpEnvironment,//環境塊指標
LPCTSTR lpCurrentDirectory,//目前的目錄
LPSTARTUPINFO lpStartupInfo,
// STARTUPINFO結構指標
LPPROCESS_INFORMATION
lpProcessInformation //); //新進程資訊
建立管道函數:
BOOL CreatePipe(
PHANDLE hReadPipe,//讀控制代碼變數地址
PHANDLE hWritePipe,//寫控制代碼變數地址
LPSECURITY_ATTRIBUTES lpPipeAttributes,
//安全屬性指標
DWORD nSize ); //管道緩衝區大小
寫管道函數:
BOOL WriteFile(
HANDLE hFile,//寫入檔案控制代碼
LPCVOID lpBuffer,//寫入資料指標
DWORD nNumberOfBytesToWrite,//要寫入位元組數量
LPDWORD lpNumberOfBytesWritten,//已寫入位元組數地址
LPOVERLAPPED lpOverlapped ); //非同步I/O結構指標

----
下 面 從 編 程 角 度 討 論 其 實 現 步 驟:

----1. 利 用AppWizard(EXE) 產 生Parent 應 用
框 架, 然 後 再 文 件Parentview.cpp 頭 部 加 入#include< global.h >, 其 中 文
件global.h 定 義 了 兩 個 進 程 用 於 相 互 通 信 的 結 構 和 常 量 值。 代 碼 如 下:

 //////////////////Global.h共用變數標頭檔
typedef struct Figure
{ int iShape; //圖形控制參數
} FIGURE,*PFIGURE;
#define ID_RECT 32771
#define ID_ELLIPSE 32772
#define ID_TERMINATE 32773

----2. 使 用ClassWizard 工 具: 選 擇 對 應
於CParentView 類 的 消 息WM_LBUTTONDOWN, 選 擇AddFunction 鍵, 增 加 函
數OnLButtonDown()。 在 主 菜 單 資 源 中 加 入Rect、Ellipse、Terminate 菜 單 項,ID 分 別
為IDC_RECT、IDR_ELLIPSE、IDR_TERMINATE, 並 在ClassWizard 中 加 入 相 應 函 數。

在檔案Parentview.h中加入如下代碼:
public:
BOOL SendCommand(); //發送資訊
HANDLE hProcess; //進程控制代碼
HANDLE hpipeWrite; //管道寫控制代碼
FIGURE figure;
檔案Parentview.cpp中部分程式碼如下:
//////////////////////Parentview.cpp視類實現檔案
void CParnetView::OnLButtonDown(UINT nFlags,Cpoint piont)
{ SECURITY_ATTRIBUTES sa; //安全性結構
STARTUPINFO sui; //子進程視窗屬性結構
PROCESS_INFORMATION pi; //子進程資訊
BOOL bTest;
HANDLE hpipeRead; //管道寫控制代碼
//填充安全性結構使控制代碼被繼承
sa.nLength=sizeof(SECURITY_ATTRIBUTES);
sa.lpSecurityDescriptor=NULL;
sa.bInheritHandle=TRUE;
bTest=CreatePipe(&hpipeRead,
&hpipeWrite,&sa,0); //建立管道
if(!bTest){
MessageBox("CreatePipe failed!",NULL,MB_OK);
return;
}
//修改寫控制代碼,使不被繼承
bTest=DuplicateHandle(GetCurrentProcess(),
hpipeWrite,GetCurrentProcess(),
NULL,0,FALSE,DUPLICATE_SAME_ACCESS);
if(!bTest){
MessageBox("Dup Handle failed!",NULL,MB_OK);
CloseHandle(hpipeRead);
CloseHandle(hpipeWrite);
return;
}
//填充進程啟動資訊
memset(&sui,0,sizeof(STARTUPINFO));
sui.cb =sizeof(STARTUPINFO);
sui.dwFlags=STARTF_USESTDHANDLES;
sui.hStdInput=hpipeRead;
sui.hStdOutput=GetStdHandle(STD_OUTPUT_HANDLE);
sui.hStdError=GetStdHandle(STD_ERROR_HANDLE);
//建立子進程Child
bTest=CreateProcess(NULL,"child.exe",NULL,
NULL,TRUE,0,NULL,NULL,&sui,π);
if(!bTest){
MessageBox("CreateProcess failed!",NULL,MB_OK);
CloseHandle(hpipeWrite); //刪除管道
}
else{ hProcess=pi.hProcess;
CloseHandle(pi.hThread);
figure.iShape=ID_RECT;
SendCommand();
}
CloseHandle(hpipeRead);
return;
Cview::OnLButtonDown(nFlags,point);
}
void CParentView::OnRect()
{figure.iShape=ID_RECT;
SendCommand();
}
void CParentView::OnEllipse()
{figure.iShape=ID_ELLIPSE;
SendCommand();
}
BOOL CParentView::SendCommand()
{BOOL bTest;
DWORD dwWritten;
//寫管道
bTest=WriteFile(hpipeWrite,&figure,
sizeof(FIGURE),&dwWritten,NULL);
if(!bTest){
MessageBox("WriteFile failed!",NULL,MB_OK);
if((!bTest)||(figure.iShape==ID_TERMINATE)){
CloseHandle(hProcess);
hProcess=NULL;
CloseHandle(hpipeWrite);
}
} return (bTest);
}
void CParentView::OnTerminate()
{figure.iShape=ID_TERMINATE;
SendCommand();
}
三. 子 進 程Child

----
Child 啟 動 之 後, 立 刻 創 建 一 個 新 的 線 程, 並 在 新 線 程 中 執 行 讀 管 道 操 作, 利 用 讀 得 的 參 數 使 主 窗 口 繪 出 形 狀。 讀 管 道 函 數 為:

BOOL ReadFile(
HANDLE hFile,//讀入檔案控制代碼
LPVOID lpBuffer,//讀入資料緩衝區地址
DWORD nNumberOfBytesToRead,//要讀入位元組數量
LPDWORD lpNumberOfBytesRead,//已讀入位元組數地址
LPOVERLAPPED lpOverlapped ); //非同步I/O結構指標

---- 首 先 從MFC 類 庫 創 建 新 線 程, 使
用ClassWizard 工 具: 選 擇AddClassNew, 輸 入 類 名CThr, 在 基 類 列 表 框 中 選
擇"CWinThread", 按 下Create 按 鈕, 生 成 線 程 類CThr。 然 後 修 改 程 序 代 碼, 下 面 給 出 部
分 源 程 序:

  ///////////////////Thr.h線程類標頭檔
class CThr : public CWinThread
{//operations
public:
LONG PipeThread();
void DoRead(void);
HANDLE hpipeRead;
HANDLE hThread;
DWORD dwThreadID;
int iShape;
BOOL bTerminate;
};
////////////Thr.cpp線程類實現檔案
#include< global.h >
CThr::CThr()
{HWND hwnd=GetActiveWindow();
//檢索管道控制代碼
hpipeRead=GetStdHandle(STD_INPUT_HANDLE);
if(hpipeRead==INVALID_HANDLE_VALUE)
::MessageBox(hwnd,"Invalid Handle!",NULL,MB_OK);
}
BOOL CThr::InitInstance()
{bTerminate=FALSE;
//設定線程優先權
SetThreadPriority(THREAD_PRIORITY_BELOW_NORMAL);
ResumeThread();
PipeThread();
return TRUE;
}
LONG CThr::PipeThread()
{while(!bTerminate){ DoRead(); }
return 0L;
}
void CThr::DoRead(void)
{FIGURE Figure;
DWORD dwRead;
BOOL bTest;
//讀管道
bTest=ReadFile(hpipeRead,&Figure,
sizeof(Figure),&dwRead,NULL);
if(bTest){
if(Figure.iShape==ID_TERMINATE) bTerminate=TRUE;
else{ iShape=Figure.iShape;
HWND hwndMain=GetActiveWindow();
InvalidateRect(hwndMain,NULL,TRUE);
UpdateWindow(hwndMain); //更新視窗
}
}
else{ bTerminate=TRUE; }
return;
}
//////////////Childview.cpp視類實現檔案
#include"global.h"
#include"thr.h"
CThr* m_pThr; //定義新線程對象
……
CChildView::CChildView()
{ m_pThr=new CThr; } //產生新線程對象
CChildView::~CChildView()
{ delete m_pThr; } //刪除線程
BOOL CChildView::PreCreateWindow(CREATESTRUCT& cs)
{ m_pThr- >CreateThread();
return CView::PreCreateWindow(cs);
}
void CChildView::OnDraw(CDC* pDC)
{……
//根據所讀參數繪圖
Cbrush brush(#000000);
pDC- >SelectObject(&brush);
if(m_pThr- >iShape==ID_RECT) pDC- >Rectangle(12,45,200,178);
if(m_pThr- >iShape==ID_ELLIPSE) pDC- >Ellipse(12,45,200,178);
}
四. 結 論

---- 運 行 以 上 例 程, 在 父 進 程Parent 窗 口 中 按 一
下 鼠 標 左 鍵, 就 會 產 生 一 個Pipe 並 啟 動 子 進 程Child, 在Parent 中 選 中 菜 單 項Rect
或Ellipse 時,Child 窗 口 中 就 會 分 別 繪 出 矩 形 和 橢 圓, 選 中Terminate 時, 就 會 中 斷 通
信。 以 上 介 紹 的 是 匿 名 管 道, 若 要 增 加 通 信 的 靈 活 性 還 可 采 用 命 名 管 道NamedPipe。

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.