30.04.2010 от semen
Раз уж я затронул тему потоков - расскажу об одной хитрости, которую я использую. Довольно часто поток необходимо настраивать при создании, например - задавать начальные параметры, данные для обработки. В принципе, сложного ничего нет и задание начальных параметров потока довольно-таки обычное дело.
Как красиво поступить в ситуации, когда данные хранятся в большом массиве типов Record (назовём его “Главным массивом”, ГМ), а каждый поток работает только с одним элементом массива? Раньше, я бы просто передавал в поток копию элемента массива и работал уже с ней (с копией). Такое решение не самое удачно, если элементы занимают достаточно большой объём. Можно использовать два пути, которые достаточно очевидны: первый - передавать в поток номер элемента ГМ и работать из потока с ГМ. Это решение неплохо подойдёт в 90% случаев и описывать его подробнее нет нужды. А что делать, если ГМ представлен в виде сложного связанного списка? В таком случае можно воспользоваться вторым подходом - передавать в поток только адрес в памяти элемента ГМ! Немного примеров:
Данные хранятся в массиве типа Record:
TMyRecord = Record
field1 : string;
field2 : string;
......
end;
TMyArray = array of TMyRecord;
MyArray : TMyArray;
В потоке объявляется публичная переменная типа Pointer:
TMyThread = class(TThread)
........
public
//address
MemAddr : ^TMyRecord;
При создании потока задаём адрес в памяти нужного элемента ГМ:
MyThread.MemAddr := @MyArray[i];
И в самом потоке можем обращаться непосредственно по адресу:
При таком подходе не происходит дублирования данных в памяти.
См. также:
Сколько потребляет физической памяти ваша программа?
Ограничение количества потоков
Вызов элемента панели управления из Delphi
Рубрики: Общее | Комментариев нет »
13.04.2010 от semen
Для получения данных из сети удобно использовать несколько сетевых потоков одновременно. Одной из проблем является ограничение максимального количества потоков.
Самым простым и очевидным решением будет выделение переменной-счётчика, где и будет хранится число потоков. При создании нового потока можно увеличивать счётчик и, таким образом, знать текущее количество потоков - здесь всё просто и безопасно. Проблемным местом данного решения является уменьшение значения счётчика при уничтожении одного из потоков. Дело в том, что нужно обеспечивать эксклюзивный доступ к переменной счётчика и ни один другой поток не должен в этот момент её считывать или изменять. Поясню на примере: поток А и Б завершаются одновременно и каждый из потоков уменьшает значение счётчика на единицу. Допустим, перед завершением потоков, значение счётчика равнялось двум (всего было 2 потока). Каждый поток получает значение счётчика (двойку) одновременно и уменьшает на единицу (значение счётчика становится единицей), при этом потоки “не знают” о существовании друг друга. В таком варианте развития событий, значение счётчика не будет соответствовать реальном числу потоков, что обязательно приведёт к сбоям в работе программы и лишает смысла наличие самого счётчика. Для обеспечения эксклюзивного доступа можно воспользоваться критическими секциями или семафорами. Использовать критические секции и семафоры нужно очень осторожно, я бы не советовал их на начальном этапе изучения потоков в Дельфи. Мы воспользуемся другим способом, довольно простым в реализации.
Как правило, для получения данных из сети используются несколько экземпляров одного класса-потока, поэтому допустимо использование общего “контейнера” для всех используемых потоков одного типа. Я использовал класс TThreadList. При создании нового потока нужно добавлять его в ThreadList:
constructor TMyThread.Create;
begin
inherited Create(True);
............
ThreadList.Add(self);
end
При уничтожении потока, убираем его из списка:
destructor TMyThread.Destroy;
begin
................
ThreadList.Remove(self);
inherited Destroy;
end
Сразу же возникает вопрос - что произойдёт, если потоки будут уничтожаться и удаляться из списка потоков одновременно? Ответ прост - в реализации процедур Add и Remove используются критические секции для обеспечения эксклюзивности доступа к списку (кстати, полезно изучить реализацию этих процедур, если в будущем планируется использование критических секций), поэтому похожая ситуация со счётчиком гарантированно не возникнет. Узнать текущее количество потоков можно простой функцией:
function getThreadCount : integer;
begin
Result := ThreadList.LockList.Count;
ThreadList.UnlockList;
end;
LockList- блокирует ThreadList для других потоков, UnlockList - снимает эту блокировку. Таким образом, пока мы считываем количество потоков никаких изменений со списком не произойдёт.
ThreadList удобно использовать и в других целях, когда необходимо обратиться к созданным потокам (например - экстренное завершение).
См. также:
Настройка потока перед запуском
Ошибка в модуле idZLibCompressorBase
Обрабатываем HTML
Рубрики: Алгоритмы, Сеть, Общее | Комментариев нет »
05.04.2010 от semen
При работе с HTML-кодом страниц, довольно часто приходится сталкиваться с обработкой специальных символов. Большинство таких функций “по умолчанию” реализованы в PHP, а вот программистам DELPHI - нужно описывать вручную. Несколько функций для обработки текста:
1. PregQuote - подготовка текста к обработке регулярными выражениями.
function PregQuote(str: string): string;
var r: IRegex; m: string;
begin
r := RegexCreate('([\.\+\*\?\[\^\]\$\(\)\{\}\=\!\<\>\|\:])', [rcoIgnoreCase, rcoUngreedy]);
m := r.Replace(str,'\$1');
Result := m;
end;
2. HtmlSpecialChars - замена спец-символов на HTML-сущности для корректного отображения в браузере. Функция полезна для сохранения HTML-кода в DELPHI, например - генерирования отчёта в html файл.
function HtmlSpecialChars(s: string): string;
begin
s := AnsiReplaceText(s, '&', '&');
s := AnsiReplaceText(s, '"', '"');
s := AnsiReplaceText(s, '«', '«');
s := AnsiReplaceText(s, '»', '»');
s := AnsiReplaceText(s, '''', ''');
s := AnsiReplaceText(s, '<', '<');
s := AnsiReplaceText(s, '>', '>');
Result := s;
end;
3. RemoveNonPrintable - удаление “невидимых” символов в тексте. Используются регулярные выражения.
function RemoveNonPrintable(s: string): string;
var
R: IRegex;
begin
R := RegexCreate('[^\x20-\xFF]+', [rcoIgnoreCase]);
s := R.Replace(s, ' ');
R := RegexCreate('\s+', [rcoIgnoreCase]);
s := R.Replace(s, ' ');
Result := s;
end;
См. также:
stripTags для Delphi
Транслит в Delphi
Ошибка в модуле idZLibCompressorBase
Рубрики: Алгоритмы, Разное | Комментариев нет »
01.04.2010 от semen
Для работы с XML-RPC в дельфи написан отличный модуль, о котором я уже упоминал - XML-RPC в Delphi. Для работы с одним известным сервисом, предоставляющем API на XML-RPC, требуется авторизация и хранение Cookies для последующей работы. В принципе, cookies могут пригодится и для других целей в xml-rpc, покажу как я их подключил.
1. Добавил новое свойство в класс TRpcCaller:
FSessionCookies : string; // cookies :)
Сделал возможность его читать и изменять:
property SessionCookies : string read FSessionCookies write FSessionCookies;
Задаём cookies в функции
function TRpcCaller.Post(const RawData: string): string;
Непосредственно перед отправкой post запроса:
FSession.AllowCookies := true;
if FSessionCookies <> '' then
begin
CM := TidCookieManager.Create(FSession);
CC := TIdCookies.Create(CM);
Cookie := TIdCookieRFC2109.Create(CC);
Cookie.CookieText := FSessionCookies;
CM.CookieCollection.AddCookie(cookie);
end;
После выполнения запроса не забываем сохранить новые cookies, если он нам нужны:
FSessionCookies := FSession.CookieManager.CookieCollection.Items[0].CookieText
См. также:
Как определить IP-адреса компьютера из Delphi?
Удаление всех файлов из указанной папки через Delphi
Алгоритм MD5 в Delphi
Рубрики: Модули, Общее | Комментариев нет »
26.03.2010 от semen
Для защиты программ от взлома используется большое количество различных алгоритмов, все они отличаются по принципу, степени защищённости от взлома, сложности реализации и обхода. Найти информацию о любом способе защиты не составит труда. Рекомендуется использовать несколько независимых алгоритмов защиты программы, сломав один алгоритм, хакер ничего не будет знать о другой защите, которая проявит себя позже.
Одним из самых простых способов защиты программы является ограничение по сроку действия. Такая защита обычно легко снимается, поэтому не стоит серьезно на неё полагаться, однако в качестве дополнения реализовать стоит.
В качестве начального значения даты можно принимать дату компиляции программы, функция:
function GetBuildTime:TDateTime;
begin
Result:=FileDateToDateTime(PInteger(PImageNtHeaders(hInstance+DWORD(PImageDosHeader(hInstance)._lfanew)).OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_RESOURCE].VirtualAddress+hInstance+4)^);
end;
При каждом запуске необходимо сверять дату компиляции программы с текущей. Сверку лучше всего вызывать где-нибудь в неприметном месте, например при совершении программой определённых действий - рассчётов, получения данных и тому подобном. Обойти такую “защиту” довольно легко, однако лишних неприятностей добавится. Да и будет подстёгивать разработчика выпускать новые версии программы
См. также:
Получение данных из ресурсов в Delphi
Устанавливаем системную дату из Delphi
Структура папок проекта Delphi
Рубрики: Разное | Комментариев нет »
26.03.2010 от semen
Для обработки gzip/deflate часто используется модуль idZLibCompressorBase. В принципе, модуль неплохо справляется со своими функциями пока не попадутся “криво” сжатые данные. В некоторых случаях может возникнуть бесконечный цикл считывания со всеми вытекающими неприятностями. Вот ошибочный код:
procedure GotoDataStart;
var LFlags:byte;
LExtra:word;
LNullFindChar:char;
begin
AStream.Seek(3,soFromCurrent);
AStream.Read(LFlags,1);
AStream.Seek(6,soFromCurrent);
// at pos 10 now
if LFlags and $4 = $4 then begin // FEXTRA
AStream.Read(LExtra, 2);
AStream.Seek(LExtra, soFromCurrent);
end;
if LFlags and $8 = $8 then begin // FNAME
repeat
AStream.Read(LNullFindChar, 1)
until LNullFindChar=#0;
end;
if LFlags and $10 = $10 then begin // FCOMMENT
repeat
AStream.Read(LNullFindChar, 1)
until LNullFindChar=#0;
end;
if LFlags and $2 = $2 then begin // FHCRC
AStream.Seek(2, soFromCurrent); // CRC16
end;
end;
В циклах repeat может возникнуть проблема, если нет нулевого символа #0, поэтому необходимо проверять длину прочитанных байт и выходить из цикла, если прочитать не удалось:
procedure GotoDataStart;
var LFlags:byte;
LExtra:word;
LNullFindChar:char;
begin
AStream.Seek(3,soFromCurrent);
AStream.Read(LFlags,1);
AStream.Seek(6,soFromCurrent);
// at pos 10 now
if LFlags and $4 = $4 then begin // FEXTRA
AStream.Read(LExtra, 2);
AStream.Seek(LExtra, soFromCurrent);
end;
if LFlags and $8 = $8 then begin // FNAME
repeat
if AStream.Read(LNullFindChar, 1) = 0 then break;
until LNullFindChar=#0;
end;
if LFlags and $10 = $10 then begin // FCOMMENT
repeat
if AStream.Read(LNullFindChar, 1) = 0 then break;
until LNullFindChar=#0;
end;
if LFlags and $2 = $2 then begin // FHCRC
AStream.Seek(2, soFromCurrent); // CRC16
end;
end;
Циклическое считывание данных довольно часто применяется, пример показывает возможную ошибку - необходимо проверять количество прочитанных байт!
См. также:
Настоящий iconv для Delphi это возможно!
Обрабатываем HTML
Base64 в Delphi
Рубрики: Модули, Алгоритмы | Комментариев нет »
22.04.2009 от semen
И наоборот, вдогонку к предыдущему посту - зарезолвить хост по IP-адресу также не сложно:
function GetHostFromIP(sIPAddress: string): string;
var
WSAData: TWSAData;
addr : Cardinal;
lpHost1: PHostEnt;
begin
Result := '';
if WSAStartup(MakeWord(1,0), WSAData) = 0 then
begin
addr := inet_addr(PChar(sIPAddress));
lpHost1 := GetHostByAddr(@addr, sizeof(addr), AF_INET);
if lpHost1 <> nil then
Result := StrPas(lpHost1^.h_name)
else
Result := sIPAddress;
WSACleanup;
end;
end;
См. также:
Настройка потока перед запуском
Транслит в Delphi
Обрабатываем HTML
Рубрики: Сеть | Комментариев нет »
22.04.2009 от semen
Резолвинг IP-адреса по хосту в Delphi можно при помощи нехитрой функции следующего вида:
function getIPFromHost(const HostName: string): string;
type
TaPInAddr = array[0..10] of PInAddr;
PaPInAddr = ^TaPInAddr;
var
phe: PHostEnt;
pptr: PaPInAddr;
i: Integer;
GInitData: TWSAData;
begin
WSAStartup($101, GInitData);
Result := '';
phe := GetHostByName(PChar(HostName));
if phe = nil then Exit;
pPtr := PaPInAddr(phe^.h_addr_list);
i := 0;
while pPtr^[i] <> nil do
begin
Result := inet_ntoa(pptr^[i]^);
Inc(i);
end;
WSACleanup;
end;
Спонсор поста - интернет магазин 1Good, Екатеринбург.
См. также:
Как определить IP-адреса компьютера из Delphi?
Получение MAC-адреса сетевой платы
Транслит в Delphi
Рубрики: Сеть | Комментариев нет »
22.04.2009 от semen
Я думаю не секрет что в ресурсах программы можно хранить свои данные, к примеру, текстовый файл с секретными кодами доступа :). Получить данные из таких ресурсов несложно. Например, если у вас есть в ресурсах элемент MYDATA с типом RCDATA то его содержимое можно получить так:
var
pData: PChar;
dHandle: Cardinal;
...
dHandle := FindResource(hInstance, 'MYDATA', RT_RCDATA);
if dHandle <> 0 then
begin
dHandle := LoadResource(hInstance, dHandle);
if dHandle <> 0 then pData := LockResource(dHandle);
FreeResource(dHandle);
end;
См. также:
Дата компиляции для защиты программы
Настройка потока перед запуском
Ошибка в модуле idZLibCompressorBase
Рубрики: Разное, Общее | Комментариев нет »
22.04.2009 от semen
Давным-давно я выработал свою систему названий для компонентов и модулей. Система проста, название модулей начинается с двухбуквенного префикса «un», а следующая буква пишется в верхнем регистре…. к примеру, «unMain.pas». Названия компонентов также начинаются с префикса, к примеру, «fmMain» или «panSidebar». Вроде бы мелочь, а разбираться в коде гораздо проще, чем если бы были названия «Form1», «Form2» и т. п.
См. также:
Удаление http:// из урла
Сколько потребляет физической памяти ваша программа?
Что нужно учесть при написании приложения с русскоязычным интерфейсом в Delphi?
Рубрики: Разное | Комментариев нет »
22.04.2009 от semen
Для того, чтобы убрать программу Delphi из списка диспетчера задач можно воспользоваться следующим кодом:
function RegisterServiceProcess(dwProcessID, dwType: Integer): Integer; stdcall; external 'KERNEL32.DLL';
...
implementation
...
procedure TForm1.Button1Click(Sender: TObject);
begin
if not (csDesigning in ComponentState) then
RegisterServiceProcess(GetCurrentProcessID, 1);
end;
См. также:
Недокументированная функция MessageBoxTimeOut
Настоящий iconv для Delphi это возможно!
Получение списка всех сетевых дисков из Delphi
Рубрики: Алгоритмы | Комментариев нет »
12.04.2009 от semen
Да, да и дату и время можно поменять из своей программы, без использования стандартных возможностей Windows. Предлагаю вашему вниманию функцию выполняющее данное действие. У функции единственный параметр TDateTime, определяющий какое время и дату требуется установить.
procedure SetupSystemTime(dt: TDateTime);
var vsys : _SYSTEMTIME;
vYear, vMonth, vDay, vHour, vMin, vSec, vMm : Word;
begin
DecodeDate(dt, vYear, vMonth, vDay);
DecodeTime(dt, vHour, vMin, vSec, vMm);
vMm := 0;
vsys.wYear := vYear;
vsys.wMonth := vMonth;
vsys.wDay := vDay;
vsys.wHour := ( vHour - 2 );
vsys.wMinute := vMin;
vsys.wSecond := vSec;
vsys.wMilliseconds := vMm;
vsys.wDayOfWeek := DayOfWeek( Trunc(dtpDate.Date) );
SetSystemTime( vsys );
end;
См. также:
Получение времени по Гринвичу в Delphi
Преобразуем Unix Timestamp в TDateTime
Дата компиляции для защиты программы
Рубрики: Система, Общее | Комментариев нет »
12.04.2009 от semen
Конечно, для качественного преобразования кодировок я бы порекомендовал подключить libiconv.dll и юзать iconv, но бывают такие программы, где кроме транслитерации больше ничего не требуется. В таких случаях была бы удобна простая функция для транслита:
function Translit(s: string): string;
const
rus: string = 'абвгдеёжзийклмнопрстуфхцчшщьыъэюяАБВГДЕЁЖЗИЙКЛМНОПРСТУФХЦЧШЩЬЫЪЭЮЯ';
lat: array[1..66] of string = ('a', 'b', 'v', 'g', 'd', 'e', 'yo', 'zh', 'z', 'i', 'y', 'k', 'l', 'm', 'n', 'o', 'p', 'r', 's', 't', 'u', 'f', 'kh', 'ts', 'ch', 'sh', 'shch', '''', 'y', '''', 'e', 'yu', 'ya', 'A', 'B', 'V', 'G', 'D', 'E', 'Yo', 'Zh', 'Z', 'I', 'Y', 'K', 'L', 'M', 'N', 'O', 'P', 'R', 'S', 'T', 'U', 'F', 'Kh', 'Ts', 'Ch', 'Sh', 'Shch', '''', 'Y', '''', 'E', 'Yu', 'Ya');
var
p, i, l: integer;
begin
Result := '';
l := Length(s);
for i := 1 to l do
begin
p := Pos(s[i], rus);
if p<1 then Result := Result + s[i] else Result := Result + lat[p];
end;
end;
Спонсором поста является бюро по переводу технической документации Bues.ru.
См. также:
Обрабатываем HTML
Реализация функции Explode в Delphi
Удаление http:// из урла
Рубрики: Разное, Общее | Комментариев нет »
12.04.2009 от semen
Оказывается в WinAPI есть и такая функция, вывод окна сообщения с действием по таймауту. Вроде бы все тривиально, но готов биться о заклад, что мало кто в курсе существования данной функции. К слову, это закономерно, с учетом того что для использования функции ее необходимо экспортировать. Применение данной функции похоже на обычный MessageBox, с небольшой лишь разницей:
// описываем и экспортируем функцию
const
MB_TIMEDOUT = 32000;
function MessageBoxTimeOut(hWnd: HWND; lpText: PChar; lpCaption: PChar; uType: UINT; wLanguageId: WORD; dwMilliseconds: DWORD): Integer; stdcall; external user32 name 'MessageBoxTimeoutA';
...
procedure TForm1.Button1Click(Sender: TObject) ;
var
iRet: Integer;
iFlags: Integer;
begin
iFlags := MB_OK or MB_SETFOREGROUND or MB_SYSTEMMODAL or MB_ICONINFORMATION;
MessageBoxTimeout(Application.Handle, 'Test a timeout of 2 seconds.', 'MessageBoxTimeout Test', iFlags, 0, 2000) ;
iFlags := MB_YESNO or MB_SETFOREGROUND or MB_SYSTEMMODAL or MB_ICONINFORMATION;
iRet := MessageBoxTimeout(Application.Handle, 'Test a timeout of 5 seconds.', 'MessageBoxTimeout Test', iFlags, 0, 5000) ;
case iRet of
IDYES:
ShowMessage('Да') ;
IDNO:
ShowMessage('Нет') ;
MB_TIMEDOUT:
ShowMessage('Таймаут) ;
end;
end;
См. также:
Как программно очистить корзину Windows?
Включаем режим ожидания у монитора из приложения Delphi
Реализация функции Explode в Delphi
Рубрики: Разное, Система | Комментариев нет »
12.04.2009 от semen
Чтобы получить значение (в байтах) потребляемой физической памяти (без учета своп-файла), можно воспользоваться функцией GetHeadStatus. К примеру, вот так:
procedure TForm1.Button1Click(Sender: TObject);
var
hs: THeapStatus;
begin
hs := GetHeapStatus();
showmessage(IntToStr(i.TotalUncommitted ));
end;
Моя простая программа из одной формы и кнопки «съедает» около 1 Мб памяти.
См. также:
Определение семейства версии Windows в Delphi
Недокументированная функция MessageBoxTimeOut
Настройка потока перед запуском
Рубрики: Система | Комментариев нет »
12.04.2009 от semen
Нередко требуется выполнить проверку наличия той или иной версии .NET Framework на компьютере пользователя. Узнать точную версию и проверить ее наличие можно при помощи приведенной ниже функции, первый параметр которой - это глубина поиска (максимальное допустимое число найденных версий). Во второй параметр возвращается точное значение версии.
function EnumInstalledDotNet(Index: Integer; out VersionName: String):
Boolean;
var
hkey: Windows.HKEY;
hsubkey: Windows.HKEY;
I: Cardinal;
J: Cardinal;
NameBuf: array[0..MAX_PATH] of Char;
CNameBuf: Cardinal;
lwt: TFileTime;
vt: DWORD;
AnyFound: Boolean;
begin
Result := False;
VersionName := '';
if ERROR_SUCCESS = RegOpenKeyEx(HKEY_LOCAL_MACHINE,
PChar('SOFTWARE\Microsoft\.NETFramework\policy'), 0,
KEY_ENUMERATE_SUB_KEYS, hkey) then
try
I := 0;
while True do
begin
AnyFound := False;
CNameBuf := MAX_PATH + 1;
if ERROR_SUCCESS <> RegEnumKeyEx(hkey, I, @NameBuf[0], CNameBuf,nil, nil, nil, @lwt) then
begin
Break;
end;
if (NameBuf[0] = 'v') and (NameBuf[1] in ['1'..'9']) then
begin
VersionName := String(NameBuf);
if ERROR_SUCCESS = RegOpenKeyEx(hkey, @NameBuf[0], 0,KEY_QUERY_VALUE, hsubkey) then
try
J := 0;
while true do
begin
CNameBuf := MAX_PATH + 1;
if ERROR_SUCCESS <> RegEnumValue(hsubkey, J, @NameBuf[0],CNameBuf, nil, @vt, nil, nil) then
begin
Break;
end;
if (vt = REG_SZ) and (NameBuf[0] <> #0) then
begin
VersionName := VersionName + '.' + String(NameBuf);
AnyFound := True;
Break;
end;
Inc(J);
end;
finally
RegCloseKey(hsubkey);
end;
end;
Inc(I);
if AnyFound then
begin
if Index = 0 then
begin
Result := True;
Break;
end;
Dec(Index);
end;
end;
finally
RegCloseKey(hkey);
end;
end;
См. также:
Функция сравнения версий программы
Ошибка в модуле idZLibCompressorBase
Резолвинг хоста по IP-адресу в Delphi
Рубрики: Система | Комментариев нет »
06.04.2009 от semen
Открыть главную виндовую менюшку можно, послав соответствующее сообщение при помощи функции SendMessage:
SendMessage(Form1.Handle, WM_SYSCOMMAND, SC_TASKLIST, 0);
Form1 - это форма нашего приложения. На самом деле, как я понимаю, можно указать хэндл любого окна.
См. также:
Как проверить состояние выпадающего меню у TCombobox?
Программная прокрутка TMemo
Масштабирование форм в Delphi
Рубрики: Система | Комментариев нет »
06.04.2009 от semen
Для получения переменных среды Windows из Delphi ничего придумывать не нужно. Все уже реализовано и упаковано вместе с Windows :). Список переменных в виде многострочного текста можно получить при помощи соответствующей функции:
showmessage(Windows.GetEnvironmentStrings);
См. также:
Windows Uptime в Delphi
Вызов элемента панели управления из Delphi
Сколько потребляет физической памяти ваша программа?
Рубрики: Система | Комментариев нет »
06.04.2009 от semen
Да, да, буфер обмена позволяет копировать, переносить, вставлять и файлы в том числе, достаточно вспомнить «Проводник» Windows, чтобы поверить в этом. Так вот, вопрос в том, как получить находящиеся в буфере обмена файлы, а если быть точным их имена (пути к ним)? А, достаточно, просто:
uses clipbrd, shellapi;
...
function getFilesFromClipboard(): string;
var
f: THandle;
buffer: Array [0..MAX_PATH] of Char;
i, numFiles: Integer;
begin
Result := '';
Clipboard.Open;
try
f:= Clipboard.GetAsHandle( CF_HDROP ) ;
If f <> 0 Then Begin
numFiles := DragQueryFile( f, $FFFFFFFF, nil, 0 ) ;
for i:= 0 to numfiles - 1 do begin
buffer[0] := #0;
DragQueryFile( f, i, buffer, sizeof(buffer)) ;
Result := Result + buffer + ',';
end;
end;
finally
Clipboard.close;
end;
end;
См. также:
Удаление всех файлов из указанной папки через Delphi
Как скачать файл из сети?
Как определить IP-адреса компьютера из Delphi?
Рубрики: Алгоритмы, Система | Комментариев нет »
06.04.2009 от semen
В догонку к предыдущему посту, привожу алгоритм проверки наличия запущенного дебаггера SoftICE. SoftICE, кстати, очень популярен среди хакеров, что вообщем-то не мешает опытным спецам без труда обходить и подобные проверки.
function IsDebuggerPresent2(): Boolean;
var
hFile: THandle;
begin
hFile := CreateFileA('.NTICE', GENERIC_READ or GENERIC_WRITE,
FILE_SHARE_READ or FILE_SHARE_WRITE, nil, OPEN_EXISTING,
FILE_ATTRIBUTE_NORMAL, 0);
if (hFile <> INVALID_HANDLE_VALUE) then
begin
CloseHandle(hFile);
Result := True;
exit;
end;
Result := False;
hFile := CreateFileA('.SICE', GENERIC_READ or GENERIC_WRITE,
FILE_SHARE_READ or FILE_SHARE_WRITE, nil, OPEN_EXISTING,
FILE_ATTRIBUTE_NORMAL, 0);
if (hFile <> INVALID_HANDLE_VALUE) then
begin
CloseHandle(hFile);
Result := True;
exit;
end;
end;
См. также:
Запуск внешних приложений из Delphi с ожиданием их завершения
Проверка наличия запущенного дебаггера
Называем компоненты и модули правильно
Рубрики: Алгоритмы, Система | Комментариев нет »