3

My question is about very antique techologies. I have a task to automate old DOS software (spectrometric) that is running in Windows mode in Windows 98. I made two different solution hovewer both of them doesn't work with DOS application:

  1. First Solution

    • Making DOS Application active
    • Sending input via SendInput function, like this:
    void MossbauerLab::Sm2201::SaveManager::AutoSaveManager::sendKeysViaInput(const std::vector<DWORD>& keys, int keyPause)
    {
        std::vector<DWORD>::const_iterator it;
        INPUT keyBoardInput;
        keyBoardInput.type = INPUT_KEYBOARD;
        keyBoardInput.ki.wScan = 0;
        keyBoardInput.ki.time = 0;
        keyBoardInput.ki.dwExtraInfo = 0;

        for(it = keys.begin(); it != keys.end(); it++)
        {
            keyBoardInput.ki.wVk = (*it);
            keyBoardInput.ki.dwFlags = 0;   // key down
            SendInput(1, &keyBoardInput, sizeof(INPUT));
            Sleep(keyPause);
            keyBoardInput.ki.dwFlags = 2;   // key up
            SendInput(1, &keyBoardInput, sizeof(INPUT));
            Sleep(keyPause);
        }
    }
  1. Generate key press via i8042 keyboard controllers: write to keyboard buffer command using D2 command, like this (KEYBOARD_CMD_REG - 0x64, KEYBOARD_DATA_REG - 0x60):
    void MossbauerLab::Sm2201::SaveManager::AutoSaveManager::sendKeysViaKeyboardController(const std::vector<BYTE>& scanCodes, int keyPause)
    {
        std::vector<BYTE>::const_iterator it;
        for(it = scanCodes.begin(); it != scanCodes.end(); it++)
        {
            // wait untill buffer is empty
            int status = 0;
            int result = 0;
            do
            {
                status = _inp(0x64);
                // std::cout <<"Keyboard status: "<< status << std::endl;
                Sleep(10);
            }
            while (status & 1);

            // send scan code for key down
            _outp(KEYBOARD_CMD_REG, 0xD2);
            _outp(KEYBOARD_DATA_REG, (*it));
            result = _inp(KEYBOARD_DATA_REG);
            std::cout <<"Keyboard command result for KEY DOWN: "<< result << std::endl;
            // send scan code for key up
            BYTE keyUpCode = (*it) | 128;
            Sleep(keyPause);
            _outp(KEYBOARD_CMD_REG, 0xD2);
            _outp(KEYBOARD_DATA_REG, keyUpCode);
            result = _inp(KEYBOARD_DATA_REG);
            std::cout <<"Keyboard command result for KEY UP: "<< result << std::endl;
        }
    }

I tested both of these solutions with standard Notepad window (notepad.exe) and both of them works fine, but i can't get it work with DOS application.

My Code where i generate keyboard input (and whole project): https://github.com/MossbauerLab/Sm2201Autosave/blob/master/MossbauerLab.Sm2201.ExtSaveUtility/src/saveManager/autoSaveManager.cpp

Could you please help me to solve this solution.

Michael Ushakov
  • 720
  • 2
  • 12
  • What you're trying to do won't work because the MS-DOS application is running in a separate VM from the main VM where Windows runs. The two VMs have two different virtualized keyboard controllers. Short of writing a VxD (a 32-bit driver) I'm not sure there's a way to do what you want. – Ross Ridge Jan 29 '20 at 22:44
  • Maybe there is a way to somehow write to MS-DOS Vx Keyboard driver? – Michael Ushakov Jan 30 '20 at 05:09
  • Ross, thank for you comment i have not heard before about VxD, i searched about virtual keyboard driver and found interesting link: https://www-user.tu-chemnitz.de/~heha/vxd/vxd.htm#C09S02 possibly it could help me to find the solution – Michael Ushakov Jan 30 '20 at 05:35
  • 1
    That's something like what you would need. You'd have to write own to write your own VxD, like the "VSAMPLED" example you linked, but it wouldn't be keyboard driver. It would instead just use APIs exposed by the Windows virtual keyboard driver (VKD) like the how example code uses VKD_Force_Keys. – Ross Ridge Jan 30 '20 at 07:35

3 Answers3

1

First of all i want to thank all who interesting this post, all of you gave me some useful info and i finally made what i wanted.

About how it was implemented: i've created VXD driver (it is my proprietary driver and i can't post it code here because i am planning to use it for commercial projects). But the main goal of this comment - YES, it is possible to simulate KEYBOARD INPUT for DOS application running in Windows 98 in window mode. Part of my solution that i could post is on github: https://github.com/MossbauerLab/Sm2201Autosave/blob/master/MossbauerLab.Sm2201.ExtSaveUtility/src/saveManager/autoSaveManager.cpp

Here i am using vXd accessor class: (https://github.com/MossbauerLab/Sm2201Autosave/blob/master/MossbauerLab.Sm2201.ExtSaveUtility/src/utils/windows/vxdAccessor.cpp)

Main idea - interact with driver using W32_DEVICEIOCONTROL driver message handler and DeviceIoControl function and passing struct that have 1 byte align using CTL (define in my driver) CODES: i did not used CTL_CODE macro. This Github project is almost ready ~95% (at present time i just have to manual select window to send by activate it with mouse click and check proper memory free).

Michael Ushakov
  • 720
  • 2
  • 12
0

I had the same problem 16 years ago, and my (less graceful but maybe easier to implement) solution was to put the text I wanted to insert into the clipboard, get the foreground window hWnd, and then use SendMessage() to send it WM_SYSCOMMAND with 0xE001 as the data. IIRC this triggered the paste command from the window's context menu (which I found by using Spy++).

I hope someone finds this useful. :)

Liron
  • 139
  • 9
-1

MS-DOS applications in Windows 98 run in Virtual Real Mode, not in Protected Mode, that's why it's impossible to communicate with them using protected mode drivers or system calls. You need to use BIOS / DOS interrupts to interface with keyboard, Windows drivers will not be able to do that for you.

Thus, the only way to do this, would be to simulate keypresses using another DOS application, but I am not sure whether the BIOS keyboard buffer is virtualised, but if not, then you should be able to pull it off by launching a Virtual Real Mode process from your application (will have to be a separate exe, but you should be able to get away with running it windowless) and pass over keypresses as commandline arguments to send them to BIOS.

This is a very interesting problem, hope this helps and you manage to solve it.

Sos Sosowski
  • 137
  • 3