Гараж Delphi




Алгоритмы и функции для эффективной разработки приложений в среде программирования Delphi

Настройка потока перед запуском

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];

И в самом потоке можем обращаться непосредственно по адресу:

s := MemAddr^.field1;

При таком подходе не происходит дублирования данных в памяти.

См. также:
Сколько потребляет физической памяти ваша программа?
Ограничение количества потоков
Вызов элемента панели управления из 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

Рубрики: Алгоритмы, Сеть, Общее | Комментариев нет »

Обрабатываем 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, '&', '&amp;');
  s := AnsiReplaceText(s, '"', '&quot;');
  s := AnsiReplaceText(s, '«', '&laquo;');
  s := AnsiReplaceText(s, '»', '&raquo;');
  s := AnsiReplaceText(s, '''', '&#039;');
  s := AnsiReplaceText(s, '<', '&lt;');
  s := AnsiReplaceText(s, '>', '&gt;');
 
  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

Рубрики: Алгоритмы, Разное | Комментариев нет »

Подключаем cookies для XML-RPC

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

Рубрики: Разное | Комментариев нет »

Ошибка в модуле idZLibCompressorBase

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

Рубрики: Модули, Алгоритмы | Комментариев нет »

Резолвинг хоста по IP-адресу в 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

Рубрики: Сеть | Комментариев нет »

Резолвинг IP-адреса по хосту в Delphi

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

Рубрики: Сеть | Комментариев нет »

Получение данных из ресурсов в 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

Рубрики: Алгоритмы | Комментариев нет »

Устанавливаем системную дату из 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
Дата компиляции для защиты программы

Рубрики: Система, Общее | Комментариев нет »

Транслит в Delphi

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:// из урла

Рубрики: Разное, Общее | Комментариев нет »

Недокументированная функция MessageBoxTimeOut

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
Настройка потока перед запуском

Рубрики: Система | Комментариев нет »

Версия .NET Framework в системе

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

Рубрики: Система | Комментариев нет »

Программное открытие меню «Пуск» из Delphi

06.04.2009 от semen

Открыть главную виндовую менюшку можно, послав соответствующее сообщение при помощи функции SendMessage:

SendMessage(Form1.Handle, WM_SYSCOMMAND, SC_TASKLIST, 0);

Form1 - это форма нашего приложения. На самом деле, как я понимаю, можно указать хэндл любого окна.

См. также:
Как проверить состояние выпадающего меню у TCombobox?
Программная прокрутка TMemo
Масштабирование форм в Delphi

Рубрики: Система | Комментариев нет »

Получение переменных среды из 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?

Рубрики: Алгоритмы, Система | Комментариев нет »

Проверка наличия запущенного дебаггера в Delphi, ч. 2

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 с ожиданием их завершения
Проверка наличия запущенного дебаггера
Называем компоненты и модули правильно

Рубрики: Алгоритмы, Система | Комментариев нет »

« Раньше