No announcement yet.

command line output

  • Filter
  • Time
  • Show
Clear All
new posts

  • command line output

    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?

  • #2
    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:

    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.

    Last edited by Michael Mattias; 5 May 2008, 01:52 PM.
    Michael Mattias
    Tal Systems (retired)
    Port Washington WI USA
    [email protected]


    • #3
      Originally posted by Michael Mattias View Post
      "kind of" solves the "output" side of things
      OK but that creates a new console, the problem is getting the output into the "parent" console.


      • #4
        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.

        'Program demonstrates how to restore standard output handle in C Runtime Library
        'which is zeroed out by initialization of GUI process.
        #Compile Exe
        #Include ""           '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)
              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!
                    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
              Exit Function
            Case %WM_DESTROY
              Call PostQuitMessage(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)
 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
        End Function


        • #5
          OK but that creates a new console, the problem is getting the output into the "parent" console.
          I "think" you might be able to handle that via redirection... ... by using the 'duplicate handle' options therein.

          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]


          • #6
            Originally posted by Michael Mattias View Post
            Nope, never tried it myself, so I very much look forward to your results.
            I appear to have a serpent by the tail. is also worth looking at, and there is a reference to it (use Q190351 as a search term) in two threads on this forum, both full of relevant stuff which I am gently absorbing. MCM I suspect you have been this way before!

            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?


            • #7
              more insights:


              • #8
                Here's two links from where I was working on this stuff last fall Chris...



                ...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).
                #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;
                 return 0;                                             
                long fnWndProc_OnCommand(lpWndEventArgs Wea)
                 unsigned int i;
                 int hCrt;
                 FILE *hf;
                    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)
                 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.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; 
                 return messages.wParam;


                • #9
                  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).
                  Fred, thanks for that example. I'm using Bloodshed too, and have just downloaded gcc - your code compiled & ran 100%. Also fed up with M$ but in this world that's a bit like objecting to breathing oxygen!

                  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.