Page 1 of 1

Windows+Console program

Posted: Sun Mar 19, 2006 10:59 am
by Seldon
I'm doing a tool to produce the hash of a file. The program has a GUI, but I'd like the user to be able to use it in console mode too (command line). I compile it with 'Windows mode' option and I check if there is an argument passed (ProgramParameter() ) . In that case, I call OpenConsole(), etc...

The problem is that OpenConsole() opens a new console window even if a console window is already open, while I want to print on the current console window (opened by cmd.exe for example).

Any hints ?? Thank you ! :wink:

PS: Of course if I compile it with 'Console mode' option , I'd have a console always opened even if the user doesn't pass any argument.

Posted: Sun Mar 19, 2006 11:14 am
by Bonne_den_kule
I think you have to use windows api for this:
http://msdn.microsoft.com/library/defau ... ctions.asp

Posted: Sun Mar 19, 2006 8:05 pm
by Seldon
Thanks. I tried this:

Code: Select all

tmp$="ciao mondo"

;AllocConsole_()

H_stdOUT=GetStdHandle_(#STD_OUTPUT_HANDLE)
If H_stdOUT<>#INVALID_HANDLE_VALUE
 res=WriteConsole_(H_stdOUT,@tmp$,Len(tmp$),@lunghezza,0)
 MessageBox_(0,"",Str(res),0)
EndIf
I compiled with 'Windows mode' option, but when I make it run from a shell (cmd.exe) it doesn't print anything. It seems I get a valid handle, but WriteConsole() returns 0. If AllocConsole() is used, it works, but of course it opens a new console window.

Posted: Mon Mar 20, 2006 12:52 pm
by Seldon
I've read all the API documentation, but still nothing. I can't believe it isn't possible to have a GUI application that can act as a console one too with no need to open a new console window when it is launched from a shell. I know it's a very specific task, so not much people could be interested, but does anyone have an hint ? I have no more ideas, as I tried (I think) all. :shock:

Posted: Mon Mar 20, 2006 2:51 pm
by freak
I looked into this for quite a while during the v4 development, and i am sorry to say that there is no good solution for this.

The problem is this:
- A console process inherits the console from the parent process (Cmd.exe), but if the parent has no console, there is always one opened. (which looks bad if you have a GUI as well)
- A GUI process does not automatically open a console, but also never inherits the console from its parent. (which makes it useless here as well)

There is no way to get the best of both worlds. I do not really understand the reason for this,
but thats unfortunately how it is.

Since XP, there is the AttachConsole API. See this code:

Code: Select all

Prototype AttachConsole(dwProcessId)
#ATTACH_PARENT_PROCESS = -1

Text$ = "Hello World"+Chr(13)+Chr(10)

If OpenLibrary(0, "Kernel32.dll")
  AttachConsole.AttachConsole = GetFunction(0, "AttachConsole")
  
  If AttachConsole
    If AttachConsole(#ATTACH_PARENT_PROCESS)
      hConsole = GetStdHandle_(#STD_OUTPUT_HANDLE)
      If hConsole <> #INVALID_HANDLE_VALUE
        WriteFile_(hConsole, @Text$, Len(Text$), @nbWritten, 0)      
        WriteFile_(hConsole, @Text$, Len(Text$), @nbWritten, 0)
      Else
        MessageRequester("", "Invalid console handle!")
      EndIf    
      
      FreeConsole_()
    Else
      MessageRequester("", "Not started from a console!")
    EndIf
  Else
    MessageRequester("", "AttachConsole not present!")
  EndIf
  
  CloseLibrary(0)
EndIf
Compile in GUI mode and run both directly and from Cmd.exe

It works in general, but it looks like Cmd.exe is not prepared for a Child process to attach to its console.
It seems that it consideres what the program writes to the console like input
typed from the user, not like a usual console program output.
Here, it prints the path before the output, and you have to hit enter before you can go back to entering commands.

This is the closest i could get to a solution to this problem. I am afraid this is simply not possible.

Posted: Tue Mar 21, 2006 10:52 am
by Seldon
Thank you for your time and explanation !! Now I know it is not possible and I am not doing something wrong. That is a typical Windows thing... under Linux or AmigaOS, you can do it with no problem. :)

Posted: Sun Jun 10, 2007 8:12 pm
by luis
freak wrote:I looked into this for quite a while during the v4 development, and i am sorry to say that there is no good solution for this.
It seem so.

A good read about this is here:

http://blogs.msdn.com/junfeng/archive/2 ... 68531.aspx

Luis

Posted: Sun Jun 10, 2007 8:17 pm
by Fred
Patching the binary at runtime is not what i call a good solution...

Posted: Mon Jun 11, 2007 4:32 pm
by luis
Fred wrote:Patching the binary at runtime is not what i call a good solution...
Neither do I. I liked the the thread, more than the original post.

Quite hilarious the ILDASM story :-)

Luis

Re: Windows+Console program

Posted: Mon Apr 05, 2010 9:13 pm
by c4s
I think it's best to reuse this thread...

So I'm using the AttachConsole_() solution now (see Freaks post) but it raises some questions for me:
- Why is "C:\>" missing at the end? (until I press enter again)
- How is it possible to use Input()?
- Why is Freak using WriteFile_() instead of WriteConsole_()?
- How can I use ClearConsole() or something like "cls"?

I hope someone can answer a couple. :wink:

Re: Windows+Console program

Posted: Wed Jan 29, 2014 6:56 pm
by bbanelli
Greetings,

I hope you don't mind me raising very old topic, but I got a "half-workaround" for this issue.

First, the code:

Code: Select all

Define handle, res, PID, hWnd = GetForegroundWindow_()
Define.MODULEENTRY32 Entry
Entry\dwSize = SizeOf(MODULEENTRY32)

;code for CLI routines

Procedure HideCLIWindow(WindowName.s)
  WinHndl = FindWindow_(0, WindowName)
  If WinHndl
    ShowWindow_(WinHndl,#SW_HIDE)
  Else
    ProcedureReturn 0
  EndIf
  ProcedureReturn 1
EndProcedure

If hWnd
  GetWindowThreadProcessId_(hWnd, @PID)
  handle = CreateToolhelp32Snapshot_(#TH32CS_SNAPMODULE, PID)
  If handle
    res = Module32First_(handle, Entry)
    If res
      CLIWindowName$ = PeekS(@Entry\szExePath)
      HideCLIWindow (CLIWindowName$)
    EndIf
    CloseHandle_(handle)
  EndIf
EndIf

;OpenWindow and other GUI routines
So, basically, I capture currently running window that's named exactly as the running path of open process and simply hide it. Yes, it shows CLI for several moments, but in the end, user experience is not "burdened" with additional open blank CLI window. There is no effect on CLI functionality of application because code is run after CLI routines. Code is compatible (up to the functionality that I used it) with both x86 and x64 Windows (tried from W2k to Win PE amd64 kernel, although CreateToolhelp32Snapshot documentation claims XP as minimum supported client).

Hope this helps someone a bit!

With my best,

Bruno