Модераторы: feodorv, GremlinProg, xvr, Fixin
  

Поиск:

Ответ в темуСоздание новой темы Создание опроса
> Добраться до названия нажатой клавиши, LL_KBHOOK, GetKeyNameText 
:(
    Опции темы
neutrino
Дата 11.3.2011, 12:48 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Gothic soul
****


Профиль
Группа: Модератор
Сообщений: 3041
Регистрация: 25.3.2002
Где: Верхняя Галилея, Кармиэль

Репутация: нет
Всего: 62



Приветствую!

Пишу keylogger - проект по одному из курсов. Соответственно необходимо сохранять нажатые клавиши. Это касается всех клавиш. Для этих целей решил использовать функцию WinAPI GetKeyNameText.
Вот код самой функции-callback:
Код

LRESULT CALLBACK KeyLogger::LowLevelKeyboardProc( int nCode, WPARAM wParam, LPARAM lParam )
{
    bool handled = false;
    
    KBDLLHOOKSTRUCT *pKeyBoard = (KBDLLHOOKSTRUCT *)lParam;

    if (wParam == WM_KEYDOWN)
    {
        // This is unrelated code, see below (I wanted to use it for all other keys)
        HKL layout = GetKeyboardLayout(0);
        unsigned char keyState[256];
        GetKeyboardState(keyState);
        char unicode[8];
        //int success = ToUnicodeEx(pKeyBoard->vkCode, pKeyBoard->scanCode, keyState, (LPWSTR)unicode, 2, pKeyBoard->flags, layout);
        
        DWORD dwMsg = 1;
        dwMsg += pKeyBoard->scanCode << 16;
        dwMsg += pKeyBoard->flags << 24;

        const int KEYNAME_LENGTH = 0x100;
        char keyname[KEYNAME_LENGTH]={0};
        keyname[0] = '[';

        int act_length = GetKeyNameText(dwMsg, (LPTSTR)(keyname+1), KEYNAME_LENGTH) + 1;
        DWORD errcode = GetLastError();
        keyname[act_length] = ']';

        datalog->log(unicode);
    }


В результате, если я например нажимаю на Shift, то функция ничего не возвращает (записывает 0 символов в строку keyname). GetLastError вернул код ошибки 998 - ERROR_NOACCESS
998 (0x3E6)
"Invalid access to memory location."

Что я делаю не так?
В C/CPP - опыта почти нет.


--------------------
The truth comes from within ...

Покойся с миром, Vit 
PM MAIL WWW ICQ Skype GTalk   Вверх
neokoder
Дата 11.3.2011, 16:21 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Шустрый
*


Профиль
Группа: Участник
Сообщений: 69
Регистрация: 14.4.2010

Репутация: нет
Всего: -3



Скорее всего ошибка в формировании dwMsg, посмотри повнимательнее. Должно быть что-то типа такого(не проверял):
Код

DWORD dwMsg, tmp;

dwMsg=0;
dwMsg |= pKeyBoard->scanCode << 16;
tmp=0x01&pKeyBoard->flags;
dwMsg |= tmp<<24;
dwMsg |=0x2FFFFFF;

PM MAIL   Вверх
xvr
Дата 11.3.2011, 21:57 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Комодератор
Сообщений: 7046
Регистрация: 28.8.2007
Где: Дублин, Ирландия

Репутация: 40
Всего: 223



Цитата(neutrino @  11.3.2011,  12:48 Найти цитируемый пост)
(LPTSTR)(keyname+1)

Вот это говорит о том, что у вас Unicode'ный проект, а вы пытаетесь скормить функции обычную строку, вместо Unicode'а. 
Хотя даже в этом случае функция не должна возвращать ошибку

PM MAIL   Вверх
neutrino
Дата 11.3.2011, 23:16 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Gothic soul
****


Профиль
Группа: Модератор
Сообщений: 3041
Регистрация: 25.3.2002
Где: Верхняя Галилея, Кармиэль

Репутация: нет
Всего: 62



neokoder, Пробовал твоим способом - та же ошибка. Блин.


xvr
Цитата(xvr @  11.3.2011,  20:57 Найти цитируемый пост)
Вот это говорит о том, что у вас Unicode'ный проект, а вы пытаетесь скормить функции обычную строку, вместо Unicode'а. 

А какая в принципе ей разница, если это выходной параметр? Я просто передал указатель на место в памяти куда название кнопки нужно записать. Ну и скастил, т.к. иначе функция не хотела его есть.


--------------------
The truth comes from within ...

Покойся с миром, Vit 
PM MAIL WWW ICQ Skype GTalk   Вверх
volatile
Дата 12.3.2011, 00:40 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Завсегдатай
Сообщений: 2107
Регистрация: 7.1.2011

Репутация: 13
Всего: 85



Цитата(neutrino @  11.3.2011,  23:16 Найти цитируемый пост)
А какая в принципе ей разница,

Хм.., разница присутствует.
Цитата(neutrino @  11.3.2011,  12:48 Найти цитируемый пост)
 int act_length = GetKeyNameText(dwMsg, (LPTSTR)(keyname+1), KEYNAME_LENGTH) + 1;

Вы передаете длину строки в элементах
KEYNAME_LENGTH у вас = 0x100; то есть 256 байт.
фактически вы уменьшили его еще на единицу, так как передаете (keyname+1). То есть размер вашего буфера 255 байт.
а функция считает что у нее есть 256 wchar_t, то есть 512 байт.
От сюда впелне логично, что
Цитата(neutrino @  11.3.2011,  12:48 Найти цитируемый пост)
"Invalid access to memory location."

это первое на что обратил внимание...
PM MAIL   Вверх
neokoder
Дата 12.3.2011, 20:01 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Шустрый
*


Профиль
Группа: Участник
Сообщений: 69
Регистрация: 14.4.2010

Репутация: нет
Всего: -3



Цитата(volatile @  12.3.2011,  00:40 Найти цитируемый пост)
Вы передаете длину строки в элементахKEYNAME_LENGTH у вас = 0x100; то есть 256 байт.фактически вы уменьшили его еще на единицу, так как передаете (keyname+1). То есть размер вашего буфера 255 байт.а функция считает что у нее есть 256 wchar_t, то есть 512 байт.

По-моему просто надо добавить в проект:
Код

#undef UNICODE
#undef _UNICODE


Тогда LPTSTR раскроется LPSTR, что и требуется.

Это сообщение отредактировал(а) neokoder - 12.3.2011, 20:02
PM MAIL   Вверх
neutrino
Дата 12.3.2011, 21:10 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Gothic soul
****


Профиль
Группа: Модератор
Сообщений: 3041
Регистрация: 25.3.2002
Где: Верхняя Галилея, Кармиэль

Репутация: нет
Всего: 62



volatile, В принципе вы правы, но поскольку эта функция должна все-го то записать название кнопки, то 256 байт ей за глаза. И правда, передал вместо KEYNAME_LENGTH, (KEYNAME_LENGTH - 1)/2. Не помогло - та же ошибка.



--------------------
The truth comes from within ...

Покойся с миром, Vit 
PM MAIL WWW ICQ Skype GTalk   Вверх
volatile
Дата 13.3.2011, 01:43 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Завсегдатай
Сообщений: 2107
Регистрация: 7.1.2011

Репутация: 13
Всего: 85



Цитата(neutrino @  12.3.2011,  21:10 Найти цитируемый пост)
поскольку эта функция должна все-го то записать название кнопки, то 256 байт ей за глаза

я специально собрал щас небольшой проект.
вот вся программка целиком
Код

int _tmain(int argc, _TCHAR* argv[])
{
      const int KEYNAME_LENGTH = 256;
      _TCHAR keyname [KEYNAME_LENGTH];
      
      for (int i=0; i<256; ++i)
      {
         LONG dwMsg = i<<16;
         int act_length = GetKeyNameText(dwMsg, keyname, KEYNAME_LENGTH);
         if (act_length)
            _tprintf(_T("%3d=%s\n"), i, keyname);
      }
}

выход:
Код

  1=Esc
  2=1
  3=2
  4=3
  5=4
  6=5
  7=6
  8=7
  9=8
 10=9
 11=0
 12=-
 13==
 14=Backspace
 15=Tab
 16=Q
 17=W
 18=E
 19=R
 20=T
 21=Y
 22=U
 23=I
 24=O
 25=P
 26=[
 27=]
 28=Enter
 29=Ctrl
 30=A
 31=S
 32=D
 33=F
 34=G
 35=H
 36=J
 37=K
 38=L
 39=;
 40='
 41=`
 42=Shift
 43=\
 44=Z
 45=X
 46=C
 47=V
 48=B
 49=N
 50=M
 51=,
 52=.
 53=/
 54=Right Shift
 55=Num *
 56=Alt
 57=Space
 58=Caps Lock
 59=F1
 60=F2
 61=F3
 62=F4
 63=F5
 64=F6
 65=F7
 66=F8
 67=F9
 68=F10
 69=Pause
 70=Scroll Lock
 71=Num 7
 72=Num 8
 73=Num 9
 74=Num -
 75=Num 4
 76=Num 5
 77=Num 6
 78=Num +
 79=Num 1
 80=Num 2
 81=Num 3
 82=Num 0
 83=Num Del
 84=Sys Req
 86=\
 87=F11
 88=F12
124=F13
125=F14
126=F15
127=F16
128=F17
129=F18
130=F19
131=F20
132=F21
133=F22
134=F23
135=F24


А вот когда я указываю вместо KEYNAME_LENGTH число 512, то и возникает ошибка 998 
я думаю вы не внимательно скорректировали KEYNAME_LENGTH
ошибка скорей всего, именно здесь!


Это сообщение отредактировал(а) volatile - 13.3.2011, 02:03
PM MAIL   Вверх
volatile
Дата 13.3.2011, 09:35 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Завсегдатай
Сообщений: 2107
Регистрация: 7.1.2011

Репутация: 13
Всего: 85



neutrino, в общем эта функция обращается к всему блоку что ей предоставили. возможно затирает его нулями. Поэтому нужно передавать реальный размер блока.

И 2-е. Вы смешиваете в одной строке char и wchar_t.
Цитата(neutrino @  12.3.2011,  21:10 Найти цитируемый пост)
передал вместо KEYNAME_LENGTH, (KEYNAME_LENGTH - 1)/2. Не помогло - та же ошибка.

этого не достаточно. вы уже записали в строку один чар '[', увеличили указатель,
и передали в функцию нечетный адрес по которому она пишет широкие символы.
В общем так не делают.
Приведите все к одному, либо char, либо wchar_t.

Это сообщение отредактировал(а) volatile - 13.3.2011, 09:38
PM MAIL   Вверх
neutrino
Дата 1.4.2011, 14:51 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Gothic soul
****


Профиль
Группа: Модератор
Сообщений: 3041
Регистрация: 25.3.2002
Где: Верхняя Галилея, Кармиэль

Репутация: нет
Всего: 62



volatile, Спасибо за помощь!

Я поставил в properties проекта Use Multibyte Char set и все заработало.


--------------------
The truth comes from within ...

Покойся с миром, Vit 
PM MAIL WWW ICQ Skype GTalk   Вверх
neutrino
Дата 1.4.2011, 15:45 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Gothic soul
****


Профиль
Группа: Модератор
Сообщений: 3041
Регистрация: 25.3.2002
Где: Верхняя Галилея, Кармиэль

Репутация: нет
Всего: 62



Бугога. Ничего не заработало. Мдя... Ну и нарутили с этими кодировками...
Все время я получаю название какой-то одной клавиши (и уж точно не той, что нажали). Нажимаю Shift - получаю Ctrl. Далее неважно что нажимаю - получаю одно и то же. Да, как только поменял тот property, то хоть что-то получать стал. Сейчас у меня следующее:
Project.Properties.CharacterSet = 'Use Multi-Byte Character Set'

Код

        const int KEYNAME_LENGTH = 0x100;
        wchar_t keyname[KEYNAME_LENGTH]={0};
        keyname[0] = L'[';

        int act_length = GetKeyNameTextW(lParam, keyname+1, KEYNAME_LENGTH-1) + 1;
        DWORD errcode = GetLastError();
        keyname[act_length] = L']';



--------------------
The truth comes from within ...

Покойся с миром, Vit 
PM MAIL WWW ICQ Skype GTalk   Вверх
neutrino
Дата 1.4.2011, 16:02 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Gothic soul
****


Профиль
Группа: Модератор
Сообщений: 3041
Регистрация: 25.3.2002
Где: Верхняя Галилея, Кармиэль

Репутация: нет
Всего: 62



Вот так работает:
Код

        DWORD dwMsg = 1;
        dwMsg += pKeyBoard->scanCode << 16;
        dwMsg += pKeyBoard->flags << 24;

        const int KEYNAME_LENGTH = 20;
        wchar_t keyname[KEYNAME_LENGTH]={0};
        keyname[0] = L'[';

        int act_length = GetKeyNameTextW(dwMsg, keyname+1, KEYNAME_LENGTH-1) + 1;
//        DWORD errcode = GetLastError();
        keyname[act_length] = L']';

Только не учитывает шифт/капс-лок


--------------------
The truth comes from within ...

Покойся с миром, Vit 
PM MAIL WWW ICQ Skype GTalk   Вверх
volatile
Дата 1.4.2011, 23:22 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Завсегдатай
Сообщений: 2107
Регистрация: 7.1.2011

Репутация: 13
Всего: 85



Цитата(neutrino @  1.4.2011,  14:51 Найти цитируемый пост)
Я поставил в properties проекта Use Multibyte

neutrino,  Ну раз вы решили использовать не юникодный проект, то надо быть последовательным:
Код

dwMsg += pKeyBoard->scanCode << 16;
dwMsg += pKeyBoard->flags << 24;

const int KEYNAME_LENGTH = 20;
wchar_t keyname[KEYNAME_LENGTH]={0}; // зачем wchar_t ? поставьте char
keyname[0] = L'['; // . Зачем здесь L ? уберите
int act_length = GetKeyNameTextW(dwMsg, keyname+1, KEYNAME_LENGTH-1) + 1; 
   // Зачем W вконце, это явный вызов юникодной функции. нужно просто GetKeyNameText()

keyname[act_length] = L']';[/quote]// . Зачем L ? 

PM MAIL   Вверх
  
Ответ в темуСоздание новой темы Создание опроса
Правила форума "C/C++: Системное программирование и WinAPI"
Fixin
GremlinProg
xvr
feodorv
  • Большое количество информации и примеров с использованием функций WinAPI можно найти в MSDN
  • Описание сообщений, уведомлений и примеров с использованием компонент WinAPI (BUTTON, EDIT, STATIC, и т.п.), можно найти в MSDN Control Library
  • Непосредственно, перед созданием новой темы, проверьте заголовок и удостоверьтесь, что он отражает суть обсуждения.
  • После заполнения поля "Название темы", обратите внимание на наличие и содержание панели "А здесь смотрели?", возможно Ваш вопрос уже был решен.
  • Приводите часть кода, в которой предположительно находится проблема или ошибка.
  • Если указываете код, пользуйтесь тегами [code][/code], или их кнопочными аналогами.
  • Если вопрос решен, воспользуйтесь соответствующей ссылкой, расположенной напротив названия темы.
  • Один топик - один вопрос!
  • Перед тем как создать тему - прочтите это .

На данный раздел распространяются Правила форума и Правила раздела С++:Общие вопросы .


Если Вам понравилась атмосфера форума, заходите к нам чаще! С уважением, Chipset, Step, Fixin, GremlinProg, xvr. feodorv.

 
1 Пользователей читают эту тему (1 Гостей и 0 Скрытых Пользователей)
0 Пользователей:
« Предыдущая тема | C/C++: Системное программирование и WinAPI | Следующая тема »


 




[ Время генерации скрипта: 0.0904 ]   [ Использовано запросов: 21 ]   [ GZIP включён ]


Реклама на сайте     Информационное спонсорство

 
По вопросам размещения рекламы пишите на vladimir(sobaka)vingrad.ru
Отказ от ответственности     Powered by Invision Power Board(R) 1.3 © 2003  IPS, Inc.