2

I want to read the text contents of the command prompt window. Let's say, I opened a command prompt, then ran a dir command and then pwd command. So the problem statement is that, what ever is present in the command prompt I should be able to read them. I am trying to use Java Native Access library for achieving this, but didn't get any luck with it. I have tried following code. But I am not getting any output.

import com.sun.jna.Native;
import com.sun.jna.platform.win32.User32;
import com.sun.jna.platform.win32.WinDef.HWND;
import com.sun.jna.platform.win32.WinDef.RECT;
import com.sun.jna.platform.win32.WinUser.WNDENUMPROC;
import com.sun.jna.Native;
import com.sun.jna.Pointer;
import com.sun.jna.platform.win32.WinDef.HWND;
import com.sun.jna.platform.win32.WinDef.LRESULT;
import com.sun.jna.platform.win32.WinUser;
import com.sun.jna.win32.StdCallLibrary;
import com.sun.jna.platform.win32.WinDef.LPARAM;
import com.sun.jna.platform.win32.WinDef.WPARAM;

public class NativeExtractor {

    public static void main(String ar[]) throws InterruptedException {
        System.out.println(System.getProperty("sun.arch.data.model"));
        executeNativeCommands();
    }

    public static void executeNativeCommands(){
        User32 user32 = User32.INSTANCE;
        //HWND notePadHwnd = user32.FindWindowA("Notepad",null  );
        HWND consoleHwnd = user32.FindWindowA("ConsoleWindowClass",null  );
        HWND editHwnd = user32.FindWindowExA(consoleHwnd, null, null, null);
        byte[] lParamStr = new byte[512];
        LRESULT resultBool = user32.SendMessageA(editHwnd, User32.WM_GETTEXT, 512, lParamStr);

        System.out.println("The content of the file is : " + Native.toString(lParamStr));
    }

    interface User32 extends StdCallLibrary {
        User32 INSTANCE = (User32) Native.loadLibrary("user32", User32.class);
        int WM_SETTEXT = 0x000c;
        int WM_GETTEXT = 0x000D;
        int GetWindowTextA(HWND hWnd, byte[] lpString, int nMaxCount);
        boolean EnumWindows(WinUser.WNDENUMPROC lpEnumFunc, Pointer arg);
        HWND FindWindowA(String lpClassName, String lpWindowName);
        HWND FindWindowExA(HWND hwndParent, HWND hwndChildAfter, String lpClassName, String lpWindowName);
        LRESULT SendMessageA(HWND paramHWND, int paramInt, WPARAM paramWPARAM, LPARAM paramLPARAM);
        LRESULT SendMessageA(HWND editHwnd, int wmGettext, long l, byte[] lParamStr);
        int GetClassNameA(HWND hWnd, byte[] lpString, int maxCount);

        void EnumChildWindows(HWND hwnd, WNDENUMPROC microsoft_word_document, Object o);
    }
}

Nevertheless, I can read the text of the notepad using below. But things are not working for command prompt . Please help me in resolving this .

public static void executeNativeCommands(){
        User32 user32 = User32.INSTANCE;
        HWND notePadHwnd = user32.FindWindowA("Notepad",null  );
        HWND editHwnd = user32.FindWindowExA(notePadHwnd, null, null, null);
        byte[] lParamStr = new byte[512];
        LRESULT resultBool = user32.SendMessageA(editHwnd, User32.WM_GETTEXT, 512, lParamStr);

        System.out.println("The content of the file is : " + Native.toString(lParamStr));
    }
Daniel Widdis
  • 8,424
  • 13
  • 41
  • 63

1 Answers1

2

A brief survey of other StackOverflow answers like this one indicate that not all applications respond to the SendMessage() function, and the Windows Console (Command Prompt window) is one of those. While SendMessage provides a standard functionality, when it doesn't work you must use the Native API for the program you're trying to read text from; in this case, the Console.

Windows has a complete Console API that includes numerous functions for interacting with the console. Some console functions are already mapped in JNA's WinCon class which is inherited by Kernel32, including the AttachConsole method to link another PID's console to your process, GetConsoleWindow to obtain the handle, and FreeConsole when you are done fetching the handle, but to read the contents of the console you'll need to extend the Kernel32 interface in your own code in order to add more mapped functions:

public interface MyKernel32 extends Kernel32 {
    MyKernel32 INSTANCE = Native.load("kernel32", MyKernel32.class, W32APIOptions.DEFAULT_OPTIONS);

    // Mapped functions go here
}

Writing the full solution is a bit much for this answer, but feel free to update your question as you attempt to implement this. You'll need to map the following functions:

Daniel Widdis
  • 8,424
  • 13
  • 41
  • 63
  • Have tried the following methods , `WinDef.HWND GetConsoleWindow(); int GetConsoleOutputCP(); boolean AttachConsole(int dwProcessId);`. Didn't get any success. Tried the sample program from https://learn.microsoft.com/en-us/windows/console/reading-and-writing-blocks-of-characters-and-attributes. But it's giving **0xC0000005: Access violation reading location 0x00000006.**. I have forgot C big time.Am I doing something wrong, please guide me, I am stuck and not able to progress. – Arunabh Dash Oct 09 '19 at 19:25
  • According to [the docs](https://learn.microsoft.com/en-us/windows/console/attachconsole), "A process can be attached to at most one console. If the calling process is already attached to a console, the error code returned is ERROR_ACCESS_DENIED (5)." Looks like you need to call [FreeConsole](https://learn.microsoft.com/en-us/windows/console/freeconsole) to detach from your current console first. – Daniel Widdis Oct 10 '19 at 00:19