Форум программистов «Весельчак У»
  *
Добро пожаловать, Гость. Пожалуйста, войдите или зарегистрируйтесь.
Вам не пришло письмо с кодом активации?

  • Рекомендуем проверить настройки временной зоны в вашем профиле (страница "Внешний вид форума", пункт "Часовой пояс:").
  • У нас больше нет рассылок. Если вам приходят письма от наших бывших рассылок mail.ru и subscribe.ru, то знайте, что это не мы рассылаем.
   Начало  
Наши сайты
Помощь Поиск Календарь Почта Войти Регистрация  
 
Страниц: [1]   Вниз
  Печать  
Автор Тема: Отловить нажатие кнопки в чужой форме  (Прочитано 23611 раз)
0 Пользователей и 3 Гостей смотрят эту тему.
Tenzor
Интересующийся

ru
Offline Offline

« : 19-07-2012 17:32 » 

Здравствуйте. Такой вопрос: есть стороннее приложение, нужно отловить нажатие на эту кнопку. Известен хэндл окна и кнопки. Смотрел хуки, но там отслеживается нажатие по координатам, а вот как сделать так, чтобы отлавливалось нажатие именно этой кнопки???
Записан
Dimka
Деятель
Команда клуба

ru
Offline Offline
Пол: Мужской

« Ответ #1 : 19-07-2012 18:05 » 

Tenzor, кнопка - это тоже окно, поэтому у неё есть handle.
Записан

Программировать - значит понимать (К. Нюгард)
Невывернутое лучше, чем вправленное (М. Аврелий)
Многие готовы скорее умереть, чем подумать (Б. Рассел)
Tenzor
Интересующийся

ru
Offline Offline

« Ответ #2 : 19-07-2012 18:55 » 

У меня есть ее хэндл, вопрос как воспользоваться этим - как получить нажатие? С помощью чего? А то обидно вся программа готова и упирается только в этот момент)))
Записан
zubr
Гость
« Ответ #3 : 19-07-2012 19:01 » 

Для отлавливания нажатия кнопки в чужом приложении хендла окна и кнопки недостаточно. Тут надо делать сабклассинг (подмена процедуры окна). Но и тут не все так просто, потому как сабклассинг можно сделать только в контексте процесса этого чужого окна, а для этого надо внедряться в адрессное пространство чужого процесса, а для этого придется ставить глобальный хук.
Правда есть более простой вариант - поставить неглобальный хук WH_MOUSE_LL, а там по координатам идентифицировать кнопку.
Записан
Tenzor
Интересующийся

ru
Offline Offline

« Ответ #4 : 19-07-2012 19:09 » 

Я знаю, что через хуки, смотрел примеры, там все по координатам. Просто окно каждый будет  таскать как ему хочется, именно поэтому нужна жесткая привязка.
Записан
zubr
Гость
« Ответ #5 : 19-07-2012 19:36 » 

Так в чем проблема? В системе в момент нажатия кнопки может быть только одно активное окно.
В процедуре обработки хука делаешь GetForegroundWindow - тем самым определяешь окно с которым работает юзер. Просто сверяешь хендл полученного окна с известным тебе.

Ну а если не хочешь юзать оконные функции - применяй сабклассинг. А хук ставь только для внедрения в чужой процесс, то есть код сабклассинга у тебя будет в дллке.
« Последнее редактирование: 19-07-2012 19:40 от zubr » Записан
Tenzor
Интересующийся

ru
Offline Offline

« Ответ #6 : 21-07-2012 18:11 » 

Потихоньку постигаю, ибо в первый раз. В dll есть  переменная
extern "C" HWND fHandle=0;
получаем хэндл окна
В def файле пишу
EXPORTS fHandle @1 DATA

Как получить эту переменную в VB?
Как получить функцию знаю, а вот переменую не нашел)
Записан
zubr
Гость
« Ответ #7 : 21-07-2012 19:38 » new

1. dll в качестве экспорта умеет передавать только функции, а никак не переменные. Создай функцию, которая будет возвращать значение переменной и экспортируй ее.
2. Боюсь что для данной задачи передавать хендл окна через глобальную переменную - бессмысленно. Потому что длл будет вызываться в контексте другого процесса. Тут надо задействовать расшаренную память.
Записан
Tenzor
Интересующийся

ru
Offline Offline

« Ответ #8 : 21-07-2012 20:04 » 

1. GetProcAddress?
2. MapFiles и иже с ними?
Записан
zubr
Гость
« Ответ #9 : 22-07-2012 04:30 » 

1.
Код:
extern "C" RETTYPE __stdcall HWND getHandle()
{
      return fHandle;
}
2. Да
Записан
Tenzor
Интересующийся

ru
Offline Offline

« Ответ #10 : 25-07-2012 13:09 » 

В общем, пока в меру своих знаний))
DLL
Код: (C++)
// HookDll.cpp : Defines the entry point for the DLL application.
//

#include "stdafx.h"
#include "HookDll.h"
#include<WinUser.h>
#include<WINDEF.h>
#include<Windows.h>
#pragma comment(lib,"User32.lib")
HHOOK hHook;
HANDLE hIns;
HANDLE hPipe;
HWND hWnd;
DWORD NumWrite;
MOUSEHOOKSTRUCT *hMouse;
LRESULT MouseProc(int nCode, WPARAM wParam, LPARAM lParam);
BOOL APIENTRY DllMain( HANDLE hModule,
                       DWORD  ul_reason_for_call,
                       LPVOID lpReserved
                                         )
{
    hIns=hModule;
    switch (ul_reason_for_call)
        {
                case DLL_PROCESS_ATTACH:
                        hHook = SetWindowsHookEx(WH_MOUSE, (HOOKPROC)MouseProc, (HINSTANCE)hIns, 0);

                break;
                case DLL_THREAD_ATTACH:
                case DLL_THREAD_DETACH:
                case DLL_PROCESS_DETACH:
                        UnhookWindowsHookEx(hHook);
                        CloseHandle(hPipe);
                        break;
    }
    return TRUE;
}
//Отправляем данные
int ReciveData(){
        hPipe = CreateFile("\\\\.\\pipe\\MFPl", GENERIC_WRITE,  FILE_SHARE_WRITE, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
        if(hPipe==INVALID_HANDLE_VALUE){
                return 0;
        }
        if(!WriteFile(hPipe,hWnd,sizeof(HWND),&NumWrite,NULL))return 0;
        return 1;
}
LRESULT MouseProc(int nCode, WPARAM wParam, LPARAM lParam){
        hMouse=(MOUSEHOOKSTRUCT*)lParam;
        if(nCode<0)CallNextHookEx(hHook,nCode,wParam,lParam);
        else{
//Отлавливаем нажатие              
                    switch(nCode){
                        case HC_ACTION:
                                switch(wParam){
                                        case WM_LBUTTONDOWN:
                                                hWnd=hMouse->hwnd;
                                                break;
                                        case WM_NCLBUTTONDOWN:
                                                hWnd=hMouse->hwnd;
                                                break;
                                        }
                                        break;
                        case HC_NOREMOVE:
                                switch(wParam){
                                        case WM_LBUTTONDOWN:
                                                hWnd=hMouse->hwnd;
                                                break;
                                        case WM_NCLBUTTONDOWN:
                                                hWnd=hMouse->hwnd;
                                                break;
                                        }
                                break;
                        }
                }
             return CallNextHookEx(hHook,nCode,wParam,lParam);
}

Написал програмку на С++ (позже она будет на VB) для теста

Код: (C++)
#include "stdafx.h"
#include<WinUser.h>
#include<iostream>
#include<Windows.h>

int main(int argc, char* argv[])
{      
        HMODULE hDLL;
        HANDLE hPip;
        hDLL=LoadLibrary("C:\\HookDLL.dll");
        if(!hDLL){
                std::cout<<"Error Load: "<<GetLastError()<<endl;
                return 0;
        }

        hPip=CreateNamedPipe("\\\\.\\pipe\\MFPl", PIPE_ACCESS_INBOUND, PIPE_TYPE_MESSAGE|PIPE_WAIT,1,0,0,INFINITE,NULL);
        if (hPip==INVALID_HANDLE_VALUE){
                std::cout<<"Error pipe: "<<GetLastError()<<endl;
                FreeLibrary(hDLL);
                return 0;
        }
\\Останавливается тут
        if(!ConnectNamedPipe(hPip,NULL)){
                std::cout<<"Error connect: "<<GetLastError()<<endl;
                CloseHandle(hPip);
                FreeLibrary(hDLL);
                return 0;
        }

        HWND bufhWnd;
        DWORD buf;
        if(!ReadFile(hPip, &bufhWnd,sizeof(bufhWnd),&buf,NULL)){
                std::cout<<"Error read: "<<GetLastError()<<endl;
                            CloseHandle(hPip);
                FreeLibrary(hDLL);
                return 0;
        }
//Тут еще дисконект д.б.
        std::cout<<bufhWnd<<endl;
        CloseHandle(hPip);
        FreeLibrary(hDLL);
        return 0;
}

Предсказуемо зависает на ожидании. Есть подозрении, что до CreateFile в dll не доходит вобще. делал локальный хук на мышь, номера команд выдавались именно в nCode, а не в wParam. в общем это..помогите))

Она же на VB и с тем же результатом
Код: (Visual Basic)
''Форма
Private Sub Form_Load()
    hDLL = LoadLibrary("C:\HookDLL.dll")
    GetHandleF
End Sub

Private Sub Form_Unload(Cancel As Integer)
    If hDLL <> 0 Then FreeLibrary (hDLL)
End Sub
' Модуль
Public Type SECURITY_ATTRIBUTES
        nLength As Long
        lpSecurityDescriptor As Long
        bInheritHandle As Long
End Type
Public Const INFINITE = &HFFFF
Public Const PIPE_ACCESS_INBOUND = &H1
Public Const PIPE_TYPE_MESSAGE = &H4
Public Const PIPE_WAIT = &H0
Public Declare Function LoadLibrary Lib "kernel32" Alias "LoadLibraryA" (ByVal lpLibFileName As String) As Long
Public Declare Function FreeLibrary Lib "kernel32" (ByVal hLibModule As Long) As Long
Public Declare Function CreateNamedPipe Lib "kernel32" Alias "CreateNamedPipeA" (ByVal lpName As String, ByVal dwOpenMode As Long, ByVal dwPipeMode As Long, ByVal nMaxInstances As Long, ByVal nOutBufferSize As Long, ByVal nInBufferSize As Long, ByVal nDefaultTimeOut As Long, lpSecurityAttributes As SECURITY_ATTRIBUTES) As Long
Public Declare Function CreateFile Lib "kernel32" Alias "CreateFileA" (ByVal lpFileName As String, ByVal dwDesiredAccess As Long, ByVal dwShareMode As Long, lpSecurityAttributes As SECURITY_ATTRIBUTES, ByVal dwCreationDisposition As Long, ByVal dwFlagsAndAttributes As Long, ByVal hTemplateFile As Long) As Long

Public Declare Function ReadFil Lib "kernel32" (ByVal hFile As Long, lpBuffer As Any, ByVal nNumberOfBytesToRead As Long, lpNumberOfBytesRead As Long, lpOverlapped As Long) As Long
Public Declare Function ConnectNamedPipe Lib "kernel32" (ByVal hNamedPipe As Long, lpOverlapped As Long) As Long
Public Declare Function WaitForSingleObject Lib "kernel32" (ByVal hHandle As Long, ByVal dwMilliseconds As Long) As Long
Public Declare Function CloseHandle Lib "kernel32" (ByVal hObject As Long) As Long
Public Declare Sub CopyMemory Lib "kernel32" Alias "RtlMoveMemory" (Destination As Any, Source As Any, ByVal Length As Long)
Public hDLL As Long, hMap As Long, lBuf As Long, NumRead As Long
Public res As Long
Public Function GetHandleF()
    Dim sa As SECURITY_ATTRIBUTES
    sa.nLength = Len(sa)
    Dim hMap As Long, hwndHandle As Long, hh As Long
    Dim str As String
    str = "HandleMap"
    hMap = CreateNamedPipe("\\.\pipe\MPLp", PIPE_ACCESS_INBOUND, PIPE_TYPE_MESSAGE Or PIPE_WAIT, 1, 0, 0, INFINITE, sa)
      If hMap =-1 Then Exit Function
    res = ConnectNamedPipe(hMap, ByVal 0)
    If res = 0 Then Exit Function
    res = ReadFil(hMap, lBuf, Len(lBuf), numred, 0)
   
End Function
« Последнее редактирование: 25-07-2012 13:42 от Tenzor » Записан
zubr
Гость
« Ответ #11 : 25-07-2012 14:17 » 

1. MouseProc - должен быть CALLBACK то есть stdcall
2. А где у тебя вызывается ReciveData. Пока не будет вызвана ReciveData прга будет стоять на пайпе.
3. Использование пайпов для обмена данными между процессами - не очень удачное решение. Первое приложение, которое прочитает пайп, очистит данные, а тебе данные надо передавать во множество приложений. Чем плох именованный CreateFileMapping?
4. Ты выбрал гиморрное решение. Я тебе несколькими постами выше предложил на порядок проще решение - через локальный хук WH_MOUSE_LL.
Там все решение из нескольких строчек кода и без всяких длл.
Записан
Tenzor
Интересующийся

ru
Offline Offline

« Ответ #12 : 25-07-2012 19:56 » 

Код: (C++)
// Hook_LL.cpp : Defines the entry point for the console application.
//

#include "stdafx.h"
#include <Windows.h>
#include <iostream>
using namespace std;
HHOOK hHook;
 
MSLLHOOKSTRUCT *MouseLL;
LRESULT CALLBACK MouseProcLL(int nCode,WPARAM wParam, LPARAM lParam){
        MouseLL=(MSLLHOOKSTRUCT*)lParam;
        if(nCode<0)CallNextHookEx(hHook,nCode,wParam,lParam);
        switch (wParam){
                case 513:
// Здесь, что-то поможет мне определить хэндл элемента на окне чужого приложения
                        break;
                case 514:
//Получить хэндл и проверить совпадает ли он с тем что был при нажатии и если да, то значит был клик
                        break;
        }
        return CallNextHookEx(hHook,nCode,wParam,lParam);
}
bool GetHook(){
        hHook=SetWindowsHookEx(WH_MOUSE_LL,(HOOKPROC)MouseProcLL,GetModuleHandle(NULL),NULL);
        if (!hHook)     return FALSE;
        return TRUE;
}
void UnHook(){
        if(hHook)UnhookWindowsHookEx(hHook);
}

int _tmain(int argc, _TCHAR* argv[])
{
        if(!GetHook())return 0;
        MSG msg;
                while(GetMessageA(&msg,NULL,0,0)){
                        TranslateMessage(&msg);
                        DispatchMessage(&msg);
                }
        UnHook();
        return 0;
}

Так? Весь вопрос в том как получить хэндл контрола на котором произошло нажатие или отпускание кнопки мыши.
Записан
zubr
Гость
« Ответ #13 : 25-07-2012 21:43 » 

Код:
MSLLHOOKSTRUCT *MouseLL;
LRESULT CALLBACK MouseProcLL(int nCode,WPARAM wParam, LPARAM lParam){
        MouseLL=(MSLLHOOKSTRUCT*)lParam;
        if(nCode<0)return CallNextHookEx(hHook,nCode,wParam,lParam);
        switch (wParam){
                case 513:
// Здесь, что-то поможет мне определить хэндл элемента на окне чужого приложения
                        break;
                case 514:
                     if(GetForegroundWindow() == WindowHandle)
                     {
                             POINT pt = MouseLL->pt;
                             ScreenToClient(WindowHandle, &pt);
                             if(ChildWindowFromPoint(WindowHandle, pt) == ButtonHandle)
                             //кнопка нажата
                     }
                        break;
        }
        return CallNextHookEx(hHook,nCode,wParam,lParam);
}
Записан
Tenzor
Интересующийся

ru
Offline Offline

« Ответ #14 : 25-07-2012 23:18 » 

Спасибо огромное Буду дальше ковырять)))
Записан
Страниц: [1]   Вверх
  Печать  
 

Powered by SMF 1.1.21 | SMF © 2015, Simple Machines