Level Extreme platform
Subscription
Corporate profile
Products & Services
Support
Legal
Français
Writing console programs with VFP
Message
General information
Forum:
Visual FoxPro
Category:
Coding, syntax & commands
Miscellaneous
Thread ID:
00398000
Message ID:
00402102
Views:
17
>>>I've created a utility program which is essentially a workstation configuration tool. Now I'd like to be able to run it from the command line or from a batch file.
>>>
>>
>>VFP is a Winapp who's output is always directed to a Window, not a console. None of the native commands write to STDOUT. You'd have to fall back on writing through API calls, and completely hiding thr VFP main Window through CONFIG.FPW.
>
>I have wanted to do this forever. Can you give a simple "hello world" example?

Well, after a bit of digging and plowing through the MSDN and various bits of arcane lore, the following code has emerged for writing to a console. Lots of this has to do with the fact that often, VFP's parent either didn't own a console, or did not let VFP inherit one from it, and did not create it with a DETACHED_CONSOLE flag. Brace yourself, this can be ugly. I'll add it to the FAQ as well in case anyone really wants to read about it; I strongly recommend hitting the MSDN Library docs on Console apps and functions, and "Systems Programming for Windows 95" by Walter Oney. It's not difficult code, but you have to wrap your mindset a bit, and it takes several API calls to do this.
CLOSE ALL
*  Demo Writing to Console
*  Declare a few things we'll need - constants first
#DEFINE STD_OUTPUT_HANDLE -11
#DEFINE INVALID_HANDLE_VALUE -1
#DEFINE ENABLE_WRAP_AT_EOL 2
#DEFINE ENABLE_PROCESSED_OUTPUT 1
*  API Calls
*  Retrieve the last error recorded by a function using Win32 default error reporting
DECLARE INTEGER GetLastError IN Win32API
*  Allocate a new console - fails if we currently are attached to a console
DECLARE SHORT AllocConsole IN WIN32API
*  Request a pseudohandle to a standard device
DECLARE INTEGER GetStdHandle IN WIN32API INTEGER nStdHandleID
*  Retrieve the current settings of the console handle specified
DECLARE SHORT GetConsoleMode IN WIN32API INTEGER nConsoleHandle, INTEGER @ nConsoleMode
*  Alter the console handling behavior of the specified console handle
DECLARE SHORT SetConsoleMode IN WIN32API INTEGER nConsoleHandle, INTEGER dwMode
*
DECLARE SHORT CloseHandle IN WIN32API INTEGER hHandle
*  Release a console;  does not destroy the console, but detaches the current process from it
DECLARE SHORT FreeConsole IN WIN32API 
*  Direct output to a console handle - can be used to write to StdOut or StdErr
DECLARE SHORT WriteConsole IN WIN32API ;
   INTEGER hConsoleOutput, ; 
   STRING @ lpBuffer, ;
   INTEGER nNumCharsToWrite, ;
   INTEGER @ lpNumCharsWritten, ;
   INTEGER nReserved
LOCAL nStdOutHandle, nStdOutMode, lAllocatedConsole, cStringToWrite, nCharsWritten
*  Check to see if we currently have a console;  if we do, then AllocConsole() will fail and we'll
*  use the console we're attached to - otherwise, create a console to write to.  Track if we do
*  create one so that we can free it when we're done with it, otherwise, stay attached to it
lAllocatedConsole = ( AllocConsole() # 0)
nStdOutHandle = GetStdHandle(STD_OUTPUT_HANDLE)
IF nStdOutHandle = INVALID_HANDLE_VALUE
   MESSAGEBOX('Unable to open StdOut ' + TRANSFORM(GetLastError()))
   RETURN
ENDIF

nStdOutMode = 0
IF GetConsoleMode(nStdOutHandle, @ nStdOutMode) = 0
   MESSAGEBOX('Unable to determine Console Mode ' + TRANSFORM(GetLastError()))
   RETURN
ENDIF
*  We want to enable Word wrap, and allow expansion/interpretation of ASCII control characters
*  like Tab, CR, LF, etc
=SetConsoleMode(nStdOutHandle, BITOR(nStdOutMode,ENABLE_WRAP_AT_EOL+ENABLE_PROCESSED_OUTPUT))
*  Spew
cStringToWrite = "Hello, World" + CHR(13) + CHR(10) + CHR(10) + "and Hello again!"
=INKEY(10)
nCharsWritten = 0
=WriteConsole(nStdOutHandle, cStringToWrite, LEN(cStringToWrite), @ nCharsWritten, 0)
*  You can check how many characters actually were written;  important if using control 
*  sequences/ANSI addressing (not native), backspace, etc.
=INKEY(10)
*  The INKEY() is there just to prove we really do the actual writes to console
nCharsWritten = 0
*  Add a tab - a character processed by the console handler just to prove we can
cStringToWrite = CHR(9) + cStringToWrite
=WriteConsole(nStdOutHandle, cStringToWrite, LEN(cStringToWrite), @ nCharsWritten, 0)
*  The INKEY() is there just to prove we really do the actual writes to console
=INKEY(10)
*  Close your handle when done to allow the OS object to release when fully dereferenced
*
*  If we allocated our own console, and we don't love it any more, we can release it.  If
*  we're going to spawn DOS apps or console WinApps and want to control them, redirect
*  their streams, we won't close the handle (we'll pass it to the child via CreateProcess()
*  or can set up the console as we want our children inheriting the console to act.
=CloseHandle(nStdOutHandle)
IF lAllocatedConsole
   =FreeConsole()
ENDIF
Don't say I never gave you anything...
EMail: EdR@edrauh.com
"See, the sun is going down..."
"No, the horizon is moving up!"
- Firesign Theater


NT and Win2K FAQ .. cWashington WSH/ADSI/WMI site
MS WSH site ........... WSH FAQ Site
Wrox Press .............. Win32 Scripting Journal
eSolutions Services, LLC

The Surgeon General has determined that prolonged exposure to the Windows Script Host may be addictive to laboratory mice and codemonkeys
Previous
Next
Reply
Map
View

Click here to load this message in the networking platform