Форум: "Основная";
Текущий архив: 2006.01.15;
Скачать: [xml.tar.bz2];
Внизпередача массива из DLL Найти похожие ветки
← →
GanibalLector © (2005-12-04 17:33) [0]Имеем такой вот массив:
type
TBasic=packed record
ID : Word;
Group : Byte;
Code : DWord;
Price : DWord;
Valid : DWord;
Line : String[24];
end;
PBasicPLU = ^TBasicPLU;
TBasicPLU = array of TBasic;
идея такова.В своем приложении я вызываю библиотеку,которая заполняет данный массив до некоторого размера. В основном приложении я хотел бы получить его длину и,соответственно,все данные.
Но вот не получается с кодом :(
Чтобы было более понятно,я покажу "это" на примере (только не с массивом,а с Integer):
procedure Test(var HMem:Integer);
var
Value:Integer;
P:Pointer;
begin
Value:=3107;
HMem:=GlobalAlloc(GMEM_DDESHARE or GMEM_MOVEABLE or GMEM_ZEROINIT,SizeOf(Value)+1);
if HMem>0 then
begin
P:=GlobalLock(HMem);
if Assigned(P) then System.Move(Value,P^,SizeOf(Value));
end;
end;
procedure TForm1.Button1Click(Sender: TObject);
var H:Integer;
P:Pointer;
begin
Test(H);
if H>0 then
begin
P:=GlobalLock(H);
Caption:=IntToStr(PInteger(P)^);
GlobalUnlock(H);
GlobalFree(H);
end;
end;
Заранее большое спасибо!!!
← →
jack128 © (2005-12-04 18:05) [1]GanibalLector © (04.12.05 17:33)
Но вот не получается с кодом :(
Хорошее объяснение. И главное очень подробное.
ps Почему GlobalLock вызываешь два раза, а GlobalUnlock - только один??
pps Вообще мне не нравится твой подход.
← →
begin...end © (2005-12-04 18:27) [2]> GanibalLector © (04.12.05 17:33)
> В своем приложении я вызываю библиотеку,которая заполняет
> данный массив до некоторого размера. В основном приложении
> я хотел бы получить его длину и,соответственно,все данные.
Функции, находящейся в DLL, передаются 2 параметра -- указатель на заранее выделенную область памяти, в которую нужно поместить данные, и длина этой области (var-параметр). Если указатель равен nil, то функция ничего не помещает в буфер, а во втором параметре возвращает требуемую длину буфера.
EXE вызывает функцию вначале с nil-указателем, получая необходимую длину буфера, выделяет буфер и вызывает функцию снова -- с указателем на готовый буфер.
Типичная схема для многих API-функций. Почему бы и здесь не сделать так же?
← →
Юрий Зотов © (2005-12-04 19:38) [3]А еще проще использовать ShareMem и SetLength. Не создавая самому себе лишних проблем.
← →
Набережных С. © (2005-12-04 20:12) [4]Или экспортировать из ДЛЛ пару функций выделения и освобождения памяти.
Или использовать IMalloc или функции-оболочки вокруг его системной реализации CoTaskMemAlloc etc
Или делать COM-сервер и реализовать интерфейс-перечислитель.
Или использовать IMardhal и реализовать объект, передаваемый "по значению".
И все эти способы, как и [2], дают большую или меньшую незаисимость от среды разработки.
← →
GanibalLector © (2005-12-04 21:56) [5]2 begin...end © (04.12.05 18:27) [2]
>Типичная схема для многих API-функций. Почему бы и здесь не сделать так же?
Хорошо...Вот бы на код посмотреть ;)
← →
GanibalLector © (2005-12-05 12:21) [6]Я продолжу свои мысли...вдруг кому-то будет интересно ;)
Так вот,усложним пример в [0] и будем передавать структуру.
type
TBasic=packed record
Id:Byte;
Line : String[24];
end;
PBasic = ^TBasic;
procedure Test(var HMem:Integer);
var Value:TBasic;
P:Pointer;
begin
Value.Id:=56;
Value.Line:="Test";
HMem:=GlobalAlloc(GMEM_DDESHARE or GMEM_MOVEABLE or GMEM_ZEROINIT,SizeOf(TBasic)+1);
if HMem>0 then
begin
P:=GlobalLock(HMem);
if Assigned(P) then System.Move(Value,P^,SizeOf(TBasic));
end;
end;
procedure TForm1.Button1Click(Sender: TObject);
var H:Integer;
P:Pointer;
Q:TBasic;
begin
Test(H);
if H>0 then
begin
P:=GlobalLock(H);
Q:=PBasic(P)^;
Memo1.Lines.Add(Q.Line);
Memo1.Lines.Add(IntToStr(Q.Id));
GlobalUnlock(H);
GlobalFree(H);
end;
end;
Данный код работает ;)
Ну,а теперь перейдем уже к массиву определенной структуры.Т.е. к основной и заветной цели [0]. Итак :
type
TBasic=packed record
Id:Byte;
Line : String[24];
end;
PBasicPLU = ^TBasicPLU;
TBasicPLU = array of TBasic;
procedure Test(var HMem:Integer);
var Value:TBasicPLU;
P:Pointer;
I:Integer;
begin
SetLength(Value,10);
for I:=0 to Length(Value)-1 do
begin
Value[I].Id:=I;
Value[I].Line:="Test"+IntToStr(I);
end;
HMem:=GlobalAlloc(GMEM_DDESHARE or GMEM_MOVEABLE or GMEM_ZEROINIT,
SizeOf(TBasic)*Length(Value)+1);
if HMem>0 then
begin
P:=GlobalLock(HMem);
if Assigned(P) then System.Move(Value,P^,SizeOf(TBasic)*Length(Value));
end;
end;
procedure TForm1.Button1Click(Sender: TObject);
var H:Integer;
P:Pointer;
Q:TBasicPLU;
i:Integer;
begin
Q:=nil;
Test(H);
if H>0 then
begin
P:=GlobalLock(H);
Q:=PBasicPLU(P)^;
//Caption:=IntToStr(Length(Q)); тут вообще ужас :(
for i:=0 to 9 do
begin
Memo1.Lines.Add(Q[i].Line);
Memo1.Lines.Add(IntToStr(Q[i].Id));
end;
GlobalUnlock(H);
GlobalFree(H);
end;
end;
Как Вы понимаете этот код не работает.Даже не вижу причин для этого :(
И еще...если вместо цикла поставить
Memo1.Lines.Add(IntToStr(Q[2].Id));
Memo1.Lines.Add(Q[2].Line);
то результат будет правильным,но только на значениях от 2 до 9.
Может память выделяю неверно???
← →
GanibalLector © (2005-12-05 12:23) [7]2 begin...end © (04.12.05 18:27) [2]
>Типичная схема для многих API-функций. Почему бы и здесь не сделать так же?
Кстати,напомните оные. Запамятовал :( Хоть погляжу в генофонде...
← →
jack128 © (2005-12-05 12:32) [8]GanibalLector © (05.12.05 12:21) [6]
TBasicPLU = array of TBasic
GanibalLector © (05.12.05 12:21) [6]
Q:=PBasicPLU(P)^;
//Caption:=IntToStr(Length(Q)); тут вообще ужас :(
Ты где так научился?? Бред написал - ужас получил, всё закономерно.procedure Test(var HMem:Integer);
var Value:TBasicPLU;
P:Pointer;
I:Integer;
begin
SetLength(Value,10);
for I:=0 to Length(Value)-1 do
begin
Value[I].Id:=I;
Value[I].Line:="Test"+IntToStr(I);
end;
HMem:=GlobalAlloc(GMEM_DDESHARE or GMEM_MOVEABLE or GMEM_ZEROINIT,
SizeOf(TBasic)*Length(Value)+SizeOf(Integer));
if HMem>0 then
begin
P:=GlobalLock(HMem);
if Assigned(P) then
begin
PInteger(P)^ := Length(Value); // Пишем длину массива
System.Move(Value,Pointer(PChar(P) + SizeOf(Integer))^,SizeOf(TBasic)*Length(Value));
ClobalUnlock(P);
end;
end;
end;
...
type
TBasicArray = array[0..(MaxInt div SizeOf(TBasic)) - 1] of TBasic;
PBasicArray = ^TBasicArray;
var
Arr: PBasicArray;
Len: Integer;
begin
Q:=nil;
Test(H);
if H>0 then
begin
P:=GlobalLock(H);
Len := PInteger(P)^; // получаем длину массива.
Arr := Pointer(PChar(P) + SizeOf(Integer));
Caption:=IntToStr(Len));
for i:=0 to Len do
begin
Memo1.Lines.Add(Arr[i].Line);
Memo1.Lines.Add(IntToStr(Arr[i].Id));
end;
GlobalUnlock(H);
GlobalFree(H);
end;
PS
Вообще мне не нравится твой подход.(c)Я
← →
jack128 © (2005-12-05 12:33) [9]jack128 © (05.12.05 12:32) [8]
for i:=0 to Len - 1 do
← →
GanibalLector © (2005-12-05 13:28) [10]2 jack128
Спасибо!!!
А я тем временем сделал так :
function Test(var HMem:Integer):Word;
var Value:TBasicPLU;
P:Pointer;
I:Integer;
begin
Result:=0;
SetLength(Value,10);
for I:=0 to Length(Value)-1 do
begin
Value[I].Id:=I;
Value[I].Line:="Test"+IntToStr(I);
end;
HMem:=GlobalAlloc(GMEM_DDESHARE or GMEM_MOVEABLE or GMEM_ZEROINIT,
SizeOf(TBasic)*Length(Value)+1);
if HMem>0 then
begin
P:=GlobalLock(HMem);
if Assigned(P) then
begin
System.Move(Value,P^,SizeOf(TBasic)*Length(Value));
Result:=Length(Value);
end;
end;
end;
procedure TForm1.Button1Click(Sender: TObject);
var H:Integer;
P:Pointer;
Q:PBasicPLU;
SizeArr:Word;
I:Integer;
begin
SizeArr:=Test(H);
if (H>0) and (SizeArr>0) then
begin
P:=GlobalLock(H);
GetMem(Q,SizeOf(TBasic)*SizeArr); // вот в чем дело !!!
Q^:=PBasicPLU(P)^;
for i:=0 to SizeArr-1 do
begin
Memo1.Lines.Add(Q^[i].Line);
Memo1.Lines.Add(IntToStr(Q^[i].Id));
end;
FreeMem(Q);
GlobalUnlock(H);
GlobalFree(H);
end;
end;
← →
jack128 © (2005-12-05 13:58) [11]GanibalLector © (05.12.05 13:28) [10]
GetMem(Q,SizeOf(TBasic)*SizeArr); // вот в чем дело !!!
Бред. Если скомпилируешь с $R+ то глюки полезут из всех щелей. Оставь в покое динамические массивы, если не знаешь как они работают.
← →
GuAV © (2005-12-05 16:39) [12]см. [2], [3], [4] +
Кроме уже указанных подходов следует также упомянуть enumeration callback функции. В функцию dll передается функция приложения, которая будет вызванна для каждой записи. Преимущества этого подхода:
+ Нет выделения памяти в одном месте и освобожения в другом. При желании, нет вообще динамического выделения памяти.
+ Есть примеры в WinAPI - EnumXXX
+ Line м.б. PChar - это снимет ограничения на длину.
+ Эта dll м.б. использована из приложения на Delphi, C, и даже VB (при соблюдении stdcall и ограничения стандартными типами).
← →
GanibalLector © (2005-12-06 19:00) [13]2 jack128 ©
>Бред. Если скомпилируешь с $R+ то глюки полезут из всех щелей.
Я этого не заметил.Код прекрасно отработал на D5 и D7.
>вообще мне не нравится твой подход
А я и не говорил,что это мой подход! Это подход Тенцера.Взято у него в книге. Также автор предлагает использовать ф-цию CoTaskMemAlloc указанную в [4].
З.Ы. И еще,код в [8] не рабочий.
← →
Cash © (2005-12-06 21:17) [14]whatsup! Вмешаться можно? А... всеравно влез!
Предворю:
В код на последующих постах не вглядывался,
поэтому, если что, не ругать!
Замечу:
To GanibalLector ©:
С построением записи TBasic полностью согласен,
это хорошо, что она не ранжирована.
А вот с этим:
PBasicPLU = ^TBasicPLU;
TBasicPLU = array of TBasic;
категорически не согласен!
Словами это объясняется так:
"создадим указатель на масив {TBasicPLU = array of TBasic;},
и еще создадим указатель на этот указатель,
и будем его использовать.", по моему это странно!
Работать то будет, но каряво!
КодTBasicPLU = array of TBasic,
создаст
открытый масив, при этом переменная этого типа будет указателем.
С этим типом хорошо работать с помощью функций:
SetLength(variable,len1,len2,.......,lenN); - она создает N-мерный масив. (выделяет память в ОП)
Finalize(variable); - она эту память вычищает и ставит variable в nil.
Удобно? Мне - да. Особенно при том, что я частнько юзаю
плагины для своих прог, а там такое иногда надо. Передать указатель в
длл-овую функцию удобнее чем саму переменную, главное запретить
изменение этого указателя (если обратного не нужно).
Память под масив лучше выделять в основной проге, указатель
сформируется в ее адресном пространстве, создай функцию,
которая возвращает число необходимых элементов.
Вызвай SetLength(parray,Extern_GetCount) для создания масива.
Передавай указатель созданного масива во внешнюю функцию,
которая его заполнит.
Для просмотра длины масива можно воспользоваться функцией
High(parray), которая вернет максимальный индекс элемента
масива, делай High(parray)+1 для получения размера масива.
Данные можно получить легко, как будто обращаешся к статическому
масиву, легко и удобно parray[0] .. parray[High(parray)].
И еще, уж чего чего, а со строками надо быть поосторожнее.
В Pascal можно задать максимум 255 символов для сток,
а в Delphi? Тоже 255? или 552? А мож 65536? и так тоже можно!
Сторка в Делфи тоже является указателем! Поэтому, присваивая
новое строковое значение прога создает для нее адрес в текущей
секции ОП, то есть в области длл-ки, а прога туда глядеть не может!
Поэтому, либо используй PChar тип строк, либо юзай юнтит ShareMem
и кидай borlandmm.dll рядом с exe-шником (ShareMem надо подключить
и к длл-ке и к DPR файлу. С этим юнитом ваабще все проблемы с
разделенной памятью отвалятся, она станет нераздельная для длл-ки
и для проги).
← →
jack128 © (2005-12-06 21:55) [15]GanibalLector © (06.12.05 19:00) [13]
>Бред. Если скомпилируешь с $R+ то глюки полезут из всех щелей.
Я этого не заметил.
Да, был не прав. Глюки должны полезть в том случае, если в первых 4 байтах памяти, выденой GetMem"ом не будут равны nil"у или же (тут еще несколько почти невероятных, отличии от первого вариантов). Мем лик же возникает в любом случае. Еще раз, если ты не представляешь, как работают дин массивы - откажись от них. Или ты представляешь как они работают? тогда, объясни мне пожалуйста - почему твой код не вызывает av?
ps программирование методом тыка - это конечно метод.. но ни к чему хорошему он не приводит.
← →
GanibalLector © (2005-12-06 23:45) [16]> Мем лик же возникает в любом случае.
Нет никакого мемлика! Ни в D5 ни в D7.
>Или ты представляешь как они работают?
Представляю.
> тогда, объясни мне пожалуйста - почему твой код не вызывает av?
А с чего он должен вызывать AV??? Был пример в книге. Сперва я попробовал передавать Integer и структуру...все получилось. Ну,а потом массив. А проблемы возникали из-за указателей.
> программирование методом тыка - это конечно метод.. но ни к чему хорошему он не приводит.
Я с тобой согласен. Знаешь,я учусь сам(в основном по книгам) и это я тебе уже говорил.Да,есть у меня некоторые пробелы в знаниях :( Лучше бы литературу порекомендовал!
← →
GanibalLector © (2005-12-06 23:53) [17]2 jack128 ©
Мой окончательный вариант(с твоими доработками...за что тебе отдельное спасибо). Ни мемликов,ни утечек нет.
type
TBasic=packed record
Id:Byte;
Line : String[24];
end;
PBasicPLU = ^TBasicPLU;
TBasicPLU = array of TBasic;
procedure Test(var HMem:Integer);
var Value:TBasicPLU;
P:Pointer;
I:Integer;
begin
SetLength(Value,random(100)+1);
for I:=0 to Length(Value)-1 do
begin
Value[I].Id:=I;
Value[I].Line:="Test"+IntToStr(I);
end;
HMem:=GlobalAlloc(GMEM_DDESHARE or GMEM_MOVEABLE or GMEM_ZEROINIT,
SizeOf(TBasic)*Length(Value)+SizeOf(Integer)+1);
if HMem>0 then
begin
P:=GlobalLock(HMem);
if Assigned(P) then
begin
PInteger(P)^ := Length(Value);
System.Move(Value,Pointer(PChar(P) + SizeOf(Integer))^,SizeOf(TBasic)*Length(Value));
end;
end;
end;
procedure TForm1.Button1Click(Sender: TObject);
var H:Integer;
P:Pointer;
Q:PBasicPLU;
Len:Word;
I:Integer;
begin
Test(H);
if (H>0) then
begin
P:=GlobalLock(H);
Len := PInteger(P)^;
GetMem(Q,SizeOf(TBasic)*Len);
Q^:=PBasicPLU(PChar(P) + SizeOf(Integer))^;
for i:=0 to Len-1 do
begin
Memo1.Lines.Add(Q^[i].Line);
Memo1.Lines.Add(IntToStr(Q^[i].Id));
end;
FreeMem(Q);
GlobalUnlock(H);
GlobalFree(H);
end;
end;
← →
jack128 © (2005-12-07 00:38) [18]Да? Я тебе такого не советовал..
ps не нужели у тебя ни разу ав"шки не выскочило при тестировании этого кода?? Нажми на кнопку раз 20-30 подряд, а потом закрой приложение - 100% выскочит.
jack128 © (05.12.05 12:32) [8]
ClobalUnlock(H); //сорри
← →
GanibalLector © (2005-12-07 02:06) [19]2 jack128 © (07.12.05 00:38) [18]
>Да? Я тебе такого не советовал..
О чем речь???
>Нажми на кнопку раз 20-30 подряд, а потом закрой приложение - 100% выскочит.
Да хоть 100. Нет его!!!
← →
Slym © (2005-12-07 06:24) [20]GanibalLector © (07.12.05 2:06) [19]
Счастливое стечение обстоятельств!
AV тебе в помощь TObject(pointer(0)).Free;
← →
Fay © (2005-12-07 07:30) [21]2 Slym © (07.12.05 6:24) [20]
> AV тебе в помощь TObject(pointer(0)).Free;
Выполни у себяTObject(pointer(0)).Free
.
Просто в образовательных целях.
← →
Slym © (2005-12-07 07:37) [22]Fay © (07.12.05 7:30) [21]
Просто в образовательных целях
Не цепляйся к букве- тут принцип работы...
а так - TObject(pointer(1)).Free;
← →
Fay © (2005-12-07 07:42) [23]2 Slym © (07.12.05 7:37) [22]
> а так - TObject(pointer(1)).Free;
Нет, спасибо 8)
← →
jack128 © (2005-12-07 10:14) [24]GanibalLector © (07.12.05 2:06) [19]
О чем речь???
О дин массивах.
GanibalLector © (07.12.05 2:06) [19]
Да хоть 100. Нет его!!!
Советую в казино сходить, с таким везением имеешь все шансы Джек Пот сорвать.
← →
jack128 © (2005-12-07 10:15) [25]Вот у меня av"ка в твоем коде вылазит постоянно.. Ну из 10 экспеременов раз 9 AV и один раз нормально завершится программа.
← →
GanibalLector © (2005-12-07 21:18) [26]2 jack128 ©
Ну,наконец-то и я получил AV.Правда на другом компьютере(мой до сих пор ее не видит). Проблему разрешил заменивTBasicPLU = array of TBasic;
наTBasicPLU = array[1..10000] of TBasic;
и полной заменой кода. :(
>Советую в казино сходить, с таким везением имеешь все шансы Джек Пот сорвать.
А это идея ;)
← →
jack128 © (2005-12-07 21:49) [27]GanibalLector © (07.12.05 21:18) [26]
Ну,наконец-то и я получил AV
Поздравляю :-)
← →
Cash © (2005-12-08 14:28) [28]Анекдот:
"Пациент:
Доктор, доктор, помогите..., меня никто... не замечает!
Доктор:
.... Следующий!"
:)))
Look to (06.12.05 21:17) [14]
← →
jack128 © (2005-12-08 15:56) [29]Cash © (08.12.05 14:28) [28]
Заметил ;)
Cash © (06.12.05 21:17) [14]
Код TBasicPLU = array of TBasic, создаст
открытый масив
Не верно. Термин _открытый_ массив имеет в дельфи самостоятельное значение, не имееющее к TBasicPLU никакого отнашения. TBasicPLU - это _динамический_ массив. Очень многие не понимают разницу между этими понятиями. подробности в open arrays + f1
Cash © (06.12.05 21:17) [14]
она(память) станет нераздельная для длл-ки
и для проги Для dll и EXE память всегда неразделяемая(если я прально понял, что вкладыаваешь в это слово), поскольку они выполняются в едином ВАП. ShareMem всего лишь добавляет общий менеджер памяти в программу.
← →
Cash © (2005-12-08 22:00) [30]По книжкам учились,? юноша!
Этот термин имеет прямое отношение к данному типу.
Мы не в Паскале, а в Делфи!
Открытый масив записей!
Открытый масив применимо к объявлению "array of .....".
Хотя нет такого типа(......)! Дык по этому и говорят просто "открытый масив"
с динамическим распределением памяти. Суть дела не меняется!
Чел. взял да и сделал двойной указатель, потом при помощи
вызова GetMem выделил под вторичный указатель памяти до][...на.
Ну, так нельзя! Дельфя то ругаться не будет, но и работоспособности это
не прибавит!
... Для dll и EXE память всегда неразделяемая ...
Еще раз прочитай первую строчку поста, и улыбнись.
Нифчего подобного! Для подтверждения моих слов делаем такую вещь:
Открываем Делфи.
Выбираем "Создать-Мастер DLL".
Смотрим и внимательно, со словарем(если без словаря не получается),
Читаем то, что дядя Борланд там написал в коментариях.
А это так, от меня, воспоминания.
При загрузке программы для нее создается страница адресного
пространства требуемого размера. Далее, если программа использует
внешние исполняемые библиотеки, то их код загружается однократно.
Впринципе, как код и самой программы. Далее создаются страницы
адресного пространства для исполняемых библиотек. API Windows
тоже имеют свое адресное пространство, и загружаются в ОП
однократно, далее используются только из ОП.
А как можно разделить, где мое пространство, а где моей DLL-ки?
Только с помощью менеджера памяти! Иначе Программа просто
не сможет оперировать адресами из области DLL!!!
Коллега, вы хотите сказать, что мы без проблем можем пробиться в блоки
памяти API функций. Бред!
← →
jack128 © (2005-12-08 22:47) [31]Cash © (08.12.05 22:00) [30]
Открытый масив применимо к объявлению "array of .....".
применимо. Но не в контексте объявления типа. Еще раз советую обратить внимание на хелп. Помогает.
Cash © (08.12.05 22:00) [30]
Читаем то, что дядя Борланд там написал в коментариях.
ничего не вижу про раздельньные ВАП для dll и exe её использующую.
>мы без проблем можем пробиться в блоки
> памяти API функций.
Что означает - пробиться?? Читать без проблем, писать - нужно флаги защиты памяти снять(хотя прав на снятие флагов может и не оказаться. Я не спец в этих делах, можешь в Системе/API поинтересовать) и вроде можно..
Cash © (08.12.05 22:00) [30]
API Windows
тоже имеют свое адресное пространство
:-) Ясно. Купи Рихтера и почитай, что такое виртуальное адресное пространство.
← →
jack128 © (2005-12-08 23:06) [32]Вот, наваял спецом для тебя примерчик как писать в "блок памяти API функций"
procedure TForm1.Button1Click(Sender: TObject);
const
s: string = "Мама мыла раму";
MemCount = {Length(s)} 14 + 1;
var
SaveMem, P: PChar;
OldProtect1, OldProtect2: DWORD;
Temp: DWORD;
begin
P := @RemoveMenu; // На функциях kernel32 не решился не тестить. Хоть PAGE_WRITECOPY, но бережённого бог бережет :-)
Win32Check(VirtualProtect(P, MemCount, PAGE_WRITECOPY, OldProtect1));
SaveMem := AllocMem(MemCount);
try
Move(P^, SaveMem^, MemCount); // Сохраняем код функции
Move(s[1], P^, MemCount); // копируем бред.
Win32Check(VirtualProtect(P, MemCount, OldProtect1, OldProtect2)); // Восстанавливаем старую защиту
try
RemoveMenu(0, 0, 0); // пытаемся выполнить функцию
except
on E: Exception do
// AV. Или привелигированная инструкция. Или еще какой бред полез. Правда странно? ;)
Application.ShowException(E);
end;
Win32Check(VirtualProtect(P, MemCount, PAGE_WRITECOPY, OldProtect1)); // опять получаем права на запись
Move(SaveMem^, P^, MemCount); // Восстанавливаем код функции
Win32Check(VirtualProtect(P, MemCount, OldProtect1, OldProtect2));
finally
FreeMem(SaveMem);
end;
end;
← →
Alexander Panov © (2005-12-08 23:08) [33]Cash © (08.12.05 22:00) [30]
Открытый масив применимо к объявлению
Нет такого понятия - "открытый массив".
Есть 2 понятия - "динамический массив" и "открытый массив параметров".
← →
Anatoly Podgoretsky © (2005-12-09 00:04) [34]И их тоже два варианта
open array parametersarray of type
и
Variant open array parametersarray of const
Страницы: 1 вся ветка
Форум: "Основная";
Текущий архив: 2006.01.15;
Скачать: [xml.tar.bz2];
Память: 0.58 MB
Время: 0.014 c