Windows+Console program

Just starting out? Need help? Post your questions and find answers here.
Seldon
Enthusiast
Enthusiast
Posts: 405
Joined: Fri Aug 22, 2003 7:12 am
Location: Italia

Windows+Console program

Post 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.
Bonne_den_kule
Addict
Addict
Posts: 841
Joined: Mon Jun 07, 2004 7:10 pm

Post by Bonne_den_kule »

I think you have to use windows api for this:
http://msdn.microsoft.com/library/defau ... ctions.asp
Seldon
Enthusiast
Enthusiast
Posts: 405
Joined: Fri Aug 22, 2003 7:12 am
Location: Italia

Post 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.
Seldon
Enthusiast
Enthusiast
Posts: 405
Joined: Fri Aug 22, 2003 7:12 am
Location: Italia

Post 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:
freak
PureBasic Team
PureBasic Team
Posts: 5940
Joined: Fri Apr 25, 2003 5:21 pm
Location: Germany

Post 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.
quidquid Latine dictum sit altum videtur
Seldon
Enthusiast
Enthusiast
Posts: 405
Joined: Fri Aug 22, 2003 7:12 am
Location: Italia

Post 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. :)
User avatar
luis
Addict
Addict
Posts: 3893
Joined: Wed Aug 31, 2005 11:09 pm
Location: Italy

Post 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
Fred
Administrator
Administrator
Posts: 18162
Joined: Fri May 17, 2002 4:39 pm
Location: France
Contact:

Post by Fred »

Patching the binary at runtime is not what i call a good solution...
User avatar
luis
Addict
Addict
Posts: 3893
Joined: Wed Aug 31, 2005 11:09 pm
Location: Italy

Post 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
c4s
Addict
Addict
Posts: 1981
Joined: Thu Nov 01, 2007 5:37 pm
Location: Germany

Re: Windows+Console program

Post 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:
If any of you native English speakers have any suggestions for the above text, please let me know (via PM). Thanks!
User avatar
bbanelli
Enthusiast
Enthusiast
Posts: 544
Joined: Tue May 28, 2013 10:51 pm
Location: Europe
Contact:

Re: Windows+Console program

Post 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
"If you lie to the compiler, it will get its revenge."
Henry Spencer
https://www.pci-z.com/
Post Reply