Jul 9, 2007

With VB.NET, there is no TextWidth method of Object like we have in VB.

TextWidth : Returns the width of a text string as it would be printed in the current font of a Form, PictureBox, or Printer.


Syntax in VB


object.TextWidth(string)


The TextWidth method syntax has these parts:

object Optional. An object expression that evaluates to an object in the Applies To list. If object is omitted, the Form with the focus is assumed to be object.


String Required. A string expression that evaluates to a string for which the text width is determined. Parentheses must surround the string expression.



Remarks


The width is expressed in terms of the ScaleMode property setting or Scale method coordinate system in effect for object. Use TextWidth to determine the amount of horizontal space required to display the text. If string contains embedded carriage returns, TextWidth returns the width of the longest line.

So What do in VB.NET ?


Well there is a way. Suppose we need to acquire the width of text in a TextBox as TextBox1
Dim myGraphics As System.Drawing.Graphics
myGraphics = Me.CreateGraphics

MsgBox(myGraphics.MeasureString(TextBox1.Text, Me.Font).Width)


This Could be very helpful in MSFlex Grid

You need to Resize Column Width of MSFlexGrid depending upon the Maximum Text width

Private Sub SizeColumns()
Dim g As Graphics = Me.CreateGraphics()
Dim myGraphics As System.Drawing.Graphics
myGraphics = Me.CreateGraphics
Dim FlexWidth2Trans As Integer
FlexWidth2Trans = (1440 / g.DpiX)

NOTE: MSFlexGrid uses twips, but .NET uses pixels. So by multiplying the inches by 1440, the twips to pixel conversion now gives the same result as in the original

Dim row_num As Integer
Dim col_num As Integer
Dim max_width As Single

For col_num = 0 To AxMSFlexGrid1.Cols - 1
max_width = 0
For row_num = 0 To AxMSFlexGrid1.Rows - 1
If max_width < myGraphics.MeasureString(AxMSFlexGrid1.get_TextMatrix(row_num, col_num), Me.Font).Width Then max_width = myGraphics.MeasureString(AxMSFlexGrid1.get_TextMatrix(row_num, col_num), Me.Font).Width * FlexWidth2Trans End If Next row_num AxMSFlexGrid1.set_ColWidth(col_num, max_width + 240) Next col_num End Sub

Jul 4, 2007

How to spawn console processes with redirected standard handles

This article describes how to redirect the input and output of a child process that receives input from the standard input handle or sends output to the standard output handle. The Win32 API enables applications to spawn a child console process with redirected standard handles. This feature allows a parent process to send and receive the input and output of the child process.

Note Some console based applications do not use the standard handles for their input/output (IO) operations. The Win32 API does not support redirection of these processes.

The CreateProcess() API through the STARTUPINFO structure enables you to redirect the standard handles of a child console based process. If the dwFlags member is set to STARTF_USESTDHANDLES, then the following STARTUPINFO members specify the standard handles of the child console based process: HANDLE hStdInput - Standard input handle of the child process.

HANDLE hStdOutput - Standard output handle of the child process.
HANDLE hStdError - Standard error handle of the child process.

You can set these handles to either a pipe handle, file handle, or any handle that can do synchronous reads and writes through the ReadFile() and WriteFile() API. The handles must be inheritable and the CreateProcess() API must specify that inheritable handles are to be inherited by the child process by specifying TRUE in the bInheritHandles parameter. If the parent process only wishes to redirect one or two standard handles, specifying GetStdHandle() for the specific handles causes the child to create the standard handle as it normally would without redirection. For example, if the parent process only needs to redirect the standard output and error of the child process, then the hStdInput member of the STARTUPINFO structure is filled as follows: hStdInput = GetStdHandle(STD_INPUT_HANDLE);


Note Child processes that use such C run-time functions as printf() and fprintf() can behave poorly when redirected. The C run-time functions maintain separate IO buffers. When redirected, these buffers might not be flushed immediately after each IO call. As a result, the output to the redirection pipe of a printf() call or the input from a getch() call is not flushed immediately and delays, sometimes-infinite delays occur. This problem is avoided if the child process flushes the IO buffers after each call to a C run-time IO function. Only the child process can flush its C run-time IO buffers. A process can flush its C run-time IO buffers by calling the fflush() function.

Note Windows 95 and Windows 98 require an extra step when you redirect the standard handles of certain child processes.

The following sample redirects the standard input, output, and error of the child process specified in the CreateProcess call. This sample redirects the provided console process (Child.c).


Sample code
/*++
Copyright (c) 1998 Microsoft Corporation

Module Name:

Redirect.c

Description:

This sample illustrates how to spawn a child console based
application with redirected standard handles.

The following import libraries are required:
user32.lib

Dave McPherson (davemm) 11-March-98
--*/


#include
#pragma comment(lib, "User32.lib")
void DisplayError(char *pszAPI);
void ReadAndHandleOutput(HANDLE hPipeRead);
void PrepAndLaunchRedirectedChild(HANDLE hChildStdOut,
HANDLE hChildStdIn,
HANDLE hChildStdErr);
DWORD WINAPI GetAndSendInputThread(LPVOID lpvThreadParam);
HANDLE hChildProcess = NULL;
HANDLE hStdIn = NULL; // Handle to parents std input.
BOOL bRunThread = TRUE;
void main ()
{
HANDLE hOutputReadTmp,hOutputRead,hOutputWrite;
HANDLE hInputWriteTmp,hInputRead,hInputWrite;
HANDLE hErrorWrite;
HANDLE hThread;
DWORD ThreadId;
SECURITY_ATTRIBUTES sa;

// Set up the security attributes struct.
sa.nLength= sizeof(SECURITY_ATTRIBUTES);
sa.lpSecurityDescriptor = NULL;
sa.bInheritHandle = TRUE;

// Create the child output pipe.

if (!CreatePipe(&hOutputReadTmp,&hOutputWrite,&sa,0))
DisplayError("CreatePipe");
// Create a duplicate of the output write handle for the std error
// write handle. This is necessary in case the child application
// closes one of its std output handles.
if (!DuplicateHandle(GetCurrentProcess(),hOutputWrite,
GetCurrentProcess(),&hErrorWrite,0,
TRUE,DUPLICATE_SAME_ACCESS))
DisplayError("DuplicateHandle");

// Create the child input pipe.
if (!CreatePipe(&hInputRead,&hInputWriteTmp,&sa,0))
DisplayError("CreatePipe");
// Create new output read handle and the input write handles. Set
// the Properties to FALSE. Otherwise, the child inherits the
// properties and, as a result, non-closeable handles to the pipes
// are created.
if (!DuplicateHandle(GetCurrentProcess(),hOutputReadTmp,
GetCurrentProcess(),
&hOutputRead, // Address of new handle.
0,FALSE, // Make it uninheritable.
DUPLICATE_SAME_ACCESS))
DisplayError("DupliateHandle");
if (!DuplicateHandle(GetCurrentProcess(),hInputWriteTmp,
GetCurrentProcess(),
&hInputWrite, // Address of new handle.
0,FALSE, // Make it uninheritable.
DUPLICATE_SAME_ACCESS))
DisplayError("DupliateHandle");

// Close inheritable copies of the handles you do not want to be
// inherited.
if (!CloseHandle(hOutputReadTmp)) DisplayError("CloseHandle");
if (!CloseHandle(hInputWriteTmp)) DisplayError("CloseHandle");

// Get std input handle so you can close it and force the ReadFile to
// fail when you want the input thread to exit.
if ( (hStdIn = GetStdHandle(STD_INPUT_HANDLE)) ==
INVALID_HANDLE_VALUE )
DisplayError("GetStdHandle");

PrepAndLaunchRedirectedChild(hOutputWrite,hInputRead,hErrorWrite);

// Close pipe handles (do not continue to modify the parent).
// You need to make sure that no handles to the write end of the
// output pipe are maintained in this process or else the pipe will
// not close when the child process exits and the ReadFile will hang.
if (!CloseHandle(hOutputWrite)) DisplayError("CloseHandle");
if (!CloseHandle(hInputRead )) DisplayError("CloseHandle");
if (!CloseHandle(hErrorWrite)) DisplayError("CloseHandle");

// Launch the thread that gets the input and sends it to the child.
hThread = CreateThread(NULL,0,GetAndSendInputThread,
(LPVOID)hInputWrite,0,&ThreadId);
if (hThread == NULL) DisplayError("CreateThread");

// Read the child's output.
ReadAndHandleOutput(hOutputRead);
// Redirection is complete

// Force the read on the input to return by closing the stdin handle.
if (!CloseHandle(hStdIn)) DisplayError("CloseHandle");

// Tell the thread to exit and wait for thread to die.
bRunThread = FALSE;
if (WaitForSingleObject(hThread,INFINITE) == WAIT_FAILED)
DisplayError("WaitForSingleObject");
if (!CloseHandle(hOutputRead)) DisplayError("CloseHandle");
if (!CloseHandle(hInputWrite)) DisplayError("CloseHandle");
}

///////////////////////////////////////////////////////////////////////

// PrepAndLaunchRedirectedChild
// Sets up STARTUPINFO structure, and launches redirected child.
///////////////////////////////////////////////////////////////////////
void PrepAndLaunchRedirectedChild(HANDLE hChildStdOut,
HANDLE hChildStdIn,
HANDLE hChildStdErr)
{
PROCESS_INFORMATION pi;
STARTUPINFO si;
// Set up the start up info struct.
ZeroMemory(&si,sizeof(STARTUPINFO));
si.cb = sizeof(STARTUPINFO);
si.dwFlags = STARTF_USESTDHANDLES;
si.hStdOutput = hChildStdOut;
si.hStdInput = hChildStdIn;
si.hStdError = hChildStdErr;
// Use this if you want to hide the child:
// si.wShowWindow = SW_HIDE;
// Note that dwFlags must include STARTF_USESHOWWINDOW if you want to
// use the wShowWindow flags.
// Launch the process that you want to redirect (in this case,
// Child.exe). Make sure Child.exe is in the same directory as
// redirect.c launch redirect from a command line to prevent location
// confusion.
if (!CreateProcess(NULL,"Child.EXE",NULL,NULL,TRUE,
CREATE_NEW_CONSOLE,NULL,NULL,&si,&pi))
DisplayError("CreateProcess");

// Set global child process handle to cause threads to exit.
hChildProcess = pi.hProcess;


// Close any unnecessary handles.
if (!CloseHandle(pi.hThread)) DisplayError("CloseHandle");
}

///////////////////////////////////////////////////////////////////////
// ReadAndHandleOutput
// Monitors handle for input. Exits when child exits or pipe breaks.
///////////////////////////////////////////////////////////////////////
void ReadAndHandleOutput(HANDLE hPipeRead)
{
CHAR lpBuffer[256];
DWORD nBytesRead;
DWORD nCharsWritten;

while(TRUE)
{
if (!ReadFile(hPipeRead,lpBuffer,sizeof(lpBuffer),
&nBytesRead,NULL) || !nBytesRead)
{
if (GetLastError() == ERROR_BROKEN_PIPE)
break; // pipe done - normal exit path.
else
DisplayError("ReadFile"); // Something bad happened.
}

// Display the character read on the screen.
if (!WriteConsole(GetStdHandle(STD_OUTPUT_HANDLE),lpBuffer,
nBytesRead,&nCharsWritten,NULL))
DisplayError("WriteConsole");
}
}


///////////////////////////////////////////////////////////////////////
// GetAndSendInputThread
// Thread procedure that monitors the console for input and sends input
// to the child process through the input pipe.
// This thread ends when the child application exits.
///////////////////////////////////////////////////////////////////////

DWORD WINAPI GetAndSendInputThread(LPVOID lpvThreadParam)
{
CHAR read_buff[256];
DWORD nBytesRead,nBytesWrote;
HANDLE hPipeWrite = (HANDLE)lpvThreadParam;

// Get input from our console and send it to child through the pipe.
while (bRunThread)
{
if(!ReadConsole(hStdIn,read_buff,1,&nBytesRead,NULL))
DisplayError("ReadConsole");
read_buff[nBytesRead] = '\0'; // Follow input with a NULL.
if (!WriteFile(hPipeWrite,read_buff,nBytesRead,&nBytesWrote,NULL))
{
if (GetLastError() == ERROR_NO_DATA)
break; // Pipe was closed (normal exit path).
else
DisplayError("WriteFile");
}
}
return 1;
}


///////////////////////////////////////////////////////////////////////
// DisplayError
// Displays the error number and corresponding message.
///////////////////////////////////////////////////////////////////////

void DisplayError(char *pszAPI)
{
LPVOID lpvMessageBuffer;
CHAR szPrintBuffer[512];
DWORD nCharsWritten;

FormatMessage(
FORMAT_MESSAGE_ALLOCATE_BUFFER|FORMAT_MESSAGE_FROM_SYSTEM,
NULL, GetLastError(),
MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
(LPTSTR)&lpvMessageBuffer, 0, NULL);
wsprintf(szPrintBuffer,
"ERROR: API = %s.\n error code = %d.\n message = %s.\n",
pszAPI, GetLastError(), (char *)lpvMessageBuffer);

WriteConsole(GetStdHandle(STD_OUTPUT_HANDLE),szPrintBuffer,
lstrlen(szPrintBuffer),&nCharsWritten,NULL);

LocalFree(lpvMessageBuffer);
ExitProcess(GetLastError());
}



//////////////////////////////////////////////////////////////////////
// child.c
// Echoes all input to stdout. This will be redirected by the redirect
// sample. Compile and build child.c as a Win32 Console application and
// put it in the same directory as the redirect sample.
//

#include
#include
#include
void main ()
{
FILE* fp;
CHAR szInput[1024];

// Open the console. By doing this, you can send output directly to
// the console that will not be redirected.

fp = fopen("CON", "w");
if (!fp) {
printf("Error opening child console - perhaps there is none.\n");
fflush(NULL);
}
else
{

// Write a message direct to the console (will not be redirected).

fprintf(fp,"This data is being printed directly to the\n");
fprintf(fp,"console and will not be redirected.\n\n");
fprintf(fp,"Since the standard input and output have been\n");
fprintf(fp,"redirected data sent to and from those handles\n");
fprintf(fp,"will be redirected.\n\n");
fprintf(fp,"To send data to the std input of this process.\n");
fprintf(fp,"Click on the console window of the parent process\n");
fprintf(fp,"(redirect), and enter data from it's console\n\n");
fprintf(fp,"To exit this process send the string 'exit' to\n");
fprintf(fp,"it's standard input\n");
fflush(fp);
}



ZeroMemory(szInput,1024);
while (TRUE)
{
gets(szInput);
printf("Child echoing [%s]\n",szInput);
fflush(NULL); // Must flush output buffers or else redirection
// will be problematic.
if (!_stricmp(szInput,"Exit") )
break;
ZeroMemory(szInput,strlen(szInput) );
}
}

Jul 3, 2007

Various methods for launching another program from one program VC++

There are several methods for launching another program from one program.

You can use _spawn(), _exec(), system(), WinExec(), ShellExecute(), ShellExecuteEx(), and CreateProcess().



The system() function is a more portable function.

WinExec(), ShellExecute(), ShellExecuteEx(), and CreateProcess() are unique to Windows programming. All four windows functions allow for launching an application in the background (window-hidden).



The WinExec() is the easiest of the four to use. It only takes two arguments, however MS recommends using the CreateProcess() instead of WinExec on all 32-bit programs.



The ShellExecute() is easier to setup then CreateProcess, and it has more options then WinExec. However, it's also a legacy function. MS recommends using ShellExecuteEx() for Win32 applications.

HINSTANCE ShellExecute(

HWND hwnd,

LPCTSTR lpVerb,

LPCTSTR lpFile,

LPCTSTR lpParameters,

LPCTSTR lpDirectory,

INT nShowCmd

);



The ShellExecuteEx() only takes one parameter, but the parameter is a structure with many members, and it's almost as compicate as the CreateProcess() function.

BOOL ShellExecuteEx(

LPSHELLEXECUTEINFO lpExecInfo

);





The CreateProcess() function takes 10 parameters, and can be tricky to use.

int system( const char *command );

UINT WinExec(

LPCSTR lpCmdLine, // address of command line

UINT uCmdShow // window style for new application

);

BOOL CreateProcess(

LPCTSTR lpApplicationName,

// pointer to name of executable module

LPTSTR lpCommandLine, // pointer to command line string

LPSECURITY_ATTRIBUTES lpProcessAttributes, // process security attributes

LPSECURITY_ATTRIBUTES lpThreadAttributes, // thread security attributes

BOOL bInheritHandles, // handle inheritance flag

DWORD dwCreationFlags, // creation flags

LPVOID lpEnvironment, // pointer to new environment block

LPCTSTR lpCurrentDirectory, // pointer to current directory name

LPSTARTUPINFO lpStartupInfo, // pointer to STARTUPINFO

LPPROCESS_INFORMATION lpProcessInformation // pointer to PROCESS_INFORMATION

);

How to convert Twips to Pixels and back again

Description: Visual Basic uses Twips by default instead of pixels, this shows how to convert between them
Its very easy to convert between Twips and Pixels, using the Screen object.

Heres how to convert from Twips to Pixels for Horizontal (X axis) positions:

CODE: Pixels = Twips / Screen.TwipsPerPixelX


And for Vertical (Y axis) positions:

CODE: Pixels = Twips / Screen.TwipsPerPixelY



To convert back again, just use (for horizontal):

CODE: Twips = Pixels * Screen.TwipsPerPixelX

And for vertical:

CODE: Twips = Pixels * Screen.TwipsPerPixelY


On most systems you can use either horizontal or vertical but I presume in some cases you can't, so its best to use the correct ones.


MSFlexGrid uses twips, but .NET uses pixels. You can use the code below to
convert pixels to twips:


Private m_TwipsPerPixelX As Integer
Private m_TwipsPerPixelY As Integer
....
Using g As Graphics = Me.CreateGraphics()
m_TwipsPerPixelX = 1440 / g.DpiX
m_TwipsPerPixelY = 1440 / g.DpiY
End Using
....
Me.MSFlexGrid1.ColWidth = 100 * m_TwipsPerPixelX