It would be useful if my application could behave both as an interactive and a command line program. For this, I need to be able to send output to the command line, but that command line is (I assume) the parent application's console. For example, if the application is called from a "Command Prompt" shell with a parameter, let it echo the parameter to the shell, and if called without a parameter, let it open a window. How would I do that?
Announcement
Collapse
No announcement yet.
command line output
Collapse
X
-
Well, STDOUT for PB.Windows (Simple STDOUT for PB/DLL and PB/Win 2-13-04) "kind of" solves the "output" side of things, except for the documented bug in Windows/XP I recently posted here:
http://www.powerbasic.com/support/pb...ad.php?t=37183
My current workaround (GetConsoleWindow()) will only work on Window/XP+, and of course does not allow for the possibility that the STDOUT was correctly redirected to another handle by the parent process. I was going to put the code needed for that into that STDOUT code Real Soon Now but have not gotten to it.
MCMLast edited by Michael Mattias; 5 May 2008, 01:52 PM.Michael Mattias
Tal Systems (retired)
Port Washington WI USA
[email protected]
http://www.talsystems.com
-
Here's an example of opening a console window from a GUI process and using C's printf to output text. I know this is posted here someplace or other but I never put it in source code. It involves some of the same issues I believe as Michael was alluding to.
Code:'Program demonstrates how to restore standard output handle in C Runtime Library 'which is zeroed out by initialization of GUI process. #Compile Exe #Include "Win32api.inc" 'Translation of Windows.h for PowerBASIC %IDC_BUTTON1 = 1250 'ctrl id of button %O_TEXT = &H4000 'from Fcntl.h Type FILE 'From stdio.h 'When a GUI application is started the three standard OS handles pChar As Asciiz Ptr 'STD_INPUT_HANDLE, STD_OUTPUT_HANDLE, and STD_ERROR_HANDLE are all cnt As Long 'zeroed out by the console initialization routines. These three pBase As Asciiz Ptr 'handles are replaced by valid values when a GUI application calls flag As Long 'AllocConsole(). Therefore, once this is done, calling GetStdHandle() fil As Long 'will always return valid handle values. The problem is that the charbuf As Long 'CRT has already completed initialization before an application gets bufsize As Long 'a chance to call AllocConsole(); the three low I/O handles 0, 1, TmpFileName As Asciiz Ptr 'and 2 have already been set up to use the original zeroed out OS End Type 'handles, so all CRT I/O is sent to invalid OS handles and CRT output 'does not appear in the console. Declare Function GetConsoleWindow Lib "Kernel32.dll" Alias "GetConsoleWindow" () As Dword Declare Function printf CDecl Lib "msvcrt.dll" Alias "printf" _ 'printf from stdio.h ( _ szFmtStr As Asciiz _ [, _ Byval lpVar1 As Any, _ Byval lpVar2 As Any, _ Byval lpVar3 As Any, _ Byval lpVar4 As Any _ ] _ ) As Long Declare Function Open_OSFileHandle CDecl Lib "msvcrt.dll" Alias "_open_osfhandle" _ 'from IO.h ( _ Byval hHandle As Long, _ Byval iType As Long _ ) As Long Declare Function FDOpen CDecl Lib "msvcrt.dll" Alias "_fdopen" _ 'from stdio.h ( _ Byval hHandle As Long, _ ByRef pszStr As Asciiz _ ) As Dword Function WndProc(Byval hWnd As Long,Byval wMsg As Long,Byval wParam As Long,Byval lParam As Long) As Long Select Case wMsg Case %WM_CREATE Local hButton As Dword Local hIns As Dword hIns=GetModuleHandle(Byval 0) hButton=CreateWindow("button","Show Console!",%WS_CHILD Or %WS_VISIBLE,110,65,200,25,hWnd,%IDC_BUTTON1,hIns,Byval 0) WndProc=0 Exit Function Case %WM_COMMAND If Lowrd(wParam)=%IDC_BUTTON1 And HiWrd(wParam)=%BN_CLICKED Then Local hStdOutput As Dword 'Standart Output Handle Local hf,ptrFile As FILE Ptr 'FILE * Local hDll,hCrt,dwWeight As Dword Local hSysMenu As Dword Register i As Long hDll=LoadLibrary("msvcrt.dll") 'Load/Increment Reference Count on msvcrt.dll If hDll Then 'Get base address of exported symbol _iob from msvcrt.dll. _iob is an ptrFile=GetProcAddress(hDll,"_iob") 'array of FILE structs that holds the stdin, stdout, and stderr handles. Call AllocConsole() 'These handels are zeroed out at initialization of a GUI process, and hSysMenu=GetSystemMenu(GetConsoleWindow(),Byval 0) 'must be reset with valid operating system handles if Call DeleteMenu(hSysMenu,6,%MF_BYPOSITION) 'console output is desired in a GUI process. With a hCrt=Open_OSFileHandle(GetStdHandle(%STD_OUTPUT_HANDLE),%O_TEXT) 'valid handel to stdout returned in hf, it hf=FDOpen(hCrt,"w") 'is restored back in position 1 of the i/o buffer FILE array with @ptrFile[1][email protected] '@[email protected] printf output using CRT in PowerBASIC! dwWeight=210 For i=1 To 200 ' printf("%d" + Chr$(9) + "My Name Is Fred And I Weigh %u Pounds!"+$Cr+$Lf,i,dwWeight) Next i Call FreeLibrary(hDll) 'Free/decrement reference count on msvcrt.dll End If End If WndProc=0 Exit Function Case %WM_DESTROY Call PostQuitMessage(0) WndProc=0 Exit Function End Select WndProc=DefWindowProc(hWnd, wMsg, wParam, lParam) End Function Function WinMain(Byval hIns As Long, Byval hPrev As Long, Byval lpCL As Asciiz Ptr, Byval iShow As Long) As Long Local szBuffer As Asciiz * 64 Local wc As WNDCLASSEX Local Msg As tagMsg Local hWnd As Dword szBuffer="Console_Output" : wc.lpszClAssName=Varptr(szBuffer) wc.lpfnWndProc=Codeptr(WndProc) : wc.cbSize=Sizeof(wc) wc.style=%CS_HREDRAW Or %CS_VREDRAW : wc.hInstance=hIns wc.cbClsExtra=0 : wc.cbWndExtra=0 wc.hIcon=LoadIcon(%NULL, Byval %IDI_APPLICATION) : wc.hCursor=LoadCursor(%NULL, Byval %IDC_ARROW) wc.hbrBackground=%COLOR_BTNFACE+1 : wc.lpszMenuName=%NULL Call RegisterClAssEx(wc) szBuffer="GUI Console Output With C Runtime Library From PowerBASIC!" hWnd=CreateWindow("Console_Output",szBuffer,%WS_OVERLAPPEDWINDOW,500,550,440,200,0,0,hIns,Byval 0) Call ShowWindow(hWnd,iShow) Call UpdateWindow(hWnd) While GetMessage(Msg,%NULL,0,0) TranslateMessage Msg DispatchMessage Msg Wend Function=msg.wParam End Function
Fred
"fharris"+Chr$(64)+"evenlink"+Chr$(46)+"com"
Comment
-
OK but that creates a new console, the problem is getting the output into the "parent" console.
Nope, never tried it myself, so I very much look forward to your results.Michael Mattias
Tal Systems (retired)
Port Washington WI USA
[email protected]
http://www.talsystems.com
Comment
-
Originally posted by Michael Mattias View PostNope, never tried it myself, so I very much look forward to your results.
Trying to compile C examples, my current C compiler (MinGW) seems to hate them all, downloaded M$ Visual C++ Express Edition which looks pretty but needs (I suspect) a day's familiarisation. Who ever heard of a compiler without a COMPILE button?
Comment
-
Here's two links from where I was working on this stuff last fall Chris...
http://www.powerbasic.com/support/pb...ad.php?t=35026
http://www.powerbasic.com/support/pb...ad.php?t=34989
...and here's a c program I got working before I got it working in PowerBASIC
(compiles with gcc. I used the Bloodshed IDE & dev suite from Sourceforge. Got mad at MS couple years back and won't use their stuff anymore).
Code:#include <windows.h> #include <stdio.h> #include <stdlib.h> #include <fcntl.h> //contains equate _O_TEXT #include <io.h> //contains declare for _open_osfhandle((long)GetStdHandle(STD_OUTPUT_HANDLE),_O_TEXT); #define IDC_BUTTON 1500 //extern int iArr[]; //_CRTIMP int __cdecl _open_osfhandle(long, int); //long CDecl Lib "msvcrt.dll" _open_osfhandle(Long hHandle, Long iType) typedef struct WindowsEventArguments //Package Window Procedure Parameters into structure { HWND hWnd; //Handle of Window WPARAM wParam; //Window Parameter LPARAM lParam; //Long Parameter HINSTANCE hIns; //Instance Handle (Resolves To Process Address) }WndEventArgs, *lpWndEventArgs; long fnWndProc_OnCreate(lpWndEventArgs Wea) //Called One Time During Window Creatiion { HWND hButton; Wea->hIns=((LPCREATESTRUCT)Wea->lParam)->hInstance; hButton=CreateWindow("button","Execute",WS_CHILD|WS_VISIBLE,70,70,141,30,Wea->hWnd,(HMENU)IDC_BUTTON,Wea->hIns,0); return 0; } long fnWndProc_OnCommand(lpWndEventArgs Wea) { unsigned int i; int hCrt; FILE *hf; if(LOWORD(Wea->wParam)==IDC_BUTTON) { AllocConsole(); hCrt=_open_osfhandle((long)GetStdHandle(STD_OUTPUT_HANDLE),_O_TEXT); hf = _fdopen( hCrt, "w" ); *stdout = *hf; i = setvbuf( stdout, NULL, _IONBF, 0 ); printf("My Name Is Fred!\n"); MessageBox(Wea->hWnd,"Hopefully, You See A Console?","See A Console?",MB_ICONINFORMATION); } return 0; } long fnWndProc_OnClose(lpWndEventArgs Wea) //This function handles the WM_CLOSE message { //sent when the 'x' button is clicked. if(MessageBox(Wea->hWnd,"Do You Wish To Exit This App?","Exit Check?",MB_YESNO)==IDYES) { DestroyWindow(Wea->hWnd); PostQuitMessage(WM_QUIT); } return 0; } long __stdcall fnWndProc(HWND hwnd,UINT msg,WPARAM wParam,LPARAM lParam) //This is the all important Window { //Procedure. Note that in WinMain() WndEventArgs wea; //the WNDCLASSEX variable wc has a //field lpfnWndProc. This is pro- switch (msg) //nounced long pointer to Window { //Procedure. Below you can see where case WM_CREATE: //this variable was set to the wea.hWnd=hwnd, wea.wParam=wParam, wea.lParam=lParam; //address of this function. All return fnWndProc_OnCreate(&wea); //messages destined for this program case WM_COMMAND: //Windows will package up into a wea.hWnd=hwnd, wea.wParam=wParam, wea.lParam=lParam; //message packet consisting of the four return fnWndProc_OnCommand(&wea); //parameters to this function and case WM_CLOSE: //and it will come blowing through wea.hWnd=hwnd, wea.wParam=wParam, wea.lParam=lParam; //here at blinding speed. return fnWndProc_OnClose(&wea); } return DefWindowProc(hwnd,msg,wParam,lParam); } int __stdcall WinMain(HINSTANCE hIns,HINSTANCE hPrevIns,LPSTR lpszArgument,int iShow) { //The program starts in WinMain(). The WNDCLASSEX structure variable char szClassName[]="Form1"; //wc is filled out with general characteristics of a window. Then WNDCLASSEX wc; //the class is RegisteredClassEx()'ed. Directly after that a MSG messages; //CreateWindow() call instantiates an instance of the class. Then HWND hWnd; //the program drops into a message processing loop in which any messages //destined for this program are DispatchMessage()'ed to the fnWndProc(). wc.lpszClassName=szClassName; wc.lpfnWndProc=fnWndProc; wc.cbSize=sizeof (WNDCLASSEX); wc.style=CS_DBLCLKS; wc.hIcon=LoadIcon(NULL,IDI_APPLICATION); wc.hInstance=hIns; wc.hIconSm=LoadIcon(NULL, IDI_APPLICATION); wc.hCursor=LoadCursor(NULL,IDC_ARROW); wc.hbrBackground=(HBRUSH)COLOR_BACKGROUND; wc.cbWndExtra=0; wc.lpszMenuName=NULL; wc.cbClsExtra=0; RegisterClassEx(&wc); hWnd=CreateWindow(szClassName,"Form1",WS_OVERLAPPEDWINDOW,200,100,300,250,HWND_DESKTOP,0,hIns,0); ShowWindow(hWnd,iShow); while(GetMessage(&messages,NULL,0,0)) { TranslateMessage(&messages); DispatchMessage(&messages); } return messages.wParam; }
Fred
"fharris"+Chr$(64)+"evenlink"+Chr$(46)+"com"
Comment
-
Originally posted by Fred Harris View Post...and here's a c program I got working before I got it working in PowerBASIC (compiles with gcc. I used the Bloodshed IDE & dev suite from Sourceforge. Got mad at MS couple years back and won't use their stuff anymore).
What I'm after is to be able to run a single executable either as a GUI (if called without parameters) or as a command line exe from a batch file or a script. If run as a GUI, the calling shell does not need to wait for me. If called from a BAT or script, then the calling shell has to wait & receive my STDOUT and STDERR.
Comment
Comment