windows sdk编程系列文章18 ---- 管道.doc_第1页
windows sdk编程系列文章18 ---- 管道.doc_第2页
windows sdk编程系列文章18 ---- 管道.doc_第3页
windows sdk编程系列文章18 ---- 管道.doc_第4页
windows sdk编程系列文章18 ---- 管道.doc_第5页
已阅读5页,还剩6页未读 继续免费阅读

下载本文档

版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领

文档简介

windows sdk编程系列文章 - 管道2008-04-17 22:58这一讲将探索一下管道,看看它是什么、有什么用。为使之更加生动有趣,我将用怎样改变 Edit 控件的背景色和文本颜色来说明此技术。理论:管道,顾名思义就是有两个端的通道。可以使用管道在进程间、同一进程内进行数据交换,就像手提式无线电话机一样。把管道的一端给另一方,他就可以借助管道和你通讯了。有两种管道,即有名管道和匿名管道。匿名管道就是没有名字的管道了,也就是说在使用它们时不需要知道其名字。而有名管道正好相反,在使用前必须知道其名字。也可以根据管道的特性来分类,即是单向的还是双向的。单向管道,数据只能沿一个方向移动,从一端流向另一端,而双向管道数据可以在两端间自由交换。匿名管道通常是单向的而有名管道通常是双向的。有名管道常用于一个服务器联络多个客户端的网络环境。 这一讲将详细讨论一下匿名管道。匿名管道主要目的是作为父进程与子进程、子进程之间通讯的联结通路。在处理控制台问题时,匿名管道是相当有用的。控制台应用程序就是使用控制台作为输入和输出的一种 Win32 应用程序。一个控制台就像一个 DOS 窗口。但控制台应用程序的的确确是32位的应用程序,它可以向其它图形程序一样使用 GUI 函数,只不过它碰巧使用了控制台罢了。控制台应用程序有三个用于输入输出的标准句柄,它们是标准输入、标准输出和标准错误句柄。标准输入用于从控制台读或取信息而标准输出用于往控制台写或打印信息。标准错误用于汇报输出不能重定向的错误。控制台应用程序可以通过调用函数 GetStdHandle 来获得这三个句柄。一个图形应用程序没有控制台,如果在其中调用GetStdHandle 就会返回错误;如果的确要使用控制台,可以调用AllocConsole 来分配一个新的控制台以使用,但当处理完成时,别忘了调用 FreeConsole 来释放控制台。匿名管道用得最多的功能就是 重定向子进程的标准输入和标准输出。父进程可以是一个控制台或者是图形程序,而子进程必须是控制台应用程序。众所周知,控制台应用使用标准输入输出句柄。若要重定向输入输出,就得用指向管道一端的句柄来替换这个标准句柄。控制台应用程序不会知道我们使用了指向管道任一端的句柄,它会把这个句柄作为标准句柄来看待。借用面向对象的术语,这就是多态性的一种。因为子进程不需作任何改动,因此这种方法是非常有用的。关于控制台应用程序应该掌握的另一点就是它从哪获得标准句柄。当一个控制台应用程序被创建时,父进程有两种选择:为子进程创建一个新的控制台或者是让子进程继承自己的控制台。若使用后者,那父进程本身必须是一个控制台应用程序,或者如果是 GUI 应用程序,它必须首先调用 AllocConsole 分配了一个控制台。通过调用 CreatePipe 来创建一个匿名管道,它的原型为:BOOL CreatePipe( PHANDLE hReadPipe, PHANDLE hWritePipe, LPSECURITY_ATTRIBUTES lpPipeAttributes, DWORD nSize ); pReadPipe 双字指针变量,指向管道读端的句柄。 pWritePipe 双字指针变量,指向管道写端的句柄 pPipeAttributes 双字指针变量,指向SECURITY_ATTRIBUTES 结构,其用于决定读写句柄是否可以被子进程继承 nSize 建议管道留给用户使用的缓冲区的大小,这仅仅是个建议值,可以用 NULL 来使用缺省值 如果函数调用成功返回值为非零,否则为零。成功调用之后,就会得到两个句柄,一个指向管道的读出端,另一个指向管道的写入端。现在我将要把重点放到重定向子控制台程序的标准输出到自己进程的所需的步骤上。注意我的这个方法不同于Borland 公司的 API 参考上的例子。Win32 API 参考上假设父进程是控制台应用程序,因此子进程可以继承它的标准句柄。然而大多数情况下我们需要重定向控制台应用程序的输出到 GUI 应用程序。创建匿名管道使用 CreatePipe ,同时别忘了把 SECURITY_ATTRIBUTES 结构成员bInheritable 设置为TRUE,这样才可以继承句柄。现在要准备好创建进程的函数即CreateProcess 的参数,只有它才可以装载子控制台应用程序。STARTUPINFO 是一个重要的结构,它决定了子进程出现时主窗口的外观,它对于我们的目标也是至关重要的。通过这个结构就可以隐藏主窗口并且把管道句柄传递给子进程。以下就是必须要填写的成员: cb STARTUPINFO结构的大小 dwFlags 二进制标志位,它决定本结构的哪些成员有效,也决定主窗口是显示还是隐藏的状态。在我们的程序中使用STARTF_USESHOWWINDOW 和 STARTF_USESTDHANDLES的组合 hStdOutput 和hStdError 你想要子进程使用的标准输出和标准错误句柄,对我们来说,我们将把管道的写端作为子进程的标准输出和错误。因此当子进程往标准输出或标准错误发送信息时,它实际上把这些信息通过管道传给了父进程 wShowWindow 决定主窗口是显示还是隐藏。我们不希望显示子进程的主窗口,因此把该成员置成SW_HIDE 调用CreateProcess 来创建子进程,但调用成功后子进程仍然不处于激活状态。它被装进了内存但并没有立即运行。在父进程中关闭管道的写端也是必须的。这是因为父进程并不使用管道的写句柄,而且如果一个管道有两个写入端也就不会工作,因此我们在从管道往外读数据之前必须关闭管道的写端。但是不能在调用CreateProcess 之前关闭,否则管道就坏了。你应当在CreateProcess 刚刚返回并且在读数据之前关闭管道的写端。现在就可以通过函数ReadFile 在管道的读端读数据了。通过使用ReadFile ,可以使子进程处于运行状态。它将开始执行,并且当它往标准输出( 实际上是管道的写端 )上写数据时,数据就会被送至管道的读端。应当不停调用ReadFile 直至它的返回值为 0 ,也就是说再也没有数据可读了。对从管道读来的数据你可以进行任何处理,在我们的例子中它被显示在 Edit 控件中。记得用完后关闭管道的读句柄。例子:见光盘FirstWindow19 #include Windows.h#include tchar.h#define IDR_MAINMENU 101#define IDM_ASSEMBLE 40001TCHAR ClassName = _T(PipeWinClass);TCHAR AppName = _T(One-way Pipe Example);TCHAR CreatePipeError = _T(Error during pipe creation);TCHAR CreateProcessError = _T(Error during process creation);TCHAR CommandLine = _T(cl /c test.cpp);TCHAR EditClass = _T(EDIT);HINSTANCE g_hInstance;HWND hwndEdit;INT_PTR CALLBACK ProcWinMain( HWND hWnd, UINT Msg, WPARAM wParam, LPARAM lParam ) HANDLE hRead; HANDLE hWrite; STARTUPINFO startupinfo; PROCESS_INFORMATION pinfo; BYTE buffer1024; DWORD bytesRead; SECURITY_ATTRIBUTES sat; switch(Msg) case WM_CREATE: hwndEdit = CreateWindowEx(WS_EX_CLIENTEDGE,EditClass,NULL,WS_CHILD|WS_VISIBLE|ES_MULTILINE|ES_AUTOHSCROLL|ES_AUTOVSCROLL ,0,0,0,0,hWnd,NULL, g_hInstance,NULL); break; case WM_DESTROY: PostQuitMessage(0); break; case WM_CTLCOLOREDIT: SetTextColor(HDC)wParam,RGB(255,255,0); SetBkColor(HDC)wParam,RGB(0,0,0); return (LONG)GetStockObject(BLACK_BRUSH); break; case WM_SIZE: MoveWindow(hwndEdit,0,0,LOWORD(lParam),HIWORD(lParam),TRUE); break; case WM_COMMAND: if(lParam = 0) if(LOWORD(wParam) = IDM_ASSEMBLE) sat.nLength = sizeof(SECURITY_ATTRIBUTES); sat.lpSecurityDescriptor = NULL; sat.bInheritHandle = TRUE; if(CreatePipe(&hRead,&hWrite,&sat,NULL) startupinfo.cb = sizeof(STARTUPINFO); GetStartupInfo(&startupinfo); startupinfo.hStdOutput = hWrite; startupinfo.hStdError = hWrite; startupinfo.dwFlags = STARTF_USESHOWWINDOW | STARTF_USESTDHANDLES; startupinfo.wShowWindow = SW_HIDE; if(CreateProcess(NULL,CommandLine,NULL,NULL,TRUE,NULL,NULL,NULL,&startupinfo,&pinfo) CloseHandle(hWrite); while(1) RtlZeroMemory(buffer,1024); if(ReadFile(hRead,buffer,1023,&bytesRead,NULL) SendMessage(hwndEdit,EM_SETSEL,-1,0); SendMessage(hwndEdit,EM_REPLACESEL,FALSE,(LPARAM)buffer); else break; CloseHandle(hRead); else MessageBox(hWnd,CreateProcessError,AppName,MB_ICONERROR|MB_OK); else MessageBox(hWnd,CreatePipeError,AppName,MB_OK|MB_ICONERROR); break; default: return DefWindowProc(hWnd,Msg,wParam,lParam); return 0;int WINAPI WinMain( HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow) WNDCLASSEX wc; MSG msg; HWND hWnd; g_hInstance = hInstance; wc.cbSize = sizeof(WNDCLASSEX); wc.style = CS_HREDRAW | CS_VREDRAW; wc.lpfnWndProc = ProcWinMain; wc.cbClsExtra = NULL; wc.cbWndExtra = NULL; wc.hInstance = hInstance; wc.hbrBackground = (HBRUSH)(COLOR_APPWORKSPACE); wc.lpszMenuName = MAKEINTRESOURCE(IDR_MAINMENU); wc.lpszClassName = ClassName; wc.hIcon = wc.hIconSm = LoadIcon(NULL,IDI_APPLICATION); wc.hCursor = LoadCursor(NULL,IDC_ARROW); RegisterClassEx(&wc); hWnd = CreateWindowEx(WS_EX_CLIENTEDGE,ClassName,AppName,WS_OVERLAPPEDWINDOW, CW_USEDEFAULT,CW_USEDEFAULT,400,200,NULL,NULL,hInstance,NULL); ShowWindow(hWnd,SW_SHOWNORMAL); UpdateWindow(hWnd); while(GetMessage(&msg,NULL,0,0) TranslateMessage(&msg); DispatchMessage(&msg); return msg.wParam;分析:这个例子调用 cl.exe 来编译一个名为 test.cpp 的程序,并且重定向 cl.exe 的输出到客户区的 Edit 控件中。当程序被加载时,象往常一样要注册窗口类和创建主窗口。在主窗口被创建的过程中要做的第一件事就是创建用于显示程序cl.exe 输出的 Edit 控件。现在有趣的事来了,我们将改变此 Edit 控件的文本颜色和背景色。当 Edit 控件将要重画客户区时,它会给父窗口发送 WM_CTLCOLOREDIT 消息。参数 wParam 包含了用于画控件自己的客户区设备描述符的句柄 (HDC) 。我们可以利用这种机制来修改 HDC 的特性。 case WM_CTLCOLOREDIT: SetTextColor(HDC)wParam,RGB(255,255,0); SetBkColor(HDC)wParam,RGB(0,0,0); return (LONG)GetStockObject(BLACK_BRUSH); break; SetTextColor 把文本颜色变为黄色,背景颜色变为黑色。最后我们返回一个通过调用GetStockObject 而得到黑色刷子的句柄。处理WM_CTLCOLOREDIT 必须返回一个刷子的句柄,因为 Windows 将要使用这个刷子来重画 Edit 控件的背景。在这个例子中,我希望背景是黑色,所以返回了一个黑色刷子的句柄。 现在当用户选择 Compile 子菜单时,就会创建一个匿名管道。 if(LOWORD(wParam) = IDM_ASSEMBLE) sat.nLength = sizeof(SECURITY_ATTRIBUTES); sat.lpSecurityDescriptor = NULL; sat.bInheritHandle = TRUE; 在调用CreatePipe 之前,必须要填写SECURITY_ATTRIBUTES 结构。如果我们不关心安全性的话,可以在lpSecurityDescriptor 成员中填入 NULL 。bInheritHandle 则必须为 TRUE ,这样管道的句柄才可以被子进程继承。 if(CreatePipe(&hRead,&hWrite,&sat,NULL) 在此之后,我们调用CreatePipe 来创建管道,如果成功,那么变量hRead 和 hWrite 将分别被填入相应的管道的读出端和写入端的句柄。 startupinfo.cb = sizeof(STARTUPINFO); GetStartupInfo(&startupinfo); startupinfo.hStdOutput = hWrite; startupinfo.hStdError = hWrite; startupinfo.dwFlags = STARTF_USESHOWWINDOW | STARTF_USESTDHANDLES; startupinfo.wShowWindow = SW_HIDE; 下一步就是填写STARTUPINFO 结构了。调用 GetStartupinfo 用父进程的缺省值来填写STARTUPINFO 结构。如果要使程序同时工作在 Windows9x 和 Windows NT 下,就必须调用GetStartupInfo 来填写STARTUPINFO 结构。调用返回后,就可以修改重要的成员了。因为我们要子进程输出到父进程而不是缺省的标准输出和标准错误,所以我们把hStdOutput 和 hStdError 都赋成管道写端的句柄。为了隐藏子进程的主窗口,必须把成员变量wShowWidow 赋值为SW_HIDE 。最后通过把成员 dwFlags 赋值为STARTF_USESHOWWINDOW 和 STARTF_USESTDHANDLES 来指明成员hStdOutput, hStdError 和 wShowWindow 是有效的。 if(CreateProcess(NULL,CommandLine,NULL,NULL,TRUE,NULL,NULL,NULL,&startupinfo,&pinfo) CloseHandle(hWrite); 现在调用CreateProcess 来创建子进程。注意为使管道工作,参数bInheritHan

温馨提示

  • 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
  • 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
  • 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
  • 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
  • 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
  • 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
  • 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。

评论

0/150

提交评论