Консоль и размер буфера ввода

Тема в разделе "WASM.WIN32", создана пользователем n0hack, 18 июл 2008.

  1. n0hack

    n0hack New Member

    Публикаций:
    0
    Регистрация:
    3 июн 2008
    Сообщения:
    71
    Уважаемые коллеги! :)
    Не сталкивался ли кто с такой проблемой:
    Имеется консольное приложение. Для ввода данных из stdin используется небольшой буфер (16 байт для определенности). Нужно организовать ввод с помощью winapi (желательно CreateFile("CONIN$", ....) / ReadFile()) так, чтобы пользователь не мог ввести данных больше, чем вмещает буфер. Поясню на примере:

    Код (Text):
    1. #include <windows.h>
    2.  
    3. CHAR Buff[16];
    4.  
    5. void main() {
    6.     HANDLE hStdOut = CreateFile("CONOUT$", GENERIC_WRITE, FILE_SHARE_WRITE,
    7.         NULL, OPEN_EXISTING, 0, NULL);
    8.  
    9.     if(hStdOut == INVALID_HANDLE_VALUE)
    10.         ExitProcess(0);
    11.  
    12.     HANDLE hStdIn = CreateFile("CONIN$", GENERIC_READ, FILE_SHARE_READ,
    13.         NULL, OPEN_EXISTING, 0, NULL);
    14.  
    15.     if(hStdIn == INVALID_HANDLE_VALUE) {
    16.         CloseHandle(hStdOut);
    17.         ExitProcess(0);
    18.     }
    19.  
    20.     DWORD dwTemp;
    21.  
    22.     do {
    23.         ReadFile(hStdIn, Buff, sizeof(Buff), &dwTemp, NULL);
    24.         dwTemp = dwTemp < 2 ? 0 : dwTemp - 2;
    25.         Buff[dwTemp] = 0;
    26.         WriteFile(hStdOut, Buff, lstrlen(Buff), &dwTemp, NULL);
    27.         WriteFile(hStdOut, "\n", 1, &dwTemp, NULL);
    28.     } while(lstrcmp(Buff, "exit"));
    29.  
    30.     CloseHandle(hStdIn);
    31.     CloseHandle(hStdOut);
    32.     ExitProcess(0);
    33. }
    Пользователь может ввести до 256-и байт (по крайней мере в win2k sp4), после чего выполнится несколько итераций цикла. Долго курил в MSDN и гугл, все что нашел - топик на rsdn 2004 года без единого ответа. В итоге пришел к такому методу:

    Код (Text):
    1. #include <windows.h>
    2.  
    3. HANDLE hStdIn, hStdOut;
    4. DWORD dwTemp;
    5. CHAR Buff[16];
    6.  
    7. // Ввод одного символа
    8. CHAR InChar() {
    9.     DWORD dwTemp;
    10.     CHAR nChar = 0;
    11.     ReadFile(hStdIn, &nChar, 1, &dwTemp, NULL);
    12.     return nChar;
    13. }
    14.  
    15. // Вывод одного символа
    16. VOID OutChar(CHAR nChar) {
    17.     DWORD dwTemp;
    18.     WriteFile(hStdOut, &nChar, 1, &dwTemp, NULL);
    19. }
    20.  
    21. // Ввод строки из stdin посимвольно
    22. DWORD InString(PCHAR szString, DWORD dwBuffSize) {
    23.     DWORD dwSaveSize, dwSize = 0;
    24.     PCHAR lpStr = szString;
    25.     CHAR nChar;
    26.  
    27.     // оставляем один байт под терминатор
    28.     dwBuffSize--;
    29.  
    30.     while((nChar = InChar()) != '\r') {
    31.         dwSaveSize = dwSize;
    32.  
    33.         if(nChar == '\x08') {
    34.             // backspace
    35.             if(dwSize) {
    36.                 lpStr--;
    37.                 dwSize--;
    38.                 WriteFile(hStdOut, "\x08\x20\x08", 3, &dwTemp, NULL);
    39.             }
    40.             continue;
    41.         }
    42.        
    43.         // игнорируем служебные символы
    44.         // в частности - табуляцию, ибо одним пробелом при
    45.         // нажатии backspace не затрешь
    46.         if(((BYTE)nChar >= 32)&&(dwSize < dwBuffSize)) {
    47.             dwSize++;
    48.             *lpStr++ = nChar;
    49.             OutChar(nChar);
    50.         }
    51.     }
    52.  
    53.     OutChar('\n');
    54.  
    55.     *lpStr = 0;
    56.     return dwSize;
    57. }
    58.  
    59. int main() {
    60.     hStdOut = CreateFile("CONOUT$", GENERIC_WRITE, FILE_SHARE_WRITE,
    61.         NULL, OPEN_EXISTING, 0, NULL);
    62.  
    63.     if(hStdOut == INVALID_HANDLE_VALUE)
    64.         ExitProcess(0);
    65.  
    66.     hStdIn = CreateFile("CONIN$", GENERIC_READ, FILE_SHARE_READ,
    67.         NULL, OPEN_EXISTING, 0, NULL);
    68.  
    69.     if(hStdIn == INVALID_HANDLE_VALUE) {
    70.         CloseHandle(hStdOut);
    71.         ExitProcess(0);
    72.     }
    73.  
    74.     // для посимвольного ввода-вывода
    75.     SetConsoleMode(GetStdHandle(STD_INPUT_HANDLE), 0);
    76.  
    77.     do {
    78.         InString(Buff, sizeof(Buff));
    79.         WriteFile(hStdOut, Buff, lstrlen(Buff), &dwTemp, NULL);
    80.         WriteFile(hStdOut, "\n", 1, &dwTemp, NULL);
    81.     } while(lstrcmp(Buff, "exit"));
    82.  
    83.     CloseHandle(hStdIn);
    84.     CloseHandle(hStdOut);
    85.     ExitProcess(0);
    86.     return 0;
    87. }
    Тут все работает, как надо, но нет таких удобных вещей, как истории ввода, работающих кнопочек home/end и тп... Хотелось бы реализовать сабж как-нибудь попроще, но пока не получается. Пользоваться ReadConsoleInput() что-то совсем не хочется. Посоветуйте что-нибудь.
     
  2. driver

    driver New Member

    Публикаций:
    0
    Регистрация:
    18 июн 2008
    Сообщения:
    302
    go out с нашего сайта - :dntknw: -
     
  3. Magnum

    Magnum New Member

    Публикаций:
    0
    Регистрация:
    29 дек 2007
    Сообщения:
    925
    n0hack
    немного не уловил идею
    ну что с того, что он введет данных больше??
    считываются только 16 байт, не больше.
    уточни задачу
    обрисуй предельно ясно
    т.к. ничего не понятно, что ты хочешь сделать
     
  4. n0hack

    n0hack New Member

    Публикаций:
    0
    Регистрация:
    3 июн 2008
    Сообщения:
    71
    driver
    Пардон? ((((:

    Magnum
    А Вы подумайте, что будет, если я попрошу пользователя ввести сначала его имя, а потом фамилию первым способом :)
     
  5. n0hack

    n0hack New Member

    Публикаций:
    0
    Регистрация:
    3 июн 2008
    Сообщения:
    71
    Есть конечно сделать Buff[256], но меня интересует именно как не позволить юзверю ввести более N символов.
     
  6. Magnum

    Magnum New Member

    Публикаций:
    0
    Регистрация:
    29 дек 2007
    Сообщения:
    925
    n0hack
    чисто интуитивно что-то мне подсказывает, что там где есть CreateFile, там есть и SetFilePointer и GetFilePointer

    следовательно запомнить метку начала ввода и далее через GetFilePointer считать число введенных символов
     
  7. n0hack

    n0hack New Member

    Публикаций:
    0
    Регистрация:
    3 июн 2008
    Сообщения:
    71
    Magnum
    Ага, я тоже так думал :)
    Не канает SetFilePointer с консолью. И к тому же эту функцию можно использовать только по схеме "позволить пользователю ввести сколько ему захочется, а потом отбросить лишнее, чтобы не мешалось при следующем чтении". А задача стоит - НЕ ДАТЬ пользователю ввести более, чем положено.
     
  8. Magnum

    Magnum New Member

    Публикаций:
    0
    Регистрация:
    29 дек 2007
    Сообщения:
    925
    n0hack
    да в цикл возьми
    если длина строки > заданной --- тогда очишаешь строчку в консоли, возвращаешь указатель на место и пусть вводит строку повторно
     
  9. n0hack

    n0hack New Member

    Публикаций:
    0
    Регистрация:
    3 июн 2008
    Сообщения:
    71
    Magnum
    некрасиво )
     
  10. n0hack

    n0hack New Member

    Публикаций:
    0
    Регистрация:
    3 июн 2008
    Сообщения:
    71
    но спасибо за идею.
    пока посплю. может утром что в голову придет.
     
  11. Com[e]r

    Com[e]r Com[e]r

    Публикаций:
    0
    Регистрация:
    20 апр 2007
    Сообщения:
    2.624
    Адрес:
    ого..
    девайс, я чего то тоже неуловил про "наш сайт" =\
    n0hack, красиво всё, и в коде будет красиво, и на экране( ты только представь: сейчас хрен где найдёшь консольную прогу, которая с цветами работает или позицию курсора устанавливает! )
     
  12. n0hack

    n0hack New Member

    Публикаций:
    0
    Регистрация:
    3 июн 2008
    Сообщения:
    71
    Ну, как выяснилось, работать с конcолью "на низком уровне" в терминологии MS не так страшно - пара вечеров, примерно 500 строк кода на си и все работает, как часы. Но я бы не советовал никому этим заниматься без явной нужды. Код не выкладываю - сыроват пока.