Начнём по порядку.
1)Класс с подключением библиотек win32
Код:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Runtime.InteropServices;
using System.Diagnostics;
namespace Win32Lib
{
public static class Win32
{
public const int WM_SETCURSOR = 0x020;
public const int WM_COMMAND = 0x111;
public const int WM_KEYDOWN = 0x100;
public const int WM_KEYUP = 0x101;
public const int WM_CHAR = 0x102;
public const int WM_MOUSEMOVE = 0x200;
public const int WM_LBUTTONDOWN = 0x201;
public const int WM_LBUTTONUP = 0x202;
public const int WM_LBUTTONDBLCLK = 0x203;
public const int GWL_EXSTYLE = -20;
public const int WS_EX_TOOLWINDOW = 0x00000080;
public const int WS_EX_APPWINDOW = 0x00040000;
public delegate bool EnumThreadDelegate(IntPtr hWnd, IntPtr lParam);
[DllImport("User32.dll")]
public static extern IntPtr FindWindow(string strClassName, string strWindowName);
[DllImport("user32.dll", SetLastError = true, CharSet = CharSet.Auto)]
public static extern IntPtr FindWindowEx(int parentHandle, IntPtr childAfter, string lclassName, string windowTitle);
[DllImport("user32.dll")]
public static extern bool PostMessage(IntPtr hWnd, uint Msg, int wParam, int lParam);
[DllImport("User32.dll")]
public static extern Int32 SendMessage(IntPtr hWnd, uint Msg, int wParam, Int64 lParam);
[DllImport("user32.dll")]
public static extern int SetWindowLong(IntPtr window, int index, int
value);
[DllImport("user32.dll")]
public static extern int GetWindowLong(IntPtr window, int index);
[DllImport("user32.dll")]
public static extern byte VkKeyScan(char ch);
[DllImport("user32.dll", SetLastError = true)]
public static extern uint GetWindowThreadProcessId(IntPtr hWnd, out uint lpdwProcessId);
[DllImport("user32.dll")]
public static extern bool ShowWindow(IntPtr hwnd, int nCmdShow);
[DllImport("kernel32.dll")]
public static extern int OpenProcess(ProcessAccessFlags dwDesiredAccess, bool bInheritHandle, int dwProcessId);
[DllImport("kernel32.dll")]
public static extern bool WriteProcessMemory(int hProcess, uint lpBaseAddress, byte[] buffer, int size, int lpNumberOfBytesWritten);
[DllImport("kernel32.dll")]
public static extern bool ReadProcessMemory(int hProcess, uint lpBaseAddress, byte[] buffer, int size, int lpNumberOfBytesRead);
[DllImport("kernel32.dll")]
public static extern Int32 CloseHandle(int hProcess);
[DllImport("user32.dll")]
public static extern bool EnumThreadWindows(int dwThreadId, EnumThreadDelegate lpfn, IntPtr lParam);
public enum ProcessAccessFlags : uint
{
All = 0x001F0FFF,
Terminate = 0x00000001,
CreateThread = 0x00000002,
VMOperation = 0x00000008,
VMRead = 0x00000010,
VMWrite = 0x00000020,
DupHandle = 0x00000040,
SetInformation = 0x00000200,
QueryInformation = 0x00000400,
Synchronize = 0x00100000
}
}
public static class ShowMode
{
public const int SW_FORCEMINIMIZE = 11;
public const int SW_HIDE = 0;
public const int SW_MAXIMIZE = 3;
public const int SW_MINIMIZE = 6;
public const int SW_RESTORE = 9;
public const int SW_SHOW = 5;
public const int SW_SHOWDEFAULT = 10;
public const int SW_SHOWMAXIMIZED = 3;
public const int SW_SHOWMINIMIZED = 2;
public const int SW_SHOWMINNOACTIVE = 7;
public const int SW_SHOWNA = 8;
public const int SW_SHOWNOACTIVATE = 4;
public const int SW_SHOWNORMAL = 1;
}
}
2.Класс, который я использую для чтения из памяти
Код:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Win32Lib;
using System.ComponentModel;
namespace MyMagic
{
class WhiteMagic
{
int handler;
public WhiteMagic(int processId)
{
handler = Win32.OpenProcess(Win32.ProcessAccessFlags.All, false, processId);
}
public uint GetAddressByOffsets(uint[] offsets)
{
uint ret=offsets[0];
for(int i=1;i<offsets.Length;i++)
{
ret = ReadUint(ret);
ret += offsets[i];
}
return ret;
}
public uint ReadUint(uint offset)
{
byte[] buff = new byte[4];
Win32.ReadProcessMemory(handler, offset, buff, 4, 0);
uint ret=BitConverter.ToUInt32(buff, 0);
return ret;
}
public void Close()
{
Win32.CloseHandle(handler);
}
}
}
P.S.Пробовал открывать с правами только на чтение - не помогает.
Функция GetAddressByOffsets использую для высчитывания адресов флагов и параметров при старте бота один раз.
3.Пример обращения (привожу не весь код - там 500 с лишним строк - только то что выполняется в таймерах)
Комментарии по этому куску.
checkOffsets - выполняется по таймеру раз в 50-100мс. Проверяет наличие в таргете ресурса. То что для установки использую рандом - вчера тестировал - думал, что возможна какая-то кореляция между таймерами и поэтому всё подвисает.
Как только боту в таргет попадает ресурс он останавливает этот таймер и вызывает таймер проверки начала сбора т.е. я шлю нажатие кнопки сбора до тех пор пока не появится флаг того, что я собираю ресурс.(checkStartGather)
После того как я получил подтверждение старта сбора (флаги сбора и нахождение в таргете ресурса) таймер проверки начала сбора останавливается и запускается таймер проверки окончания сбора.
(Про интервал в 20000 после окончания сбора руда несколько секунд ещё таргете. По этому моменту я выставляю таймер на проверку сбора в 20с(вчера тестил с этой штукой, но бот всё равно зависал так что это не принципиально)
Таймер окончания сбора ожидает, когда флаг сбора станет равным нулю и запускает таймер появления ресурса
1) А зачем ShowWindow? Оо
2) Все это счастье - в отдельном треде для каждого окна? У таймера точно крышу не сносит от доступов с разных сторон?
3) Ты не забываешь, что в C# при срабатывании таймера, метод вызывается в отдельном треде, но при этом этот "отдельный тред" - один. (т.е. если срабатывает 10 таймеров, то методы из них вызовутся последовательно)
4) Мог бы byte[] buff = new byte[4] сделать статиком - чуть меньше напрягов для GC, но не должно это сильно влиять
Добавлено через 8 минут
Понятное дело, что в методе ты этого сделать не сможешь. Если тебе нужен динамический буффер, то создаешь его в конструкторе, а в деструкторе освобождаешь. Либо можно там где вызываешь метод, создать динамический массив , который примет указатель на массив из функции, а после завершения его работы освободить
Последний раз редактировалось Dino; 07.04.2015 в 16:32.
Причина: Добавлено сообщение
Добавлено через 8 минут
Понятное дело, что в методе ты этого сделать не сможешь. Если тебе нужен динамический буффер, то создаешь его в конструкторе, а в деструкторе освобождаешь. Либо можно там где вызываешь метод, создать динамический массив , который примет указатель на массив из функции, а после завершения его работы освободить
Читай мой ответ, прямо над твоим :)
Это C#, в нем не надо освобождать память в явном виде. В нем этим занимается GarbageCollector.
на сколько я знаю, его нужно зарывать.
открыл, прочитал, закрыл.
ничего подобного, открыл и работаешь как отпала надобность в чтении памяти так и закрываешь. то же самое со всем остольным, с файлами, сетью и прочими вещами. ты представь тебе побайтово нужно файл читать, открыл файл считал байт, закрыл файл, открыл считал закрыл.
Добавлено через 2 минуты
Цитата:
Сообщение от Dino
Че правда чтоль? А я думаю "синтаксис знакомый дай отвечу"
Ну это объясняется тем, что мои знания по C# сводятся к нулю
Ну так в сишарпе сборщик мусора одна из его фишек, это наверно единственный для меня в нем плюс. остальное все минусы. да и ресурсы всегда в ручную освобождаю.
Последний раз редактировалось Тигрь; 07.04.2015 в 17:01.
Причина: Добавлено сообщение
Сделал пару исправлений. Сейчас потестирую, но я сомневаюсь, что они прям важные эти исправления, которые я внёс..
Добавлено через 24 минуты
По поводу ShowWindow - был в маразме - перебирал все варианты исправления зависонов поэтому добавил.
Убрал, но сейчас все равно также
Буффер привязал к объекту, но ничего не изменилось.
Сейчас на всякий случай проверю не работают ли в какой-то момент два таймера одновременно.
Последний раз редактировалось Алексанw24; 07.04.2015 в 18:21.
Причина: Добавлено сообщение