( Index )
Month

Brief Information about the April 2005 CSIG Meeting

FC1 - A File Compare program using Anonymous Pipes --- Windows API

by Bruce Arnold

3rd Tuesday of the month. 7:30PM - C/C++ Group, SPRS

Anonymous Pipe Diagram

Fc1 Screen Shot

Welcome to the C++ Users Group. This group is a "Special Interest Group" of the ACGNJ devoted to discussing programming languages in general and C, C++, and C++ for Windows programming in particular. Each month a small but hopefully useful program (complete with source code) is presented for discussion.

Object: To create a shell program to encapsulate the functionality of the standard FC.EXE command line program that is included in all Microsoft operating systems. This program is Windows based and allows the user to drag and drop two file names. It then compares the files using the FC.EXE utility and captures the output back to itself. It then displays the output in a List Box and allows it to be copied to the clipboard.

The program uses the "Anonymous Pipe Operations" of the CreatePipe() function. The function returns two handles: a read handle to the pipe and a write handle to the pipe. The read handle has read-only access to the pipe, and the write handle has write-only access to the pipe. To communicate using the pipe, the pipe server must pass one of the handles to another process. Usually, this is done through inheritance; that is, the process allows the handle to be inherited by a child process.

The program also presents a newly created class called CResize() which allows resizing a dialog box created with MFC.


At the meeting on Tuesday night we will be discussing the utility and the source code.


SAMPLE CODE =========== ///////////////////////////////////////////////////////////////////////////// // DoClipCopy Send the data to the clipboard // *** ADDED__CODE *** BOOL CFC1Dlg::DoClipCopy(CString &s) { HGLOBAL hMem; // Declare a special memory handle. hMem = ::GlobalAlloc(GMEM_MOVEABLE, s.GetLength() + 1); if(hMem==NULL) return false; char *p = (char *)::GlobalLock(hMem); if (p) strcpy(p, s.GetBuffer(100)); ::GlobalUnlock(hMem); if(OpenClipboard()) { EmptyClipboard(); SetClipboardData(CF_TEXT, hMem); CloseClipboard(); // GlobalFree is not req'd because return TRUE; // the ClipBoard now owns this memory. } else { ::GlobalFree(hMem); return FALSE; } } /////////////////////////////////////////////////////////////////////// // ReadAndHandleOutput // Monitors handle for input. Exits when child exits or pipe breaks. /////////////////////////////////////////////////////////////////////// void CFC1Dlg::ReadAndHandleOutput(HANDLE hPipeRead) { #define MAXCOUNT 256 CHAR lpBuffer[MAXCOUNT]; CHAR lineBuff[MAXCOUNT+1], ch; int idx=0; MSG msg; DWORD nBytesRead; CFC1App * pApp = (CFC1App *)AfxGetApp(); CWaitCursor wait; // Change the cursor to an hourglass while(TRUE) { // m_result.SetTopIndex(m_result.GetCount()-1); // Scroll to bottom. // if (::PeekMessage( &msg, NULL, 0, 0, PM_NOREMOVE) && !pApp-→PumpMessage()) { ::PostQuitMessage( 0 ); break; } wait.Restore(); // Restore the hourglass which was just stolen. if (!ReadFile(hPipeRead,lpBuffer,sizeof(lpBuffer), &nBytesRead,NULL) || !nBytesRead) { if (GetLastError() == ERROR_BROKEN_PIPE) break; // pipe done - normal exit path. else DisplayError("1-ReadFile");// Something bad happened. } for(unsigned int i=0; i<nBytesRead; i++) // Deal with line by line issue. { ch = lpBuffer[i]; if (ch != '\r' && ch != '\n') { lineBuff[idx++] = ch; if (MAXCOUNT==idx) --idx; // prevent overflow. } if (ch=='\n') { lineBuff[idx] = 0; for(char *p = lineBuff+strlen(lineBuff)-1; p != lineBuff; --p) { if (*p == ' ') *p = 0; // TrimRight spaces. else break; } m_result.AddString(lineBuff); idx = 0; } } } if (idx) { lineBuff[idx] = 0; m_result.AddString(lineBuff); } }
"Random Access" questions start at 7:30 Tuesday night. See you there.

SOURCE CODE

Source Code Files

For help, email me at "b a r n o l d @ i e e e . o r g".
Back to C++ Main Page