Author Topic: WriteConsoleInput  (Read 20895 times)

jj2007

  • Member
  • *****
  • Posts: 13957
  • Assembly is fun ;-)
    • MasmBasic
Re: WriteConsoleInput
« Reply #15 on: January 03, 2013, 09:23:59 PM »
Well, I can't compile your source (SendStringsOnDemand) with MASM. Also, when using jWasm, I get an executable that behaviors differently than the EXE you supplied - I get directly an error "invalid handle".

That is odd. The library \Masm32\MasmBasic\MasmBasic.lib should have time stamp 2 Jan 13, 18:33, 68126 bytes. It doesn't work with ML.exe 6.14 (no SSE2), but 6.15 upwards works fine for me.

Sorry to impose MB on you, but re-writing the whole thing in plain Masm32 would be tedious. I am not proficient in C to write a corresponding example, and I haven't found any full example on the web...

It might even help to find an executable written in another language that does prefilling of an Input$() type prompt.

Quote
Also, I've seen some "strange" comments in your code:
Code: [Select]
LOCAL PipeBytes, buffer[8000]:BYTE ; 8102 works, 8104 crashes, slow for small buffers (e.g. 100 bytes) How should one interpret that?

A few lines further down:
invoke ReadFile, hPipe, edi, sizeof buffer, addr PipeBytes, NULL

I have played with several values, of course if you take 2 bytes, you need many ReadFile calls, and that slows it down. Somewhere around 8102 for XP it starts crashing, the usual problem with stack & guard pages, so I chose 8000 as a compromise. This is for XP - Win7 seems to allow higher values.

In any case, thanks a lot for your willingness to help, much appreciated :icon14:

@sinsi: yes, that works perfectly in "direct", i.e. non-piped mode.
pushw KEY_EVENT
...
imul edx, edi, 18

does not crash, but the prefill stops working even in direct mode.

qWord

  • Member
  • *****
  • Posts: 1475
  • The base type of a type is the type itself
    • SmplMath macros
Re: WriteConsoleInput
« Reply #16 on: January 03, 2013, 09:44:47 PM »
I'v download the library this morning. I get this error for all version of MASM
Code: [Select]
SendStringsOnDemand.asm(134) : error A2046:missing single or double quotation mark in string
 cStyle$(2): Macro Called From
  Input$(3): Macro Called From
   Let(1): Macro Called From
the problem is the angle brackets in the literal "Enter x, Date or Time: !>"
MREAL macros - when you need floating point arithmetic while assembling!

jj2007

  • Member
  • *****
  • Posts: 13957
  • Assembly is fun ;-)
    • MasmBasic
Re: WriteConsoleInput
« Reply #17 on: January 03, 2013, 10:02:44 PM »
Sorry, I use JWasm by default and didn't stumble over that one. Here is a workaround for ML 6.15:

                Let esi=Input$(Chr$("Enter x, Date or Time: ", 62),  esi)                ; let's simulate a prompt...

japheth

  • Guest
Re: WriteConsoleInput
« Reply #18 on: January 03, 2013, 10:55:02 PM »

I do not really understand what you are trying to do, but if it's some inter-process communication with "key-strokes" being sent from a parent process to a child process, you should probably forget using pipes and look at DuplicateHandle() instead.

jj2007

  • Member
  • *****
  • Posts: 13957
  • Assembly is fun ;-)
    • MasmBasic
Re: WriteConsoleInput
« Reply #19 on: January 03, 2013, 11:15:59 PM »
I do not really understand what you are trying to do, but if it's some inter-process communication with "key-strokes" being sent from a parent process to a child process, you should probably forget using pipes and look at DuplicateHandle() instead.

The CmdGUI app (CmdGUI_full.exe) launches cmd.exe, displays its output in a standard edit control, and sends lines of text to cmd.exe via a pipe. Cursor up/down works like doskey /history. In short, a standard window instead of a console for cmd.exe. Right-click in CmdGUI to see one advantage of having that.

Then there is a console prog (SendStringsOnDemand.exe) that prompts for input, providing a prefilled string:
Enter x, Date or Time: >date
Everything works fine except prefilling via the pipe.

DuplicateHandle assumes that you have source code control over the child process - not a universal solution.

japheth

  • Guest
Re: WriteConsoleInput
« Reply #20 on: January 04, 2013, 12:55:04 AM »
DuplicateHandle assumes that you have source code control over the child process - not a universal solution.

Yes, I see. Additionally, according to MS, DuplicateHandle() will only copy console handles if target process and source process are identical.

jj2007

  • Member
  • *****
  • Posts: 13957
  • Assembly is fun ;-)
    • MasmBasic
Re: WriteConsoleInput
« Reply #21 on: January 04, 2013, 05:17:53 AM »
Are you aware of any plain C or C++ solution for the prompt with prefill? I have searched a lot, but all I found is examples in Python, Linux C++ and Ruby using the readline library plus a hook (code by Casper):

Code: [Select]
require 'rubygems'
require 'rb-readline'

module RbReadline
  def self.prefill_prompt(str)
    @rl_prefill = str
    @rl_startup_hook = :rl_prefill_hook
  end

  def self.rl_prefill_hook
    rl_insert_text @rl_prefill if @rl_prefill
    @rl_startup_hook = nil
  end
end

RbReadline.prefill_prompt("Previous query")
str = Readline.readline("Enter query: ", true)

puts "You entered: #{str}"

See The GNU Readline Library, 2.2MB to download, but it seems there is no Windows version.

The functionality is not that exotic; most travel agents still have a terminal-like screen where they can edit client data via prefill. Very old technology, it's amazing that they don't switch to Windows.

japheth

  • Guest
Re: WriteConsoleInput
« Reply #22 on: January 04, 2013, 04:41:23 PM »
> Are you aware of any plain C or C++ solution for the prompt with prefill?

Hm, I guess the best solution is some kind of KI ( deutsch: Koud Intschäggtschen ).

A small routine that reads a pipe and writes to console via WriteConsoleInput(). It has to be copied to the "other" address space and run - may be using CreateRemoteThread().

jj2007

  • Member
  • *****
  • Posts: 13957
  • Assembly is fun ;-)
    • MasmBasic
Re: WriteConsoleInput
« Reply #23 on: January 04, 2013, 05:22:55 PM »
'Son cannot speak for himself, so daddy puts the words in his mouth' - interesting idea, thanks Japheth.
Edit: There is one problem, though: In the CmdGUI case, it's the 'son' who knows what to say, i.e. the child process only knows what the prefilled string should contain...

Still, if anybody knows a console proggie that asks for input and offers a prefilled string, let me know. I had hoped to find something among the DOS command, but those which prompt the user do so without offering a string in the readline, it seems...
« Last Edit: January 04, 2013, 06:24:25 PM by jj2007 »

jj2007

  • Member
  • *****
  • Posts: 13957
  • Assembly is fun ;-)
    • MasmBasic
Re: WriteConsoleInput
« Reply #24 on: January 06, 2013, 11:54:12 AM »
I've put an update into the QikPad thread in the campus. Until now, I have not found a solution for the piped WriteConsoleInput problem.

What I did find, though, is that inkey (Masm32, using crt_getch) and Inkey (MasmBasic, using ReadFile) both behave badly when piped through cmd.exe: the proggies hang and must be killed via Task Manager. Workaround is to launch them with start myproggie. In contrast, Input$() does not hang the child process. However, the underlying ReadFile cannot be used as a substitute for inkey; SetConsoleMode 0 works in standalone mode, i.e. one keypress is enough, but in pipes it requires a Return. Confusing ::)

                invoke SetLastError, 0
                mov ebx, rv(GetStdHandle, STD_INPUT_HANDLE)
                invoke SetConsoleMode, ebx, 0        ; enable return after single key press (works standalone but not piped)
                push ecx        ; create a slot for chars read
                mov edx, esp
                invoke ReadFile, ebx, addr buffer, 1000, edx, 0        ; works fine, doesn't block, but needs Return in pipes
                deb 4, "ret", eax, $Err$()
                pop ecx        ; chars read

jj2007

  • Member
  • *****
  • Posts: 13957
  • Assembly is fun ;-)
    • MasmBasic
Re: WriteConsoleInput
« Reply #25 on: January 06, 2013, 11:55:57 AM »
I've put an update into the QikPad thread in the campus. Until now, I have not found a solution for the piped WriteConsoleInput problem.

What I did find, though, is that inkey (Masm32, using crt_getch) and Inkey (MasmBasic, using ReadFile) both behave badly when piped through cmd.exe: the proggies hang and must be killed via Task Manager. Workaround is to launch them with start myproggie. In contrast, Input$() does not hang the child process. However, the underlying ReadFile cannot be used as a substitute for inkey; SetConsoleMode 0 works in standalone mode, i.e. one keypress is enough, but in pipes it requires a Return. Confusing ::)

                invoke SetLastError, 0
                mov ebx, rv(GetStdHandle, STD_INPUT_HANDLE)
                invoke SetConsoleMode, ebx, 0        ; enable return after single key press (works standalone but not piped)
                push ecx        ; create a slot for chars read
                mov edx, esp
                invoke ReadFile, ebx, addr buffer, 1000, edx, 0        ; works fine, doesn't block, but needs Return in pipes
                deb 4, "ret", eax, $Err$()
                pop ecx        ; chars read