Consoles and win32

We can perform console I/O with the ReadFile() and WriteFile() functions, but it’s easier to use the specific console I/O functions, ReadConsole() and WriteConsole(). The ReadConsole() and WriteConsole() functions both accept TCHAR, or generic characters. TCHAR characters can be used to describe either ANSI single byte characters or wide double byte Unicode characters; thus, the TCHAR type allows us to be narrow/wide neutral.

The GetStdHandle() function gives us a mechanism for retrieving the standard input, STDIN, the Standard Output, STDOUT, and the standard error handles, STDERR. The GetStdHandle() function takes a single parameter that can be one of three values, STD_INPUT_HANDLE, STD_OUTPUT_HANDLE, and STD_ERROR_HANDLE.

#include "stdafx.h"
#include <Windows.h>

int main()
{
 HANDLE hStdin, hStdout, hStderr;

 hStdin = GetStdHandle(STD_INPUT_HANDLE);
 if (hStdin != INVALID_HANDLE_VALUE) {
 printf("Handle to standard input acquired.\n");
 }
 //combine the steps
 if ((hStdout = GetStdHandle(STD_OUTPUT_HANDLE)) != INVALID_HANDLE_VALUE) {
 printf("Handle to standard output acquired.\n");
 }

 if ((hStderr = GetStdHandle(STD_ERROR_HANDLE)) != INVALID_HANDLE_VALUE){
 printf("Handle to standard error acquired.\n");
 }

 return 0;
}

The SetConsoleMode() and GetConsoleMode() functions allow us to modify and view the console mode for the input or screen buffer. The console mode describes how characters are processed via flags; five commonly used flags, which are enabled by default, are ENABLE_LINE_INPUT, ENABLE_ECHO_INPUT, ENABLE_PROCESSED_INPUT, ENABLE_PROCESSED_OUTPUT, and ENABLE_WRAP_AT_EOL_OUTPUT. Both the SetConsoleMode() and GetConsoleMode() functions return a Boolean value indicating success or failure.

 #include "stdafx.h"
#include <Windows.h>

void PrintConsoleInputFlags(DWORD dwFlags);
void PrintConsoleOutputFlags(DWORD dwFlags);

int main()
{
 HANDLE hStdin, hStdout;
 DWORD dwStdinFlags, dwStdoutFlags;
 //get handles to stdin and stdout
 hStdin = GetStdHandle(STD_INPUT_HANDLE);
 hStdout = GetStdHandle(STD_OUTPUT_HANDLE);

 if (hStdin == INVALID_HANDLE_VALUE || hStdout == INVALID_HANDLE_VALUE) {
 printf("Error getting stdin or stdout.\n");
 exit(EXIT_FAILURE);
 }

 //GetConsoleMode returns Boolean value indicating success
 if (GetConsoleMode(hStdin, &dwStdinFlags)) {
 printf("Console mode for stdin acquired.\n");
 }

 if (GetConsoleMode(hStdout, &dwStdoutFlags)) {
 printf("Console mode for stdout acquired.\n");
 }

 printf("\nFor stdin: \n");
 PrintConsoleInputFlags(dwStdinFlags);
 

 printf("\nFot stdout: \n");
 PrintConsoleOutputFlags(dwStdoutFlags);

 return 0;
}

void PrintConsoleInputFlags(DWORD dwFlags) {
 if (dwFlags & ENABLE_ECHO_INPUT) {
 printf("Echo input enabled.\n");
 }
 if (dwFlags & ENABLE_INSERT_MODE) {
 printf("Insert mode enabled.\n");
 }
 if (dwFlags & ENABLE_LINE_INPUT) {
 printf("Line input enabled.\n");
 }
 if (dwFlags & ENABLE_MOUSE_INPUT) {
 printf("Mouse input enabled.\n");
 }
 if (dwFlags & ENABLE_PROCESSED_INPUT) {
 printf("Processed input enabled.\n");
 }
}

void PrintConsoleOutputFlags(DWORD dwFlags) {
 if (dwFlags & ENABLE_PROCESSED_OUTPUT) {
 printf("Processed output enabled.\n");
 }
}

The ReadConsole() and WriteConsole() functions both return TRUE if and only if the action succeeds. The ReadConsole() function takes a handle to the input buffer, and then two length parameters indicating lengths in generic characters, not bytes. The WriteConsole() function is essentially the same, except the buffer is a pointer to a constant.

#include "stdafx.h"
#include <Windows.h>


int main()
{
 const int Buffer_Length = 2056;

 HANDLE hStdin, hStdout;
 DWORD dwCharsRead, dwCharsWritten;
 TCHAR tszBuffer[Buffer_Length];

 BOOL bSuccess;

 //get handles for standard input
 //and standard output
 hStdin = GetStdHandle(STD_INPUT_HANDLE);
 hStdout = GetStdHandle(STD_OUTPUT_HANDLE);

 if (hStdin == INVALID_HANDLE_VALUE) {
 exit(EXIT_FAILURE);
 }
 else {
 printf("Handle to stdin acquired.\n");
 }

 if (hStdout == INVALID_HANDLE_VALUE) {
 exit(EXIT_FAILURE);
 }
 else {
 printf("Handle to stdout acquired.\n");
 }

 printf("Please enter in some text!\n");

 bSuccess = ReadConsole(hStdin, tszBuffer, Buffer_Length - 2, &dwCharsRead, NULL);

 //replace the enter with the null character
 if (bSuccess) {
 printf("Successfully read from console.\n");
 printf("%d chars read.\n", dwCharsRead);
 tszBuffer[dwCharsRead - 2] = '';
 }

 bSuccess = WriteConsole(hStdout, tszBuffer, _tcslen(tszBuffer), &dwCharsWritten, NULL);

 if (bSuccess) {
 printf("\nSuccessfully wrote to console.\n");
 printf("%d chars written.\n", dwCharsWritten);
 }


 //close the handles!
 CloseHandle(hStdin);
 CloseHandle(hStdout);

 return 0;
}

Note that a Windows process can only have one console.

Advertisements

Directory Management in win32

Creating and deleting directories involves a pair of thankfully simple functions, CreateDirectory() and RemoveDirectory(). The CreateDirectory() function takes two arguments, the first is the pathname to the directory to create, and the second is a pointer to a SECURITY_ATTRIBUTES structure. For the second argument, we can simply put NULL.  The RemoveDirectory() function has only one parameter, the name of the directory to be removed. Both functions return a Boolean value stating the success or failure of the function call.

#include <Windows.h>
#include <stdlib.h>
#include <stdio.h>

int _tmain(int argc, char argv[]){

	if((CreateDirectory("exampleDir", NULL))==FALSE){
		printf("Error creating directory.\n");
		exit(EXIT_FAILURE);
	} else {
		printf("Directory created.\n");
	}

	if((RemoveDirectory("exampleDir"))==FALSE){
		printf("Error removing directory.\n");
		exit(EXIT_FAILURE);
	} else {
		printf("Directory deleted.\n");
	}

	return 0;

}

A process has a working directory. We can both get and set the working directory. The GetCurrentDirectory() function takes two arguments, the size of the buffer in characters, and the buffer to write the full pathname of the directory to. The SetCurrentDirectory() function has one parameter, the name of the directory we wish to set as the current working directory.

#include <Windows.h>
#include <stdio.h>
#include <stdlib.h>

int _tmain(int argc, char argv[]){

	TCHAR szBuffer[MAX_PATH + 1];
	TCHAR szNewDir[] = _T("testdir");
	DWORD dwRValue = 0;
	CreateDirectory(szNewDir, NULL);

	dwRValue = GetCurrentDirectory(MAX_PATH, szBuffer);

	if(dwRValue != 0){
		_tprintf(_T("Current directory is %s\n"), szBuffer);
	} else {
		printf("Error getting current directory.\n");
		exit(EXIT_FAILURE);
	}

	if(!(SetCurrentDirectory(szNewDir))){
		printf("Could not change directory.\n");
		exit(EXIT_FAILURE);
	} else {
		printf("Directory changed.\n");
	}

	if(!(GetCurrentDirectory(MAX_PATH, szBuffer))){
		printf("Could not get working directory.\n");
		exit(EXIT_FAILURE);
	} else {
		_tprintf(_T("Current directory is %s\n"), szBuffer);
	}

	return 0;

}

The ReadConsole() and WriteConsole() functions are used to read and write from the console. Both the ReadConsole() and WriteConsole() functions take five arguments; the first argument is a HANDLE to standard input or standard output.  We get a standard handle using the GetStdHandle() function, which takes a single parameter that can be one of three DWORD values, STD_INPUT_HANDLE, STD_OUTPUT_HANDLE, and STD_ERROR_HANDLE .

#include <Window.h>
#include <stdlib.h>
#include <stdio.h>

int _tmain(int argc, char argv[]){

	//create a handle to standard output
	HANDLE hOut = GetStdHandle(STD_OUTPUT_HANDLE);
	TCHAR *szMsg = "Nice boat!";
	DWORD dwCount;
	BOOLEAN bRValue;

	if(hOut==INVALID_HANDLE_VALUE){
		printf("Could not open a file handle to standard output.\n");
		exit(EXIT_FAILURE);
	}

	WriteConsole(hOut, szMsg, _tcslen(szMsg),  &dwCount, NULL);

	if(dwCount == _tcslen(szMsg)){
		printf("\nThe full message has been printed.\n");
	} else {
		printf("\nError! The full message has not printed.\n");
	}

	CloseHandle(hOut);

	return 0;

}

Note that a process can only have one console at a time.

Standard Handles and win32

Like *nix, a Windows process has three standard devices for input, output, and error reporting; to access these standard devices, Windows needs a HANDLE that is acquired with the GetStdHandle() function. The GetStdHandle() function accepts a DWORD argument and returns a HANDLE on success and INVALID_HANDLE_VALUE otherwise.

The parameter can be one of three values, STD_INPUT_HANDLE, STD_OUTPUT_HANDLE, and STD_ERROR_HANDLE.

#include <Windows.h>
#include <stdio.h>

int _tmain(int argc, _TCHAR* argv[])
{
	printf("%x \n", STD_INPUT_HANDLE);
	printf("%x \n", STD_OUTPUT_HANDLE);
	printf("%x \n", STD_ERROR_HANDLE);

	return 0;
}

The GetStdHandle() function does not create a new or duplicate handle on a standard device. No matter how many times we call GetStdHandle(), the function returns the same handle.

#include 
#include 

int _tmain(int argc, _TCHAR* argv[])
{
	char *szString = "For great justice! ";
	DWORD dwBytesWritten;
	HANDLE hStdin = GetStdHandle(STD_OUTPUT_HANDLE);

	if(hStdin == INVALID_HANDLE_VALUE){
		printf("Error accessing standard input.\n");
	}

	if(WriteFile(hStdin, szString, strlen(szString), &dwBytesWritten, NULL)){
		printf("No problems writing to standard input.\n");
	}

	return 0;
}

The SetStdHandle() function enables us to redirect standard input, standard output, and standard error. The SetStdHandle() function takes two arguments; the first argument is a DWORD value indicating whether we are redirecting standard input, standard output, or standard error, and the second value is a handle to the file we want to redirect to.

#include <Windows.h>
#include <stdio.h>

int _tmain(int argc, _TCHAR* argv[])
{

	HANDLE hFile;

	hFile = CreateFile("textfile.txt", GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);

	if(hFile == INVALID_HANDLE_VALUE){
		printf("Error opening file.");
		return -1;
	}

	if(SetStdHandle(STD_OUTPUT_HANDLE, hFile)==FALSE){
		printf("Error setting standard handle.\n");
		return -2;
	}

	//will print to the file
	//not to the console
	printf("I survived the Kobayashi Maru!\n");
	printf("Photons be free!\n");
	
	return 0;
}

Note that if you call GetStdHandle() after redirecting the standard input, output or error you will get the redirected handle! To recover standard output to the console screen, call CreateFile() with CONOUT$, likewise, a call to CreateFile() with CONIN$ will recover a handle to standard input.