Deze C++ code doet exact hetzelfde als de vorige versie van het programma (zie mijn vorige blog). Echter, ik heb het programma proberen te herschrijven volgens de richtlijnen uit het boek Clean Code: A Handbook of Agile Software Craftsmanship van Robert C. Martin. Wat zeker nog ontbreekt is het vrijgeven van het geheugen en het vrijgeven van de handles (zowel de Pipes als de Process-handle) (dit ontbreekt ook in the originele versie). Zelfs buiten dat, ben ik nog niet volledig overtuigd dat het programma klaar is. Misschien volgt een nieuwe versie als ik het boek uitgelezen heb?...
#include "stdafx.h"
#include <windows.h>
// SecurityAttribute-stuff (needed for the Pipes)
class SecurityAttributes
{
private:
SECURITY_ATTRIBUTES security_attributes;
public:
SecurityAttributes();
LPSECURITY_ATTRIBUTES GetPointer();
};
// Pipe-stuff
typedef struct
{
HANDLE Read;
HANDLE Write;
} PipeHandlePair;
typedef struct
{
PipeHandlePair input;
PipeHandlePair output;
PipeHandlePair error;
} PipeHandles;
void CreatePipes(PipeHandles &ThePipeHandles);
void CreatePipe(PipeHandlePair &PipePair, SecurityAttributes &TheSecurityAttributes);
void SendTextMessageToPipe(HANDLE PipeHandle, LPCSTR Message);
DWORD GetAmountOfDataAvailableOnPipe(HANDLE PipeHandle);
DWORD ReadDataFromPipe(HANDLE PipeHandle, LPBYTE Buffer, DWORD BytesToRead);
LPSTR ReadStringDataFromPipe(HANDLE PipeHandle, DWORD StringLength);
LPSTR ReadAvailableDataFromPipeAsString(HANDLE PipeHandle);
void ReadAndDisplayOutputFromPipes(PipeHandles &ThePipeHandles);
// ProcessStartupInfo-stuff (needed for the Processes)
class ProcessStartupInfo
{
private:
STARTUPINFO startup_info;
public:
ProcessStartupInfo(const PipeHandles &ThePipeHandles);
LPSTARTUPINFO GetPointer();
};
// Process-stuff
void WaitForProcessToEnd(HANDLE ProcessHandle);
void WaitForProcessToEnd(PROCESS_INFORMATION &process_info);
bool CreateProcess(PROCESS_INFORMATION &process_info, LPCSTR CommandLine, PipeHandles &ThePipeHandles);
bool CreateProcessAndWaitForItToEnd(LPCSTR CommandLine, PipeHandles &ThePipeHandles, LPCSTR OptionalInputToSend = NULL);
// Other stuff
void SimpleMessageBox(LPCSTR Title, LPCSTR Content);
void DisplayNormalOrErrorOutput(LPSTR OutputString, LPSTR ErrorString);
int main()
{
PipeHandles OurPipeHandles;
CHAR InputToSend[] = "";
CreatePipes(OurPipeHandles);
if(CreateProcessAndWaitForItToEnd("cmd /C "echo Test"", OurPipeHandles, InputToSend))
ReadAndDisplayOutputFromPipes(OurPipeHandles);
return 0;
}
void CreatePipes(PipeHandles &ThePipeHandles)
{
SecurityAttributes TheSecurityAttributes;
CreatePipe(ThePipeHandles.output, TheSecurityAttributes);
CreatePipe(ThePipeHandles.input, TheSecurityAttributes);
CreatePipe(ThePipeHandles.error, TheSecurityAttributes);
}
void CreatePipe(PipeHandlePair &PipePair, SecurityAttributes &TheSecurityAttributes)
{
CreatePipe(&PipePair.Read, &PipePair.Write, TheSecurityAttributes.GetPointer(), 0);
}
bool CreateProcess(PROCESS_INFORMATION &process_info, LPCSTR CommandLine, PipeHandles &ThePipeHandles)
{
ProcessStartupInfo StartupInfo(ThePipeHandles);
return CreateProcess(NULL, (LPSTR) CommandLine, NULL, NULL, TRUE, 0, NULL, NULL, StartupInfo.GetPointer(), &process_info) != FALSE;
}
bool CreateProcessAndWaitForItToEnd(LPCSTR CommandLine, PipeHandles &ThePipeHandles, LPCSTR OptionalInputToSend)
{
PROCESS_INFORMATION process_info;
if(!CreateProcess(process_info, CommandLine, ThePipeHandles))
return false;
SendTextMessageToPipe(ThePipeHandles.input.Write, OptionalInputToSend);
WaitForProcessToEnd(process_info.hProcess);
return true;
}
void SendTextMessageToPipe(HANDLE PipeHandle, LPCSTR Message)
{
if(Message && *Message) // Is valid?
{
DWORD bytes_written = 0;
WriteFile(PipeHandle, Message, strlen(Message), &bytes_written, NULL);
}
}
void WaitForProcessToEnd(HANDLE ProcessHandle)
{
WaitForSingleObject(ProcessHandle, INFINITE);
}
void WaitForProcessToEnd(PROCESS_INFORMATION &process_info)
{
WaitForSingleObject(process_info.hProcess, INFINITE);
}
DWORD ReadDataFromPipe(HANDLE PipeHandle, LPBYTE Buffer, DWORD BytesToRead)
{
DWORD BytesRead = 0;
if(BytesToRead)
ReadFile(PipeHandle, Buffer, BytesToRead, &BytesRead, NULL);
return BytesRead;
}
void ReadAndDisplayOutputFromPipes(PipeHandles &ThePipeHandles)
{
CHAR *OutputString = ReadAvailableDataFromPipeAsString(ThePipeHandles.output.Read);
CHAR *ErrorString = ReadAvailableDataFromPipeAsString(ThePipeHandles.error.Read);
DisplayNormalOrErrorOutput(OutputString, ErrorString);
}
LPSTR ReadAvailableDataFromPipeAsString(HANDLE PipeHandle)
{
DWORD BytesAvailable = GetAmountOfDataAvailableOnPipe(PipeHandle);
LPSTR StringData = ReadStringDataFromPipe(PipeHandle, BytesAvailable);
return StringData;
}
DWORD GetAmountOfDataAvailableOnPipe(HANDLE PipeHandle)
{
DWORD BytesToRead = 0;
if(!PeekNamedPipe(PipeHandle, NULL, 0, NULL, &BytesToRead, NULL))
return 0;
return BytesToRead;
}
LPSTR ReadStringDataFromPipe(HANDLE PipeHandle, DWORD StringLength)
{
CHAR *ReturnBuffer = new CHAR[StringLength + 1];
if(ReturnBuffer)
{
DWORD BytesRead = ReadDataFromPipe(PipeHandle, (LPBYTE) ReturnBuffer, StringLength);
ReturnBuffer[BytesRead] = 0;
}
return ReturnBuffer;
}
void DisplayNormalOrErrorOutput(LPSTR OutputString, LPSTR ErrorString)
{
if(OutputString && ErrorString)
{
if(*ErrorString)
SimpleMessageBox("There were errors!", ErrorString); else
SimpleMessageBox("Output code", OutputString);
}
}
void SimpleMessageBox(LPCSTR Title, LPCSTR Content)
{
MessageBox(HWND_DESKTOP, Content, Title, MB_OK);
}
SecurityAttributes::SecurityAttributes()
{
security_attributes.nLength = sizeof(SECURITY_ATTRIBUTES);
security_attributes.bInheritHandle = TRUE;
security_attributes.lpSecurityDescriptor = NULL;
}
LPSECURITY_ATTRIBUTES SecurityAttributes::GetPointer()
{
return &security_attributes;
}
ProcessStartupInfo::ProcessStartupInfo(const PipeHandles &ThePipeHandles)
{
ZeroMemory(&startup_info, sizeof(STARTUPINFO));
startup_info.cb = sizeof(STARTUPINFO);
startup_info.hStdInput = ThePipeHandles.input.Read;
startup_info.hStdOutput = ThePipeHandles.output.Write;
startup_info.hStdError = ThePipeHandles.error.Write;
startup_info.dwFlags = STARTF_USESTDHANDLES;
}
LPSTARTUPINFO ProcessStartupInfo::GetPointer()
{
return &startup_info;
}
10-06-2011, 00:00
Geschreven door Fibergeek 
|