Итак вот подробное описание того какой должна быть структура плагина:
delphi Код:
library plugin_demo2;
{$define Release}// для совместимости с релизом пакетхака, при дебуге можно закоментироватьuses
FastMM4,
Coding in'Coding.pas'; // модуль с описаниями основных типов// используемых в плагине и программеvar{version}{revision}
min_ver_a: array[0..3] ofByte = (3,4,1, 46);
min_ver: Integer absolute min_ver_a; // минимальная поддерживаемая версия программы
ps: TPluginStruct; // структура передаваемая в плагин// Обязательно вызываемая функция.// Должна вернуть описание плагина,// заодно может проверить версию программыfunction GetPluginInfo(const ver: Integer): PChar; stdcall;
beginif ver<min_ver then
Result:='Демонстрационный Plugin к программе l2phx'+sLineBreak+
'Для версий 3.4.0+'+sLineBreak+
'У вас старая версия программы! Плагин не сможет корректно с ней работать!'else
Result:='Демонстрационный Plugin к программе l2phx'+sLineBreak+
'Для версий 3.4.0+';
end;
// Обязательно вызываемая функция.// Получает структуру с ссылками на все функции основной программы,// которые могут вызываться из плагина.// Если вернёт False то плагин выгружается.function SetStruct(const struct: TPluginStruct): Boolean; stdcall;
begin
ps:=struct;
Result:=True;
end;
// Необязательно вызываемая функция. (может отсутствовать в плагине)// Вызывается при установки соединения (cnt) с клиентом (withServer=False) // или сервером (withServer=True)procedure OnConnect(const cnt: Cardinal; // номер соединенияconst withServer: Boolean); stdcall; // с сервером?beginend;
// Необязательно вызываемая функция. (может отсутствовать в плагине)// Вызывается при разрыве соединения (cnt) с клиентом (withServer=False)// или сервером (withServer=True)procedure OnDisconnect(const cnt: Cardinal; // номер соединенияconst withServer: Boolean); stdcall; // с сервером?beginend;
// Необязательно вызываемая функция. (может отсутствовать в плагине)// Вызывается при выгрузке плагинеprocedure OnFree; stdcall;
beginend;
// Необязательно вызываемая функция. (может отсутствовать в плагине)// Вызывается при загрузке плагинеprocedure OnLoad; stdcall;
beginend;
// Необязательно вызываемая функция. (может отсутствовать в плагине)// Вызывается при вызове скриптовой функции обьявленной в RefreshPrecompilefunction OnCallMethod(const MethodName: String; // имя функции в верхнем регистреvar Params, // параметры функции
FuncResult: Variant// результат функции): Boolean; stdcall; // если вернёт True то дальнейшая// обработка функции прекратитьсяbegin
Result:=False; // передаём обработку функции программеif MethodName='PI'thenbegin
Result:=True; // запрещаем дальнейшую обработку функции в программе
FuncResult:=Pi;
end;
end;
// Необязательно вызываемая функция. (может отсутствовать в плагине)// Вызывается перед компиляцией скриптовfunction OnRefreshPrecompile(var funcs: TStringArray): Integer; stdcall;
beginSetLength(funcs,1); // указываем количество добавляемых в скрипт функций
funcs[0]:='function Pi:Extended'; // одна из добавляемых функцийend;
// Необязательно вызываемая функция. (может отсутствовать в плагине)// Вызывается при приходе пакета, параметры:// cnt - номер соединения// fromServer - если пакет от сервера равна True, если от клиента то False// pck - собственно пакет (в виде массива)procedure OnPacket(const cnt: Cardinal; const fromServer: Boolean; var pck: TPacket); stdcall;
beginif pck.size<3thenexit; // на случай если предыдущие плагины обнулили пакетend;
// экспортируем используемые программой функции
exports
GetPluginInfo,
SetStruct,
OnPacket,
OnConnect,
OnDisconnect,
OnLoad,
OnFree,
OnCallMethod,
OnRefreshPrecompile;
beginend.
о передоваемой плагину структуре TPluginStruct:
delphi Код:
TPluginStruct = packedrecord
Threads: PThreads; // указатель на первый элемент массива TThread// через него можно получить доступ к любой переменной соединения
ThreadsCount: Integer; // максимальное число соединений //(не путать с количеством реально установленых соединений!)// функции отправки пакета:
SendPck: TSendPacket;
SendPckStr: TSendPckStr;
SendPckData: TSendPckData;
// функции преобразования:
DataPckToStrPck: TDataPckToStrPck; // преобразует пакет из массива в строку и отрезает 2 байта длинны
HexToString:THexToString; // преобразует Hex пакета в просто пакет в виде строки
StringToHex:TStringToHex; // наоборот// функции чтения из пакета в виде строки:
ReadC: TReadC;
ReadH: TReadH;
ReadD: TReadD;
ReadF: TReadF;
ReadS: TReadS;
// функции чтения из пакета в виде массива:
ReadCEx: TReadCEx;
ReadHEx: TReadHEx;
ReadDEx: TReadDEx;
ReadFEx: TReadFEx;
ReadSEx: TReadSEx;
// функции записи в пакет в виде строки:
WriteC: TWriteC;
WriteH: TWriteH;
WriteD: TWriteD;
WriteF: TWriteF;
WriteS: TWriteS;
// функции записи в пакет в виде массива:
WriteCEx: TWriteCEx;
WriteHEx: TWriteHEx;
WriteDEx: TWriteDEx;
WriteFEx: TWriteFEx;
WriteSEx: TWriteSEx;
// функции работы с таймером на основе отдельного потока:
CreateAndRunTimerThread: TCreateAndRunTimerThread; // создаёт и запускает таймер
ChangeTimerThread: TChangeTimerThread; // может изменить интервал, параметр// пользователя и процедуру вызываемую таймером
DestroyTimerThread: TDestroyTimerThread; // останавливает и уничтожает таймерend;
у функций чтения первый параметр это пакет, второй - позиция с которой производиться чтение
у функций записи первый параметр это пакет, второй - записываемые данные, третий - индекс в который производиться запись, если 3й параметр не задан или равен -1, то данные пишутся в конец пакета
о параметрах остальных функций из структуры:
delphi Код:
procedure SendPacket(Size: Word; // размер пакета (размер pck +2)
pck: string; // пакет в виде строки без первых 2х байт длинны
tid: Byte; // номер соединения
ToServer: Boolean); // направление отсылки, если True то на серверprocedure SendPckStr(pck: string; // пакет в виде строки без первых 2х байт длинныconst tid: Byte; // номер соединенияconst ToServer: Boolean); // направление отсылки, если True то на серверprocedure SendPckData(var pck; // пакет в виде массиваconst tid: Byte; // номер соединенияconst ToServer: Boolean// направление отсылки, если True то на сервер); stdcall;
function DataPckToStrPck(var pck // пакет в виде массива): string; stdcall; // возвращает пакет в виде строкиfunction HexToString(Hex:String// HEX строка):String;
function StringToHex(s, // пакет в виде строки
Separator:String// разделитель между байтами):String;
function CreateAndRunTimerThread(const interval, // интервал срабатывания таймера
usrParam: Cardinal; // параметр передаваемый в процедуру OnTimerProcconst OnTimerProc: TOnTimer // вызывается при срабатывании таймера): Pointer; stdcall; // возвращает указатель на объект потокаprocedure ChangeTimerThread(const timer: Pointer; // указатель на объект потокаconst interval: Cardinal; // интервал срабатывания таймераconst usrParam: Cardinal = $ffffffff;
// параметр передаваемый в процедуру OnTimerProc,// если равен $ffffffff, то не меняетсяconst OnTimerProc: TOnTimer = nil// вызывается при срабатывании таймера, если nil - не меняется); stdcall;
procedure DestroyTimerThread(var timer: Pointer// указатель на объект потока); stdcall;
__________________
Я здесь практически не появляюсь!, Skype - ikskor
Ещё пожалуй расскажу о том как наиболее удобно отлаживать плагин Вариант 1 (отладка только плагина):
1. Компилим плагин
2. Запускаем пакетхак
3. В delphi выбираем меню Run -> Attach to Process...
4. там находим и выбираем l2pbx.exe, убираем галочку "Pause After Attach" и жмём Attach
5. В пакетхаке подключаем плагин
6. Усё, можем ставить бряки в плагине
Вариант 2 (отладка программы вместе с плагином):
1. В дельфи создаём группу из проекта программы и проекта плагина
2. Компилим оба проекта (не забываем указать путь компиляции для плагина в папку plugins)
3. Запускаем программу с дебугом
4. В программе подключаем плагин и дельфи автоматически распознаёт что эта dll из группы и даёт возможность ставить бряки и в проекте плагина
Первый вариант позволяет отлаживать плагин без перекомпиляции основной программы, тоесть можно работать только с плагином
Второй позволяет отлаживать всё сразу
ЗЫ описание на основе дельфи 2007, но в 2006 скорее всего всё так же, а в более ранних версиях думаю тоже должны быть аналогичные возможности, но возможно немного в других местах
__________________
Я здесь практически не появляюсь!, Skype - ikskor
А как насчёт расписать TPacket?
Что включает параметр size, data?
Например содержится ли TPacket.id ещё и в TPacket.data[0]?
TPacket.size указывает размер всего пакета, или только данных? (хотя по проверке pck.size<3 я считаю что это длина всего пакета с байтами длины и айдишкой, но лучше перестраховаться)
Ну блин, структуру я не идиот, там и смотрел!
Я ж не структу прошу расписать, а ньюансы полей.
А вот в SendPckData с массивом вообще не понятно, ну передам я массив байт, а как определяется конец пакета? Или надо передавать массив вместе с длиной пакета?
А так же в чём разница между процедурами SendPacket и SendPckStr? Первая отсекает строку заданного размера?
Вобщем подробностей бы побольше!