Версия для печати темы

Нажмите сюда для просмотра этой темы в обычном формате

UoKit.com Форумы _ UO Pilot _ ffi pid по hwnd

Автор: DarkMaster 17.2.2024, 16:59

Господа, а как дернуть pid по hwnd?
Я так люблю виндовые переопределения типов... Задолбался уже...
Во 1 GetWindowThreadProcessId я же правильно понимаю, что это НЕ оно? Он же id потока вернет?
GetProcessHandleFromHwnd требует чтобы ему передали HWND__. Что есть это нашлась только одна страничка с гордой структурой из одного инта. Как еще через ffi воссоздать не понимаю. Объявляю define, делаю ffi.new('HWND__[1]' говорит declaration specifier expected near 'HWND__'...

Автор: DarkMaster 17.2.2024, 17:36

хэндл естественно имеет type number луашный. workwindow()

Автор: Cockney 17.2.2024, 21:09

Не, ну чего ты как маленький...

https://learn.microsoft.com/en-us/windows/win32/winprog/windows-data-types


Берешь свой HWND и распутываешь до С-совместимого типа. А вообще все должно прекрасно кастится к интам/войдам, Да там в целом вариантов то других и нет

Цитата
Во 1 GetWindowThreadProcessId я же правильно понимаю, что это НЕ оно? Он же id потока вернет?


Оно, из доки:

Цитата
[out, optional] lpdwProcessId

Тип: LPDWORD

Указатель на переменную, получающую идентификатор процесса. Если этот параметр не имеет значение NULL, GetWindowThreadProcessId копирует идентификатор процесса в переменную ; В противном случае — нет. Если функция завершается сбоем, значение переменной не изменяется.


И вообще на будущее - всякие ffi работают только с Си типами. Изначально кормить их чем-то не из https://en.wikipedia.org/wiki/C_data_types не имеет смысла как правило. Сразу ищи как кастовать свой тип к сишному

Автор: DarkMaster 18.2.2024, 5:42

Ну так я был там. В том и проблема, что HWND__ там нет. О нем вообще описание от майкрософта "сами напрямую использовать не можете" и на этом все. GetProcessHandleFromHwnd требует его. По крайней мере луа орет на него. Попытки объявить эту структуру ни к чему не привели. В доках требуется HWND, а не HWND__.

Код

ffi.cdef([[
    typedef void * PVOID;
    typedef PVOID  HANDLE;
    typedef HANDLE HWND;

    typedef unsigned long DWORD;
    HANDLE GetProcessHandleFromHwnd(HWND hwnd);
    DWORD GetProcessId(HANDLE Process);
]])
local ole = ffi.load('Oleacc.dll')
--local user, kernel = ffi.load('User32'), ffi.load('Kernel32')

local PROCESS_VM_READ = 0x0010
function readDword(address)
    if workwindow() == 0 then log('No Workwindow') return -1 end

    local PID, pointer_int, hwnd = ffi.new('unsigned long[1]'), ffi.new('int[1]'), ffi.new('HWND[1]')
    local puint = ffi.new('unsigned int[1]')

    puint[1] = workwindow()
    hwnd = ffi.cast("HWND", puint)
    log(tostring(hwnd))

    PID[1] = ole.GetProcessHandleFromHwnd(hwnd[1])

в таком варианте орет cannot convert 'void *' to 'unsigned int' при попытке дернуть хэндл процесса (я в курсе, что там не pid).

Автор: cirus 18.2.2024, 11:13

Код
--lua
local ffi = require("ffi")
local user = ffi.load('User32')
log 'clear' log 'mode compact'

ffi.cdef[[
    typedef unsigned long   DWORD;
    typedef DWORD           *LPDWORD;
    struct HWND__ { int unused; }; typedef struct HWND__ *HWND;
    DWORD GetWindowThreadProcessId( HWND    hWnd, LPDWORD lpdwProcessId );
]]

local pid = ffi.new('DWORD[1]')
user.GetWindowThreadProcessId(ffi.cast('HWND', workwindow()), pid)
log(tonumber(pid[0]))

Или так:
Код
--lua
local ffi = require("ffi")
local user = ffi.load('User32')
log 'clear' log 'mode compact'

ffi.cdef[[
    typedef unsigned long   DWORD;
    typedef DWORD           *LPDWORD;
    DWORD GetWindowThreadProcessId( unsigned long    hWnd, LPDWORD lpdwProcessId );
]]

local pid = ffi.new('DWORD[1]')
user.GetWindowThreadProcessId(workwindow(), pid)
log(tonumber(pid[0]))

Автор: DarkMaster 18.2.2024, 12:08

GetWindowThreadProcessId вернет разве id процесса? Он же потока возвращает. В этом то и суть проблемы. C GetWindowThreadProcessId работало и у меня =)

Автор: Cockney 18.2.2024, 13:27

Цитата(DarkMaster @ 18.2.2024, 5:42) *

Ну так я был там. В том и проблема, что HWND__ там нет. О нем вообще описание от майкрософта "сами напрямую использовать не можете" и на этом все. GetProcessHandleFromHwnd требует его. По крайней мере луа орет на него. Попытки объявить эту структуру ни к чему не привели. В доках требуется HWND, а не HWND__.
Код

ffi.cdef([[
    typedef void * PVOID;
    typedef PVOID  HANDLE;
    typedef HANDLE HWND;

    typedef unsigned long DWORD;
    HANDLE GetProcessHandleFromHwnd(HWND hwnd);
    DWORD GetProcessId(HANDLE Process);
]])
local ole = ffi.load('Oleacc.dll')
--local user, kernel = ffi.load('User32'), ffi.load('Kernel32')

local PROCESS_VM_READ = 0x0010
function readDword(address)
    if workwindow() == 0 then log('No Workwindow') return -1 end

    local PID, pointer_int, hwnd = ffi.new('unsigned long[1]'), ffi.new('int[1]'), ffi.new('HWND[1]')
    local puint = ffi.new('unsigned int[1]')

    puint[1] = workwindow()
    hwnd = ffi.cast("HWND", puint)
    log(tostring(hwnd))

    PID[1] = ole.GetProcessHandleFromHwnd(hwnd[1])

в таком варианте орет cannot convert 'void *' to 'unsigned int' при попытке дернуть хэндл процесса (я в курсе, что там не pid).


А откуда ты взял HWND___ ? Правильно тебе говорят что это кишки какие то винды, а для обычного вин апи требуется hwnd. Мне кажется что ты смотришь не на ту функцию в документации, или не на ту документацию


https://learn.microsoft.com/ru-ru/windows/win32/api/winuser/nf-winuser-getwindowthreadprocessid

Автор: DarkMaster 18.2.2024, 13:38

Цитата
А откуда ты взял HWND___ ?

Это мне луа выкидывает ошибку что не может к нему прикастовать. Еще раз. Мне НЕ нужен хэндл ПОТОКА нужен хендл ПРОЦЕССА. Хэндл потока дергается исправно.

Автор: cirus 18.2.2024, 13:50

GetWindowThreadProcessId возвращает ид потока, в переменную ид процесса.

Автор: DarkMaster 18.2.2024, 14:29

мля а вот теперь стыдно стало =)
тем не менее GetProcessHandleFromHwnd почему не шуршит то? прям зацепило...

Автор: cirus 18.2.2024, 16:37

Цитата
ole.GetProcessHandleFromHwnd(hwnd[1])

Цитата
тем не менее GetProcessHandleFromHwnd почему не шуршит то?

Индексация начинается с 0.

Автор: DarkMaster 18.2.2024, 18:41

Код

ffi.cdef([[
    typedef void * PVOID;
    typedef PVOID  HANDLE;
    typedef HANDLE HWND;

    typedef unsigned long DWORD;
    typedef DWORD * LPDWORD;

    HANDLE GetProcessHandleFromHwnd(HWND hwnd);
    DWORD GetProcessId(HANDLE Process);

    int OpenProcess(int dwDesiredAccess, bool bInheritHandle, int dwProcessId);
    int GetWindowThreadProcessId(int hWnd, int *lpdwProcessId);
    bool CloseHandle(int hObject);
    bool ReadProcessMemory(int hProcess, int lpBaseAddress, void *lpBuffer, int nSize, int *lpNumberOfBytesRead);
    int GetModuleHandleA(const char *lpModuleName);
]])
local ole = ffi.load('Oleacc.dll')
local user, kernel = ffi.load('User32'), ffi.load('Kernel32')

local PROCESS_VM_READ = 0x0010
function readDword(address)
    if workwindow() == 0 then log('No Workwindow') return -1 end

    local PID, pointer_int, hwnd = ffi.new('unsigned long[1]'), ffi.new('int[1]'), ffi.new('unsigned int[1]')
    local puint = ffi.new('unsigned int[1]')

    puint[0] = workwindow()
    hwnd = ffi.cast("HWND", puint)
--    log(tostring(hwnd))


    local pvoid = ole.GetProcessHandleFromHwnd(hwnd)
    log(tostring(pvoid))
    local r = ffi.cast("unsigned int * ", pvoid)
    log(tostring(r))
    log(tostring(r[0]))
    log(tonumber(r[0]))
    log"wtf"

Возваращет указатель на NULL, при чтении r[0] естественно краш(только скрипта).
Ну не сишник я. Не судите строго. У меня и си давняя история, но не очень счастливая. Как бы я ни уважал его - душа не лежит(

Автор: Cockney 18.2.2024, 18:42

А почему вообще оле используется ? Зачем он тут

Автор: cirus 18.2.2024, 19:17

Проще так:

Код
--lua
local ffi = require("ffi")
log 'clear' log 'mode compact'

ffi.cdef([[
    unsigned int GetProcessHandleFromHwnd(unsigned int hwnd);
]])
local ole = ffi.load('Oleacc.dll')

function readDword()
    if workwindow() == 0 then log('No Workwindow') return -1 end
    return ole.GetProcessHandleFromHwnd(workwindow())
end

log (readDword())

Автор: DarkMaster 18.2.2024, 19:34

Цитата
А почему вообще оле используется ? Зачем он тут

потому что нужна либа с этой функцией ole ее содержит. Допускаю, что она к нему прилинкована от другой либы.
Цитата
--lua
local ffi = require("ffi")
log 'clear' log 'mode compact'

ffi.cdef([[
unsigned int GetProcessHandleFromHwnd(unsigned int hwnd);
]])
local ole = ffi.load('Oleacc.dll')

function readDword()
if workwindow() == 0 then log('No Workwindow') return -1 end
return ole.GetProcessHandleFromHwnd(workwindow())
end

log (readDword())

вроде как синтаксис предполагает передачу указателей, а не значений.
HANDLE WINAPI GetProcessHandleFromHwnd(
_In_ HWND hwnd
);
ну и возврат тоже указателя. Лог выводит ерунду, я так подозреваю указатель.

Автор: Cockney 18.2.2024, 21:35

Цитата
ну и возврат тоже указателя. Лог выводит ерунду, я так подозреваю указатель.


хендл и есть по сути указатель. если бы функция не работала, то выводился бы 0, null, nil или что у вас там в луа

Автор: DarkMaster 19.2.2024, 3:58

Цитата
хендл и есть по сути указатель.

при попытке засунуть туда указатель ловлю маты на невозможность прикастовать к HWND__. Собственно с чего все и начиналось.

Автор: Cockney 19.2.2024, 9:00

Куда туда ? Зачем что то засовывать, если cirus дал конечный код. Если у тебя при его использовании выводится в лог не 0, то все работает.

Автор: DarkMaster 19.2.2024, 9:20

Цитата
Куда туда ?

в GetProcessHandleFromHwnd
Цитата
Зачем что то засовывать, если cirus дал конечный код.

Не рабочий.
Цитата
Если у тебя при его использовании выводится в лог не 0, то все работает.

Если функция что-то возвращает, то это не значит, что она работает корректно.

Полученное значение слишком мало, чтобы быть указателем ~800 и увеличивается при каждом запуске, что характерно для создания новых указателей. При попытке прочитать данный указатель получаем тихий краш скрипта, что явно напоминает попытку чтения неразмечнной области памяти.

Так же если функция ожидает получить на входе _указатель_ и планирует вренуть на выходе _указатель_ и нет каких либо упоминаний оперегрузке функции, то мне действительно кажется это не правильным пытаться туда пихать данные напрямую. В моем понимании в таком виде это не может работать. При передаче указателя я получаю ошибку невозможности прикастовать к HWND__.

Автор: DarkMaster 19.2.2024, 10:52

user.GetWindowThreadProcessId(ffi.cast('HWND', workwindow()), pid)

Работает на пилоте, на блокноте не хочет. На Notepad++ работает, если привязать к заголовку, но не работает, если привязать к рабочей области...

Автор: cirus 19.2.2024, 11:30

Не проще посмотреть пример чтения памяти?
https://forum.uokit.com/index.php?s=&showtopic=70333&view=findpost&p=437715

Цитата
работает на пилоте, на блокноте не хочет.

Открой Cheat Engine 32 бита и попробуй что-нибудь найти в 64 битном блокноте.

Автор: Cockney 19.2.2024, 11:31

Цитата

Если функция что-то возвращает, то это не значит, что она работает корректно


Крамольную вещь напишу - мне кажется лучше всего полагаться на поведение, описанное в документации. Если там написано, что все что не 0 это ок, значит так оно и есть.

Цитата
Полученное значение слишком мало, чтобы быть указателем ~800 и увеличивается при каждом запуске, что характерно для создания новых указателей


Хендл не обязан быть указателем в том понимании которое ты закладываешь. Он просто как тип совместим с ним. Например, getmodulehandle вернет указатель, из которого можно читать, а все остальные функции могут и не дать таких гарантий. И инкремент это не признак указателя, это простейший счётчик дескрипторов, чем хендл и является

Автор: DarkMaster 19.2.2024, 11:58

Цитата
Не проще посмотреть пример чтения памяти?

Гут ссылка. Тем не менее есть вопрос =)
ты объявляешь:
bool ReadProcessMemory(int hProcess, int lpBaseAddress, void *lpBuffer, int nSize, int *lpNumberOfBytesRead)
при том что
BOOL ReadProcessMemory(
[in] HANDLE hProcess,
[in] LPCVOID lpBaseAddress,
[out] LPVOID lpBuffer,
[in] SIZE_T nSize,
[out] SIZE_T *lpNumberOfBytesRead
);

Т.е. вместо указателей опять объявлены сами данные. Как? Почему? Тоже самое в в GetProcessHandleFromHwnd аналогично. При этом, если закидывать указатели, то не работает, а с данными шуршит. В чем прикол? У меня походу какое-то глобальное непонимание манов =\

Автор: DarkMaster 19.2.2024, 12:24

Цитата
Крамольную вещь напишу - мне кажется лучше всего полагаться на поведение, описанное в документации.

Так в том и вопрос. В документации на входе и выходе другие типы данных... Я пытаюсь это понять и прошу объяснить.

Автор: cirus 19.2.2024, 14:27

Цитата
struct HWND__ { int unused; }; typedef struct HWND__ *HWND;
struct HBITMAP__ { int unused; }; typedef struct HBITMAP__ *HBITMAP;
struct HBRUSH__ { int unused; }; typedef struct HBRUSH__ *HBRUSH;

Это всё одно и тоже, по сути int. Нет смысла играться с приведением к нужному типу.

Автор: Cockney 19.2.2024, 19:20

Цитата(DarkMaster @ 19.2.2024, 12:24) *

Так в том и вопрос. В документации на входе и выходе другие типы данных... Я пытаюсь это понять и прошу объяснить.



Я искренне не понимаю в чем проблема. Покажи хоть ссылку на вход/выход свой, ибо то что я скидываю - там должно быть все понятно.

Автор: DarkMaster 19.2.2024, 19:42

Банально взять тот же ReadProcessMemory
по майкрософту он
BOOL ReadProcessMemory(
[in] HANDLE hProcess,
[in] LPCVOID lpBaseAddress,
[out] LPVOID lpBuffer,
[in] SIZE_T nSize,
[out] SIZE_T *lpNumberOfBytesRead
);
HANDLE это цепочка
typedef void * PVOID;
typedef PVOID HANDLE;
Т.е. по сути у нас должен отправиться указатель на данные. Ну т.е. типа принимающая функция ее должна разыменовать и работать с данными. cirus передает не указатель на данные, а непосредственно int с данными:
bool ReadProcessMemory(int hProcess, int lpBaseAddress, void *lpBuffer, int nSize, int
При этом указатель не пашет, а инт пашет. Учитывая сказанное тобой выше про то, что хэндл это не совсем указатель единственное, что мне приходит в голову, что есть некоторый лист хэндлов, а тип данных тут от балды и в целевой функции нет разыменовывания и данные используются напрямую (типа индекса в листе). Но зачем тогда городить указатели, а не объявить изначально хэндл интом я вообще не понимаю. Указатель должен указывать на адрес, а он(когда там хэндл) указывает на не аллоцированную область.

Вся цепочка проблем с которыми я столкнулся по сути одинаковая в каждой функции. Я хэндл воспринимал, как указатель на данные (а по typedef так и есть), а там сами данные...

Автор: Cockney 19.2.2024, 20:16

Ну давай попробуем по порядку:

1) Любой указатель можно представить как int, т.к. по сути указатель и есть число, обозначающее номер ячейки памяти

2) Функция принимает:

- хендл
- базовый адрес откуда читаем
- выходной буффер куда пишем
- указатель на переменную в которую запишется кол-во считанных байт

Т,е. даже из самой сигнатуры становится понятно, что чтение будет из LPCVOID lpBaseAddress и хендл здесь является тем чем и должен - просто дескриптором процесса, в котором аллоцирован блок памяти, доступный по LPCVOID lpBaseAddress (может быть и смещенным).

Откуда у тебя убеждение что хендл == указатель на данные я не понимаю. То что он тайпдефнут как void* или еще что-то не делает его НЕ int'ом. Это все то же число которое можно представить и как int и как void* и как char*. Конкретное его значение интерпретируется в кишках системы везде по разному - где-то это реально поинтер на данные, где-то индекс в буффере ядра, о чем и пишут где-то мелкомягкие. пользователю достаточно этот хендл гонять из функции в функцию и не пытаться его разыменовать/прочитать и т.д.

Автор: DarkMaster 19.2.2024, 20:21

Цитата

Откуда у тебя убеждение что хендл == указатель на данные я не понимаю.

ну типа звездочка = указатель, если совсем по дубовому. Ну а указатель = адрес в памяти. Такая логика была.

Автор: Cockney 19.2.2024, 20:34

Использование void* не в качестве указателя обусловлено необходимостью поддерживать родную для системы битность. Ну т.е. если написать int, то не факт что в скомпилированном приложении он будет 32(64) бита занимать, а void* всегда либо 32 либо 64 в зависимости под какую битность собираешь. Но это вроде даже в Си уже улучшили, просто мелкомягкие не обновили доки + хедеры.

Собственно HANDLE так вот и прячет детали реализации от юзера апи

Автор: Aqualon 20.2.2024, 2:15

Да, возвращает GetWindowThreadProcessId действительно thread id, но там есть out параметр для пида.
Скопипасчу пример кода из адаптера для винапи который я сделал.

Код

local WinUser = ffi.load('User32')
ffi.cdef[[
   int __stdcall GetWindowThreadProcessId(int hWnd, int *lpdwProcessId);
]]
local WinApiInterface = {}

function WinApiInterface.GetWindowThreadProcessId(handle)
    local pid = ffi.new("int[1]")
    local threadId = WinUser.GetWindowThreadProcessId(handle, pid)
    assert(threadId ~= 0, 'GetWindowThreadProcessId error: incorrect handle passed: '..handle)
    return {
        pid = pid[0],
        threadId = threadId
    }
end

return WinApiInterface

Автор: DarkMaster 20.2.2024, 7:42

Цитата
assert(threadId ~= 0, 'GetWindowThreadProcessId error: incorrect handle passed: '..handle)

handle лучше завернуть в tostring(handle), т.к. если там будет C тип либо nil/false/true/table/usertype - выбьет ошибку. Он не сможет выполнить .. строки.

Автор: DarkMaster 20.2.2024, 19:08

Цитата
Использование void* не в качестве указателя обусловлено необходимостью поддерживать родную для системы битность. Ну т.е. если написать int, то не факт что в скомпилированном приложении он будет 32(64) бита занимать, а void* всегда либо 32 либо 64 в зависимости под какую битность собираешь. Но это вроде даже в Си уже улучшили, просто мелкомягкие не обновили доки + хедеры.

Собственно HANDLE так вот и прячет детали реализации от юзера апи

Я уже раз десятый перечитваю это... Ну разве не костыли и быдло код?)

Автор: Cockney 20.2.2024, 20:33

А есть ли у тебя опыт поддержки кодовой базы в миллионы строк кода на протяжении лет 20-30 ? Это с высоты текущих лет все кажется быдлокодом и костылями, а во времена когда это писалось просто не было даже намека на современные возможности/подходы к разработке.

Автор: DarkMaster 21.2.2024, 7:43

Цитата
А есть ли у тебя опыт поддержки кодовой базы в миллионы строк кода на протяжении лет 20-30 ?

А я и не претендую. Просто смотрю на это и впадаю в прострацию какую-то. Напоминает, как я лет 15 назад массив двумерный сортировал... вторая размернасть была равна двум и внутри инты. Я просто обявил указатель на long long чтобы при сортировке учитывались оба элементра. Сейчас за такое стыдно) А тут серьезные люди.

Автор: Cockney 21.2.2024, 13:03

Ну это прям разные случаи. От тебя не зависело до половины пользователей ПК в мире)


А между тем, реального говнокода полно в банках, на нем крутится куча транзакций и ничего. И когда переводишь кому то деньгу - знай, в этот момент работает сортировка аналогичная твоей.

Русская версия Invision Power Board (http://www.invisionboard.com)
© Invision Power Services (http://www.invisionpower.com)