Delphi - база знаний

         

Получаем имена ODBC-источников


Получаем имена ODBC-источников




usesRegistry; 

procedure TForm1.GetDataSourceNames(System: Boolean); 
var 
  reg: TRegistry; 
begin 
  ListBox1.Items.Clear; 

  reg := TRegistry.Create; 
  try 
    if System then 
      reg.RootKey := HKEY_LOCAL_MACHINE 
    else 
      reg.RootKey := HKEY_CURRENT_USER; 



    if reg.OpenKey('\Software\ODBC\ODBC.INI\ODBC Data Sources', False) then 
    begin 
      reg.GetValueNames(ListBox1.Items); 
    end; 

  finally 
    reg.CloseKey; 
    FreeAndNil(reg); 
  end; 
end; 

procedure TForm1.Button1Click(Sender: TObject); 
begin 
  //Системные DSNs 
  GetDataSourceNames(True); 
  //Пользовательские DSNs 
  GetDataSourceNames(False); 
end;


Взято из





Получение дескриптора ODBC соединения


Получение дескриптора ODBC соединения




Я как-то обращал ваше внимание на трудность получения дескриптора ODBC соединения посредством DBE. После тесного общения со службой поддержки Borland, я наконец нашел решение как это сделать. Вот этот код:

unitGetprop;

interface

uses
  SysUtils, WinTypes, WinProcs, Messages, Classes, Graphics, Controls,
  Forms, Dialogs, Grids, DBGrids, StdCtrls, DB, DBTables,
  DBIProcs, DBITypes, DBIErrs;

type
  TForm1 = class(TForm)
    Table1: TTable;
    DataSource1: TDataSource;
    Button1: TButton;
    Button2: TButton;
    DBGrid1: TDBGrid;
    Edit1: TEdit;
    procedure Button1Click(Sender: TObject);
    procedure Button2Click(Sender: TObject);
  private
{ Private declarations }
  public
{ Public declarations }
  end;

var
  Form1: TForm1;

implementation

{$R *.DFM}

procedure TForm1.Button1Click(Sender: TObject);
begin
  Table1.active := True;
end;

procedure TForm1.Button2Click(Sender: TObject);
var
  hTmpDB: hDBIDb;
  iLen: word;

begin
  Check(DbiGetProp(hDBIObj(Table1.DBhandle), dbNATIVEHNDL, @hTmpDB, sizeof(hDBIDb), iLen));
  Edit1.text := inttostr(longint(htmpdb));
end;

end

- Chris Fioravanti

Взято из

Советов по Delphi от


Сборник Kuliba






Получение файла из сети


Получение файла из сети



(Перевод одноимённой статьи с сайта delphi.about.com )

Обычно при разработке приложений, которые планируется в дальнейшем обновлять и усовершенствовать, основные модули хранятся в виде пакетов (Package) или библиотек DLL. В настоящее время Internet предоставляет возможность без особых усилий осуществлять обновление этих модулей. Поэтому добавление к Вашему приложению функции авто-обновления, является наилучшим способом для обновления приложения.

Давайте посмотрим, как реализовывается данный механизм в любом FTP приложении.

Delphi предоставляет нам полный доступ к WinInet API (wininet.pas), который можно использовать для соединения и получения файлов с веб-сайта, который использует либо Hypertext Transfer Protocol (HTTP) либо File Transfer Protocol (FTP). Например, мы можем использовать функции из WinInet API для: добавления FTP браузера в любое приложение, создания приложения, которое автоматически скачивает файлы с общедоступных FTP серверов или поиска Internet сайтов, ссылающихся на графику и скачивать только графику.

Функция GetInetFile

uses Wininet;

function GetInetFile
(const fileURL, FileName: String): boolean;
const BufferSize = 1024;
var
  hSession, hURL: HInternet;
  Buffer: array[1..BufferSize] of Byte;
  BufferLen: DWORD;
  f: File;
  sAppName: string;
begin
 Result:=False;
 sAppName := ExtractFileName(Application.ExeName);
 hSession := InternetOpen(PChar(sAppName),
                INTERNET_OPEN_TYPE_PRECONFIG,
               nil, nil, 0);
 try
  hURL := InternetOpenURL(hSession,
            PChar(fileURL),
            nil,0,0,0);
  try
   AssignFile(f, FileName);
   Rewrite(f,1);
   repeat
    InternetReadFile(hURL, @Buffer,
                     SizeOf(Buffer), BufferLen);
    BlockWrite(f, Buffer, BufferLen)
   until BufferLen = 0;
   CloseFile(f);
   Result:=True;
  finally
   InternetCloseHandle(hURL)
  end
 finally
  InternetCloseHandle(hSession)
 end
end;

Обратите внимание: Чтобы обеспечить некоторую визуальную обратную связь для пользователя, Вы можете добавить строчку наподобие FlashWindow(Application.Handle,True) в тело блока "повторить/до тех пор" (repeat/until). Вызов FlashWindow API высвечивает заголовок Вашего имени приложений в панели задач.

Использование
Для вызова функции GetInetFile можно использовать следующий код:

var FileOnNet, LocalFileName: string
begin
 FileOnNet:=
  'http://delphi.about.com/library/forminbpl.zip';
 LocalFileName:='File Downloaded From the Net.zip'

 if GetInetFile(FileOnNet,LocalFileName)=True then
  ShowMessage('Download successful')
 else
  ShowMessage('Error in file download')
end;

Данный код запрашивает файл 'forminbpl.zip' с сайта, скачивает его, и сохраняет его как 'File Downloaded From the Net.zip'.

Обратите внимание: В зависимости от версии Delphi, Вы можете использовать различные компоненты, которые можно найти на Интернет страницах, посвещённых VCL и, которые можно использовать для упрощения создания приложений (например FTP компонент, необходимый для TNMFTP, находящийся на странице FastNet VCL).

Взято с Исходников.ru



Получение Gaussian Blur


Получение Gaussian Blur




Автор: Den is Com

Ну вот, добрались и до фильтров. В неформальных испытаниях этот код оказался вдвое быстрее, чем это делает Adobe Photoshop. Мне кажется есть множество фильтров, которые можно переделать или оптимизировать для быстроты обработки изображений.

Ядро гауссовой функции exp(-(x^2 + y^2)) есть разновидность формулы f(x)*g(y), которая означает, что мы можем выполнить двумерную свертку, делая последовательность одномерных сверток - сначала мы свертываем каждую строчку изображения, затем - каждую колонку. Хороший повод для ускорения (N^2 становится N*2). Любая свертка требует некоторого место для временного хранения результатов - ниже в коде программа BlurRow как раз распределяет и освобождает память для каждой колонки. Вероятно это должно ускорить обработку изображения, правда не ясно насколько.

Поле "size" в записи TKernel ограничено значением 200. Фактически, если вы хотите использовать еще больший радиус, это не вызовет проблем - попробуйте со значениями radius = 3, 5 или другими. Для большого количества данных методы свертки на поверку оказываются эффективнее преобразований Фурье (как показали опыты).

Еще один комментарий все же необходим: гауссово размывание имеет одно магическое свойство, а именно - вы можете сначала размыть каждую строчку (применить фильтр), затем каждую колонку - фактически получается значительно быстрее, чем двумерная свертка.

Во всяком случае вы можете сделать так:



unitGBlur2;

interface

uses Windows, Graphics;

type

  PRGBTriple = ^TRGBTriple;
  TRGBTriple = packed record
    b: byte; //легче для использования чем типа rgbtBlue...
    g: byte;
    r: byte;
  end;

  PRow = ^TRow;
  TRow = array[0..1000000] of TRGBTriple;

  PPRows = ^TPRows;
  TPRows = array[0..1000000] of PRow;

const
  MaxKernelSize = 100;

type

  TKernelSize = 1..MaxKernelSize;

  TKernel = record
    Size: TKernelSize;
    Weights: array[-MaxKernelSize..MaxKernelSize] of single;
  end;
  //идея заключается в том, что при использовании TKernel мы игнорируем
  //Weights (вес), за исключением Weights в диапазоне -Size..Size.

procedure GBlur(theBitmap: TBitmap; radius: double);

implementation

uses SysUtils;

procedure MakeGaussianKernel(var K: TKernel; radius: double;

  MaxData, DataGranularity: double);
//Делаем K (гауссово зерно) со среднеквадратичным отклонением = radius.
//Для текущего приложения мы устанавливаем переменные MaxData = 255,
//DataGranularity = 1. Теперь в процедуре установим значение
//K.Size так, что при использовании K мы будем игнорировать Weights (вес)
//с наименее возможными значениями. (Малый размер нам на пользу,
//поскольку время выполнения напрямую зависит от
//значения K.Size.)
var
  j: integer;
  temp, delta: double;
  KernelSize: TKernelSize;
begin

  for j := Low(K.Weights) to High(K.Weights) do
  begin
    temp := j / radius;
    K.Weights[j] := exp(-temp * temp / 2);
  end;

  //делаем так, чтобы sum(Weights) = 1:

  temp := 0;
  for j := Low(K.Weights) to High(K.Weights) do
    temp := temp + K.Weights[j];
  for j := Low(K.Weights) to High(K.Weights) do
    K.Weights[j] := K.Weights[j] / temp;

  //теперь отбрасываем (или делаем отметку "игнорировать"
  //для переменной Size) данные, имеющие относительно небольшое значение -
  //это важно, в противном случае смазавание происходим с малым радиусом и
  //той области, которая "захватывается" большим радиусом...

  KernelSize := MaxKernelSize;
  delta := DataGranularity / (2 * MaxData);
  temp := 0;
  while (temp < delta) and (KernelSize > 1) do
  begin
    temp := temp + 2 * K.Weights[KernelSize];
    dec(KernelSize);
  end;

  K.Size := KernelSize;

  //теперь для корректности возвращаемого результата проводим ту же
  //операцию с K.Size, так, чтобы сумма всех данных была равна единице:

  temp := 0;
  for j := -K.Size to K.Size do
    temp := temp + K.Weights[j];
  for j := -K.Size to K.Size do
    K.Weights[j] := K.Weights[j] / temp;

end;

function TrimInt(Lower, Upper, theInteger: integer): integer;
begin

  if (theInteger <= Upper) and (theInteger >= Lower) then
    result := theInteger
  else if theInteger > Upper then
    result := Upper
  else
    result := Lower;
end;

function TrimReal(Lower, Upper: integer; x: double): integer;
begin

  if (x < upper) and (x >= lower) then
    result := trunc(x)
  else if x > Upper then
    result := Upper
  else
    result := Lower;
end;

procedure BlurRow(var theRow: array of TRGBTriple; K: TKernel; P: PRow);
var
  j, n, LocalRow: integer;
  tr, tg, tb: double; //tempRed и др.

  w: double;
begin

  for j := 0 to High(theRow) do

  begin
    tb := 0;
    tg := 0;
    tr := 0;
    for n := -K.Size to K.Size do
    begin
      w := K.Weights[n];

      //TrimInt задает отступ от края строки...

      with theRow[TrimInt(0, High(theRow), j - n)] do
      begin
        tb := tb + w * b;
        tg := tg + w * g;
        tr := tr + w * r;
      end;
    end;
    with P[j] do
    begin
      b := TrimReal(0, 255, tb);
      g := TrimReal(0, 255, tg);
      r := TrimReal(0, 255, tr);
    end;
  end;

  Move(P[0], theRow[0], (High(theRow) + 1) * Sizeof(TRGBTriple));
end;

procedure GBlur(theBitmap: TBitmap; radius: double);
var
  Row, Col: integer;
  theRows: PPRows;
  K: TKernel;
  ACol: PRow;
  P: PRow;
begin
  if (theBitmap.HandleType <> bmDIB) or (theBitmap.PixelFormat <> pf24Bit) then

    raise
      exception.Create('GBlur может работать только с 24-битными изображениями');

  MakeGaussianKernel(K, radius, 255, 1);
  GetMem(theRows, theBitmap.Height * SizeOf(PRow));
  GetMem(ACol, theBitmap.Height * SizeOf(TRGBTriple));

  //запись позиции данных изображения:
  for Row := 0 to theBitmap.Height - 1 do

    theRows[Row] := theBitmap.Scanline[Row];

  //размываем каждую строчку:
  P := AllocMem(theBitmap.Width * SizeOf(TRGBTriple));
  for Row := 0 to theBitmap.Height - 1 do

    BlurRow(Slice(theRows[Row]^, theBitmap.Width), K, P);

  //теперь размываем каждую колонку
  ReAllocMem(P, theBitmap.Height * SizeOf(TRGBTriple));
  for Col := 0 to theBitmap.Width - 1 do
  begin
    //- считываем первую колонку в TRow:

    for Row := 0 to theBitmap.Height - 1 do
      ACol[Row] := theRows[Row][Col];

    BlurRow(Slice(ACol^, theBitmap.Height), K, P);

    //теперь помещаем обработанный столбец на свое место в данные изображения:

    for Row := 0 to theBitmap.Height - 1 do
      theRows[Row][Col] := ACol[Row];
  end;

  FreeMem(theRows);
  FreeMem(ACol);
  ReAllocMem(P, 0);
end;

end.

 


Должно работать, если только вы не удалите некоторый код вместе с глупыми коментариями. Для примера: 



procedure TForm1.Button1Click(Sender: TObject);
var
  b: TBitmap;
begin
  if not openDialog1.Execute then
    exit;

  b := TBitmap.Create;
  b.LoadFromFile(OpenDialog1.Filename);
  b.PixelFormat := pf24Bit;
  Canvas.Draw(0, 0, b);
  GBlur(b, StrToFloat(Edit1.text));
  Canvas.Draw(b.Width, 0, b);
  b.Free;
end;




Имейте в виду, что 24-битные изображения при системной 256-цветной палитре требуют некоторых дополнительных хитростей, так как эти изображения не только выглядят в таком случае немного "странными", но и серьезно нарушают работу фильтра.

Взято из




Гауссово размывание (Gaussian Blur) в Delphi (продолжение) - Создание тени у метки


Автор: Den is Com

Данный метод позволяет создавать тень у текстовых меток TLabel. Не требует лазить в Photoshop и что-то ваять там - тень рисуется динамически, поэтому и объём программы не раздувает. Создание тени присходит в фоновом режиме, во время "простоя" процессора.

Пример использования:



ShowFade(CaptionLabel);
//или
ShowFadeWithParam(CaptionLabel,3,3,2,clGray);




Blur.pas



unitblur;

interface

uses

  Classes, graphics, stdctrls, gblur2;
const
  add_width = 4;

  add_height = 5;
type

  TBlurThread = class(TThread)
  private
    { Private declarations }
    text_position: Integer;
    FadeLabel: TLabel;
    Temp_Bitmap: TBitmap;

    procedure ShowBlur;
    procedure SetSize;
  protected
    F_width, F_X, F_Y: Integer;
    F_color: TColor;
    procedure Execute; override;
  public

    constructor Create(Sender: TLabel; Fade_width: integer; Fade_X: Integer;
      Fade_Y: Integer; Fade_color: TColor);
    destructor Destroy;

  end;
procedure ShowFade(Sender: TLabel);
procedure ShowFadeWithParam(Sender: TLabel; Fade_width: integer; Fade_X:
  Integer; Fade_Y: Integer; Fade_color: TColor);

implementation

procedure ShowFadeWithParam(Sender: TLabel; Fade_width: integer; Fade_X:
  Integer; Fade_Y: Integer; Fade_color: TColor);
var
  SlowThread: TBlurThread;
begin
  SlowThread := TBlurThread.Create(Sender, Fade_width, Fade_X, Fade_Y,
    Fade_color);
  SlowThread.Priority := tpIdle;
  SlowThread.Resume;
end;

procedure ShowFade;
var
  SlowThread: TBlurThread;
begin
  SlowThread := TBlurThread.Create(Sender, 3, 3, 3, clBlack);
  SlowThread.Priority := tpIdle;
  //SlowThread.Priority:=tpLowest;
  //SlowThread.Priority:=tpTimeCritical;
  SlowThread.Resume;
end;

constructor TBlurThread.Create(Sender: TLabel; Fade_width: integer; Fade_X:
  Integer; Fade_Y: Integer; Fade_color: TColor);
begin
  Temp_Bitmap := TBitmap.Create;
  Temp_Bitmap.Canvas.Font := Sender.Font;
  FadeLabel := Sender;
  F_width := Fade_width;
  F_X := Fade_X;
  F_Y := Fade_Y;
  F_color := Fade_color;
  inherited Create(True);
end;

destructor TBlurThread.Destroy;
begin
  Temp_Bitmap.Free;
  inherited Destroy;
end;

procedure TBlurThread.ShowBlur;
begin
  FadeLabel.Canvas.Draw(text_position + F_X, F_Y, Temp_Bitmap);
  FadeLabel.Canvas.TextOut(text_position, 0, FadeLabel.Caption);
end;

procedure TBlurThread.SetSize;
begin
  if FadeLabel.Width < (Temp_Bitmap.Canvas.TextWidth(FadeLabel.Caption) + F_width
    + F_X {add_width}) then
  begin
    FadeLabel.Width := Temp_Bitmap.Canvas.TextWidth(FadeLabel.Caption) + F_width
      + F_X {add_width};
    FadeLabel.Tag := 2;
  end
  else
    FadeLabel.Tag := 0;

  if FadeLabel.Height < (Temp_Bitmap.Canvas.TextHeight(FadeLabel.Caption) +
    F_width + F_Y {add_height}) then
  begin
    FadeLabel.Height := Temp_Bitmap.Canvas.TextHeight(FadeLabel.Caption) +
      F_width + F_Y {add_height};
    FadeLabel.Tag := 1;
  end
  else if FadeLabel.Tag <> 2 then
    FadeLabel.Tag := 0;

end;

{ TBlurThread }

procedure TBlurThread.Execute;
begin

  { Place thread code here }
  Synchronize(SetSize);

  if FadeLabel.Tag = 0 then
  begin
    Temp_Bitmap.Width := FadeLabel.Width;
    Temp_Bitmap.Height := FadeLabel.Height;
    Temp_Bitmap.Canvas.Brush.Color := FadeLabel.Color;
    Temp_Bitmap.Canvas.FillRect(FadeLabel.ClientRect);
    Temp_Bitmap.Canvas.Font.Color := F_color; //clBlack

    if FadeLabel.Alignment = taRightJustify then
      text_position := FadeLabel.Width -
        Temp_Bitmap.Canvas.TextWidth(FadeLabel.Caption) - F_width - F_X {add_width}
    else if FadeLabel.Alignment = taCenter then
      text_position := (FadeLabel.Width -
        Temp_Bitmap.Canvas.TextWidth(FadeLabel.Caption) - F_width - F_X
        {add_width}) div 2
    else
      text_position := 0;

    Temp_Bitmap.Canvas.TextOut(0, 0, FadeLabel.Caption);
    Temp_Bitmap.PixelFormat := pf24Bit;
    GBlur(Temp_Bitmap, F_width);
    //Temp_Bitmap.SaveToFile('a.bmp');
    Synchronize(ShowBlur);
  end;

end;

end.



Взято из






The gaussian kernel exp(-(x^2 + y^2)) is of the form f(x)*g(y), which means that you can perform a two-dimensional convolution by doing a sequence of one-dimensional convolutions - first you convolve each row and then each column. This is much faster (an N^2 becomes an N*2). Any convolution requires some temporary storage - below the BlurRow routine allocates and frees the memory, meaning that it gets allocated and freed once for each row. Probably changing this would speed it up some, it's not entirely clear how much.

The kernel "size" is limited to 200 entries. In fact if you use radius anything like that large it will take forever - you want to try this with a radius = 3 or 5 or something. For a kernel with that many entries a straight convolution is the thing to do, while when the kernel gets much larger Fourier transform techniques will be better (I couldn't say what the actual cutoff is.)

One comment that needs to be made is that a gaussian blur has the magical property that you can blur each row one by one and then blur each column - this is much faster than an actual 2-d convolution.

Anyway, you can do this:


unit GBlur2;

interface

uses
  Windows, Graphics;

type
  PRGBTriple = ^TRGBTriple;
  TRGBTriple = packed record
    b: byte; {easier to type than rgbtBlue}
    g: byte;
    r: byte;
  end;
  PRow = ^TRow;
  TRow = array[0..1000000] of TRGBTriple;
  PPRows = ^TPRows;
  TPRows = array[0..1000000] of PRow;

const
  MaxKernelSize = 100;

type
  TKernelSize = 1..MaxKernelSize;
  TKernel = record
    Size: TKernelSize;
    Weights: array[-MaxKernelSize..MaxKernelSize] of single;
  end;
  {the idea is that when using a TKernel you ignore the Weights except
  for Weights in the range -Size..Size.}

procedure GBlur(theBitmap: TBitmap; radius: double);

implementation

uses
  SysUtils;

procedure MakeGaussianKernel(var K: TKernel; radius: double; MaxData, DataGranularity: double);
{makes K into a gaussian kernel with standard deviation = radius. For the current application
you set MaxData = 255 and DataGranularity = 1. Now the procedure sets the value of K.Size so
that when we use K we will ignore the Weights that are so small they can't possibly matter. (Small
Size is good because the execution time is going to be propertional to K.Size.)}
var
  j: integer;
  temp, delta: double;
  KernelSize: TKernelSize;
begin
  for j := Low(K.Weights) to High(K.Weights) do
  begin
    temp := j / radius;
    K.Weights[j] := exp(-temp * temp / 2);
  end;
  {now divide by constant so sum(Weights) = 1:}
  temp := 0;
  for j := Low(K.Weights) to High(K.Weights) do
    temp := temp + K.Weights[j];
  for j := Low(K.Weights) to High(K.Weights) do
    K.Weights[j] := K.Weights[j] / temp;
  {now discard (or rather mark as ignorable by setting Size) the entries that are too small to matter.
  This is important, otherwise a blur with a small radius will take as long as with a large radius...}
  KernelSize := MaxKernelSize;
  delta := DataGranularity / (2 * MaxData);
  temp := 0;
  while (temp < delta) and (KernelSize > 1) do
  begin
    temp := temp + 2 * K.Weights[KernelSize];
    dec(KernelSize);
  end;
  K.Size := KernelSize;
  {now just to be correct go back and jiggle again so the sum of the entries we'll be using is exactly 1}
  temp := 0;
  for j := -K.Size to K.Size do
    temp := temp + K.Weights[j];
  for j := -K.Size to K.Size do
    K.Weights[j] := K.Weights[j] / temp;
end;

function TrimInt(Lower, Upper, theInteger: integer): integer;
begin
  if (theInteger <= Upper) and (theInteger >= Lower) then
    result := theInteger
  else if theInteger > Upper then
    result := Upper
  else
    result := Lower;
end;

function TrimReal(Lower, Upper: integer; x: double): integer;
begin
  if (x < upper) and (x >= lower) then
    result := trunc(x)
  else if x > Upper then
    result := Upper
  else
    result := Lower;
end;

procedure BlurRow(var theRow: array of TRGBTriple; K: TKernel; P: PRow);
var
  j, n, LocalRow: integer;
  tr, tg, tb: double; {tempRed, etc}
  w: double;
begin
  for j := 0 to High(theRow) do
  begin
    tb := 0;
    tg := 0;
    tr := 0;
    for n := -K.Size to K.Size do
    begin
      w := K.Weights[n];
      {the TrimInt keeps us from running off the edge of the row...}
      with theRow[TrimInt(0, High(theRow), j - n)] do
      begin
        tb := tb + w * b;
        tg := tg + w * g;
        tr := tr + w * r;
      end;
    end;
    with P[j] do
    begin
      b := TrimReal(0, 255, tb);
      g := TrimReal(0, 255, tg);
      r := TrimReal(0, 255, tr);
    end;
  end;
  Move(P[0], theRow[0], (High(theRow) + 1) * Sizeof(TRGBTriple));
end;

procedure GBlur(theBitmap: TBitmap; radius: double);
var
  Row, Col: integer;
  theRows: PPRows;
  K: TKernel;
  ACol: PRow;
  P: PRow;
begin
  if (theBitmap.HandleType <> bmDIB) or (theBitmap.PixelFormat <> pf24Bit) then
    raise exception.Create('GBlur only works for 24-bit bitmaps');
  MakeGaussianKernel(K, radius, 255, 1);
  GetMem(theRows, theBitmap.Height * SizeOf(PRow));
  GetMem(ACol, theBitmap.Height * SizeOf(TRGBTriple));
  {record the location of the bitmap data:}
  for Row := 0 to theBitmap.Height - 1 do
    theRows[Row] := theBitmap.Scanline[Row];
  {blur each row:}
  P := AllocMem(theBitmap.Width * SizeOf(TRGBTriple));
  for Row := 0 to theBitmap.Height - 1 do
    BlurRow(Slice(theRows[Row]^, theBitmap.Width), K, P);
  {now blur each column}
  ReAllocMem(P, theBitmap.Height * SizeOf(TRGBTriple));
  for Col := 0 to theBitmap.Width - 1 do
  begin
    {first read the column into a TRow:}
    for Row := 0 to theBitmap.Height - 1 do
      ACol[Row] := theRows[Row][Col];
    BlurRow(Slice(ACol^, theBitmap.Height), K, P);
    {now put that row, um, column back into the data:}
    for Row := 0 to theBitmap.Height - 1 do
      theRows[Row][Col] := ACol[Row];
  end;
  FreeMem(theRows);
  FreeMem(ACol);
  ReAllocMem(P, 0);
end;

end.



Example:


procedure TForm1.Button1Click(Sender: TObject);
var
  b: TBitmap;
begin
  if not openDialog1.Execute then
    exit;
  b := TBitmap.Create;
  b.LoadFromFile(OpenDialog1.Filename);
  b.PixelFormat := pf24Bit;
  Canvas.Draw(0, 0, b);
  GBlur(b, StrToFloat(Edit1.text));
  Canvas.Draw(b.Width, 0, b);
  b.Free;
end;


Note that displaying 24-bit bitmaps on a 256-color system requires some special tricks - if this looks funny at 256 colors it doesn't prove the blur is wrong.

Взято с

Delphi Knowledge Base






Получение имени конфигурации HardWare profile


Получение имени конфигурации HardWare profile




function GettingHWProfileName: string;  //Win95OSR2 or later and NT4.0 or later
var
  pInfo:  tagHW_PROFILE_INFOA;
begin
  GetCurrentHwProfile(pInfo);
  Result:=pInfo.szHwProfileName;
end;



Получение информации о таблице


Получение информации о таблице




Вам нужно воспользоваться свойством FieldDefs. В следующем примере список полей и их соответствующий размер передается компоненту TMemo (расположенному на форме) с именем Memo1:

procedureTForm1.ShowFields;
var
  i: Word;
begin
  Memo1.Lines.Clear;
  Table1.FieldDefs.Update;                     
  { должно быть вызвано, если Table1 не активна }
  for i := 0 to Table1.FieldDefs.Count - 1 do
    With Table1.FieldDefs.Items[i] do
      Memo1.Lines.Add(Name + ' - ' + IntToStr(Size));
end;

Если вам просто нужны имена полей (FieldNames), то используйте метода TTable GetFieldNames:
GetIndexNames для получения имен индексов:

var 
  FldNames, IdxNames : TStringList;
begin
  FldNames := TStringList.Create;
  IdxNames := TStringList.Create;
  If Table1.State = dsInactive then 
    Table1.Open;
  Table1.GetFieldNames(FldNames);
  Table1.GetIndexNames(IdxNames);
  {...... используем полученную информацию ......}
  FldNames.Free; {освобождаем stringlist}
  IdxNames.Free;
end;

Для получения информации об определенном поле вы должны использовать FieldDef.

Взято из





Получение IP-адреса и маски для всех сетевых интерфейсов


Получение IP-адреса и маски для всех сетевых интерфейсов



Автор: Giannis Sampaziotis

Существует множество методов получения IP адреса компьютера. Но данный пример представляет наиболее корректный способ получения всех адресов, сетевых масок, broadcast адресов и статусов для всех интерфейсов включая циклический 127.0.0.1 - требует WinSock 2.

Совместимость: Delphi 3.х (или выше)

Это завершённый Delphi компонент. Для его использования достаточно вызвать :

EnumInterfaces(var s string): Boolean;

которая вернёт строку, разделённую CRLF и содержащую всё, нужную нам информацию.


unit USock; 

interface 

uses Windows, Winsock; 



  Если Вы поместите строку результатов в wide TMEMO (в его свойство memo.lines.text)
  то никаких результатов не увидите. 

  Тестировалось на Win98/ME/2K, 95 OSR 2 и NT service 
  pack #3 , потому что используется WinSock 2 (WS2_32.DLL) 



function EnumInterfaces(var sInt: string): Boolean; 

{ функция WSAIOCtl импортируется из Winsock 2.0 - Winsock 2 доступен } 
{ только в Win98/ME/2K и 95 OSR2, NT srv pack #3 } 

function WSAIoctl(s: TSocket; cmd: DWORD; lpInBuffer: PCHAR; dwInBufferLen: 
  DWORD; 
  lpOutBuffer: PCHAR; dwOutBufferLen: DWORD; 
  lpdwOutBytesReturned: LPDWORD; 
  lpOverLapped: POINTER; 
  lpOverLappedRoutine: POINTER): Integer; stdcall; external 'WS2_32.DLL'; 

{ Константы взятые из заголовка C файлов } 

const SIO_GET_INTERFACE_LIST = $4004747F; 
  IFF_UP = $00000001; 
  IFF_BROADCAST = $00000002; 
  IFF_LOOPBACK = $00000004; 
  IFF_POINTTOPOINT = $00000008; 
  IFF_MULTICAST = $00000010; 

type sockaddr_gen = packed record 
    AddressIn: sockaddr_in; 
    filler: packed array[0..7] of char; 
  end; 

type INTERFACE_INFO = packed record 
    iiFlags: u_long; // Флаги интерфейса 
    iiAddress: sockaddr_gen; // Адрес интерфейса 
    iiBroadcastAddress: sockaddr_gen; // Broadcast адрес 
    iiNetmask: sockaddr_gen; // Маска подсети 
  end; 

implementation 

{------------------------------------------------------------------- 

1. Открываем WINSOCK 
2. Создаём сокет 
3. Вызываем WSAIOCtl для доступа к сетевым интерфейсам 
4. Для каждого интерфейса, получаем IP, MASK, BROADCAST, статус 
5. Разделяем строку символом CRLF  
6. Конец :) 

--------------------------------------------------------------------} 

function EnumInterfaces(var sInt: string): Boolean; 
var s: TSocket; 
  wsaD: WSADATA; 
  NumInterfaces: Integer; 
  BytesReturned, SetFlags: u_long; 
  pAddrInet: SOCKADDR_IN; 
  pAddrString: PCHAR; 
  PtrA: pointer; 
  Buffer: array[0..20] of INTERFACE_INFO; 
  i: Integer; 
begin 
  result := true;                                // Инициализируем переменную 
  sInt := ''; 

  WSAStartup($0101, wsaD);                      // Запускаем WinSock 
                                                // Здесь можно дабавить различные обработчики ошибки :) 

  s := Socket(AF_INET, SOCK_STREAM, 0);          // Открываем сокет 
  if (s = INVALID_SOCKET) then exit; 

  try                                            // Вызываем WSAIoCtl 
    PtrA := @bytesReturned; 
    if (WSAIoCtl(s, SIO_GET_INTERFACE_LIST, nil, 0, @Buffer, 1024, PtrA, nil, 
      nil) 
      <> SOCKET_ERROR) 
      then 
    begin                                        // Если OK, то определяем количество существующих интерфейсов 

      NumInterfaces := BytesReturned div SizeOf(INTERFACE_INFO); 

      for i := 0 to NumInterfaces - 1 do        // Для каждого интерфейса 
      begin 
        pAddrInet := Buffer[i].iiAddress.addressIn;            // IP адрес 
        pAddrString := inet_ntoa(pAddrInet.sin_addr); 
        sInt := sInt + ' IP=' + pAddrString + ','; 
        pAddrInet := Buffer[i].iiNetMask.addressIn;            // Маска подсети 
        pAddrString := inet_ntoa(pAddrInet.sin_addr); 
        sInt := sInt + ' Mask=' + pAddrString + ','; 
        pAddrInet := Buffer[i].iiBroadCastAddress.addressIn;  // Broadcast адрес 
        pAddrString := inet_ntoa(pAddrInet.sin_addr); 
        sInt := sInt + ' Broadcast=' +  pAddrString + ','; 

        SetFlags := Buffer[i].iiFlags; 
        if (SetFlags and IFF_UP) = IFF_UP then 
          sInt := sInt + ' Interface UP,'                    // Статус интерфейса up/down 
        else 
          sInt := sInt + ' Interface DOWN,'; 

        if (SetFlags and IFF_BROADCAST) = IFF_BROADCAST then  // Broadcasts 
          sInt := sInt + ' Broadcasts supported,'              // поддерживает или 
        else                                                  // не поддерживается 
          sInt := sInt + ' Broadcasts NOT supported,'; 

        if (SetFlags and IFF_LOOPBACK) = IFF_LOOPBACK then    // Циклический или 
          sInt := sInt + ' Loopback interface' 
        else 
          sInt := sInt + ' Network interface';                  // нормальный 

        sInt := sInt + #13#10;                                // CRLF между каждым интерфейсом 
      end; 
    end; 
  except 
  end; 
// 
// Закрываем сокеты 
// 
  CloseSocket(s); 
  WSACleanUp; 
  result := false; 
end; 

end. 

Взято с Исходников.ru



Получение количества установленных процессоров


Получение количества установленных процессоров




function GettingProcNum: string;  //Win95 or later and NT3.1 or later
var
  Struc:    _SYSTEM_INFO;
begin
  GetSystemInfo(Struc);
  Result:=IntToStr(Struc.dwNumberOfProcessors);
end;



Получение переменных среды


Получение переменных среды




procedureGetEnvironmentStrings(ss: TStrings);
{Переменные среды}
var
  ptr: PChar;
  s: string;
  Done: boolean;
begin
  ss.Clear;
  s := '';
  Done := FALSE;
  ptr := windows.GetEnvironmentStrings;
  while Done = false do begin
    if ptr^ = #0 then begin
      inc(ptr);
      if ptr^ = #0 then Done := TRUE
      else ss.Add(s);
      s := ptr^;
    end else s := s + ptr^;
    inc(ptr);
  end;
end;



Взято с





Получение списка DLL загруженных приложением


Получение списка DLL загруженных приложением



Автор: Simon Carter

Иногда бывает полезно знать какими DLL-ками пользуется Ваше приложение. Давайте посмотрим как это можно сделать в Win NT/2000.

Пример функции

unit ModuleProcs; 

interface 

uses Windows, Classes; 

type 
  TModuleArray = array[0..400] of HMODULE; 
  TModuleOption = (moRemovePath, moIncludeHandle); 
  TModuleOptions = set of TModuleOption; 

function GetLoadedDLLList(sl: TStrings; 
  Options: TModuleOptions = [moRemovePath]): Boolean; 

implementation 

uses SysUtils; 

function GetLoadedDLLList(sl: TStrings; 
  Options: TModuleOptions = [moRemovePath]): Boolean; 
type 
EnumModType = function (hProcess: Longint; lphModule: TModuleArray; 
  cb: DWord; var lpcbNeeded: Longint): Boolean; stdcall; 
var 
  psapilib: HModule; 
  EnumProc: Pointer; 
  ma: TModuleArray; 
  I: Longint; 
  FileName: array[0..MAX_PATH] of Char; 
  S: string; 
begin 
  Result := False; 

  (* Данная функция запускается только для Widnows NT *) 
  if Win32Platform <> VER_PLATFORM_WIN32_NT then 
    Exit; 

  psapilib := LoadLibrary('psapi.dll'); 
  if psapilib = 0 then 
    Exit; 
  try 
    EnumProc := GetProcAddress(psapilib, 'EnumProcessModules'); 
    if not Assigned(EnumProc) then 
      Exit; 
    sl.Clear; 
    FillChar(ma, SizeOF(TModuleArray), 0); 
    if EnumModType(EnumProc)(GetCurrentProcess, ma, 400, I) then 
    begin 
      for I := 0 to 400 do 
        if ma[i] <> 0 then 
        begin 
          FillChar(FileName, MAX_PATH, 0); 
          GetModuleFileName(ma[i], FileName, MAX_PATH); 
          if CompareText(ExtractFileExt(FileName), '.dll') = 0 then 
          begin 
            S := FileName; 
            if moRemovePath in Options then 
              S := ExtractFileName(S); 
            if moIncludeHandle in Options then 
              sl.AddObject(S, TObject(ma[I])) 
            else 
              sl.Add(S); 
          end; 
        end; 
    end; 
    Result := True; 
  finally 
    FreeLibrary(psapilib); 
  end; 
end; 

end. 


Для вызова приведённой функции надо сделать следующее:

Добавить listbox на форму (Listbox1)
Добавить кнопку на форму (Button1)

Обработчик события OnClick для кнопки будет выглядеть следующим образом

procedure TForm1.Button1Click(Sender: TObject); 
begin 
  GetLoadedDLLList(ListBox1.Items, [moIncludeHandle, moRemovePath]); 
end; 


Взято с Исходников.ru




Получение ссылки на экземпляр класса


Получение ссылки на экземпляр класса




...мне также понадобилось в подпрограмме получить ссылку на дочернее MDI-окно без сообщения подпрограмме с каким конкретно классом MDI необходимо работать. Что я сделал: я передавал в виде параметров тип дочернего MDI-окна и ссылку как нетипизированную переменную и затем обрабатывал это в подпрограмме.

Вот пример. Эта подпрограмма работает с дочерним окном, которое может иметь только один экземпляр. Если оно не открыто, подпрограмма создаст его, если оно открыто, оно переместит его на передний план.

procedureFormLoader(FormClassType: TFormClass; var FormName);
begin
  if TForm(FormName) = nil then
    begin
      Application.CreateForm(FormClassType, FormName);
    end
  else
    begin
      TForm(FormName).BringToFront;
      TForm(FormName).WindowState := wsNormal;
    end;
end;

Вот как это вызывать:

procedure TfrmTest.sbOpenClick(Sender: TObject);
begin
  FormLoader(TfrmTest, frmTest);
end;

Взято из

Советов по Delphi от


Сборник Kuliba






Получение типа клавиатуры


Получение типа клавиатуры




function GettingKeybType: string;  //Win95 or later and NT3.1 or later
var
  Flag:   integer;
begin
  Flag:=0;
  Case GetKeyboardType(Flag) of
    1:  Result:='IBM PC/XT or compatible (83-key) keyboard';
    2:  Result:='Olivetti "ICO" (102-key) keyboard';
    3:  Result:='IBM PC/AT (84-key) or similar keyboard';
    4:  Result:='IBM enhanced (101- or 102-key) keyboard';
    5:  Result:='Nokia 1050 and similar keyboards';
    6:  Result:='Nokia 9140 and similar keyboards';
    7:  Result:='Japanese keyboard';
  end;
end;



Получение уровня процессора


Получение уровня процессора




function GettingProcLevel: string;  //Win95 or later and NT3.1 or later
var
  Struc:    _SYSTEM_INFO;
begin
  GetSystemInfo(Struc);
  Case Struc.wProcessorLevel of
    3:  Result:='Intel 80386';
    4:  Result:='Intel 80486';
    5:  Result:='Intel Pentium';
    6:  Result:='Intel Pentium II or better';
  end;
end;



Получить и установить системные цвета


Получить и установить системные цвета




var

  OldColor: TColor; 
  Element: TColor = COLOR_BTNFACE; 

  {....} 


  Set the color for a system element. SetSysColors function 
  changes the current Windows session only. 
  The new colors are not saved when Windows terminates. 
  For a list of color elements see  Win32 API Help - Function GetSysColor 


  Open the ColorDialog - and set the new color systemwide 


procedure TForm1.Button1Click(Sender: TObject); 
begin 
  if ColorDialog1.Execute then 
  begin 
    SetSysColors(1, Element, ColorDialog1.Color); 
  end; 
end; 


  Save the old color value of the element COLOR_BTNFACE to restore on Button2 click 


procedure TForm1.FormShow(Sender: TObject); 
begin 
  OldColor := GetSysColor(COLOR_BTNFACE); 
end; 


  Restore the old color value 
  Stellt den alten Farbwert wieder her 


procedure TForm1.Button2Click(Sender: TObject); 
begin 
  SetSysColors(1, Element, OldColor); 
end;


Взято из





Получить информацию о BIOSе


Получить информацию о BIOSе




Вот пример как можно даты БИОС материнской платы и видеокарты выдрать.
То же самое можно с названием производителя и версией.
В WinNT приходится читать не из ПЗУ а из реестра но это достаточно надежно
- соотв ключи WinNT закрывает на запись и обновляет при каждом старте (?).
Для Win9x можешь хоть весь БИОС напрямую читать.

Получить заводской номер винчестера (не тот что getvolumeinfo дает) ИМХО
невозможно - порты IDE даже Win9x блокирует.

type
TRegistryRO= class (TRegistry)
   function OpenKeyRO (const Key: string): Boolean;
  end;
{ это уже ветхая история - был один глюк у D3}

implementation

uses WAPIInfo, Windows, SysUtils, StrUtils;

function TRegistryRO.OpenKeyRO (const Key: string): Boolean;
function
IsRelative(const Value: string): Boolean;
  begin Result := not ((Value <> '') and (Value[1] = '\')) end;
var
  TempKey: HKey;
  S: string;
  Relative: Boolean;
begin
  S := Key;
  Relative := IsRelative(S);
  if not Relative then Delete(S, 1, 1);
  TempKey := 0;
    Result := RegOpenKeyEx(GetBaseKey(Relative), PChar(S), 0,
      KEY_READ, TempKey) = ERROR_SUCCESS;
   if Result then begin
     if (CurrentKey <> 0) and Relative then S := CurrentPath + '\' + S;
     ChangeKey(TempKey, S);
    end;
end;

function GetBIOSDate : string;
const
  BIOSDatePtr
= $0ffff5;
  SystemKey = 'HARDWARE\DESCRIPTION\System';
  BiosDateParam = 'SystemBiosDate';
var
  p : pointer;
  s : string[128];
begin
  if OSisNT then begin
     with TRegistryRO.Create do try
       RootKey := HKEY_LOCAL_MACHINE;
       if OpenKeyRO (SystemKey) then begin
         s := ReadString (BiosDateParam);
        end;
       finally Free;
      end; { of try}
    end
   else try
      s[0] := #8;
      p := Pointer(BIOSDatePtr);
      Move (p^, s[1], 8);
     except FillChar (s[1],
8, '9');
    end; { of try}
  Result := copy (s, 1, 2) + copy (s, 4, 2) + copy (s, 7, 2);
end;

function GetVideoDate : string;
const
  VideoDatePtr = $0C0000;
  SystemKey = 'HARDWARE\DESCRIPTION\System';
  VideoDateParam = 'VideoBiosDate';
var
  p : pointer;
  s : string[255];
begin
  if OSisNT then begin
     with TRegistryRO.Create do try
       RootKey := HKEY_LOCAL_MACHINE;
       if OpenKeyRO (SystemKey)
        then s := ReadString (VideoDateParam)
        else s := 'NT/de/tected';
       finally Free;
      end; { of
try}
    end
   else try
      s[0] := #255;
      p := Pointer(VideoDatePtr + 60); { первые $60 - строка CopyRight}
      Move (p^, s[1], 255);
      if pos('/', s) > 2 then s := copy (s, pos('/', s) - 2, 8)
       else begin
         p := Pointer(VideoDatePtr + 60 + 250);
         Move (p^, s[1], 255);
         if pos('/', s) > 2 then s := copy (s, pos('/', s) - 2, 8);
        end;
     except FillChar (s[1], 8, '9');
    end; { of try}
  Result := copy (s, 1, 2) + copy (s, 4, 2) + copy (s, 7, 2);
end;

unit WAPIInfo;

interface

uses
Registry, SysUtils, Windows;

procedure GetOSVerInfo (var OSID : DWORD; var OSStr : string);
function OSisNT : boolean;
procedure GetCPUInfo (var CPUID : DWORD; var CPUStr : string);
procedure GetMemInfo (var MemStr : string);

implementation

procedure GetOSVerInfo (var OSID : DWORD; var OSStr : string);
var
  OSVerInfo : TOSVersionInfo;
  Reg : TRegistry;
  s : string;
begin
  OSVerInfo.dwOSVersionInfoSize := SizeOf (OSVerInfo);
  GetVersionEx (OSVerInfo);
  OSID := OSVerInfo.dwPlatformID;
  case OSID of
    VER_PLATFORM_WIN32S : OSStr := 'Windows 3+';
    VER_PLATFORM_WIN32_WINDOWS : OSStr := 'Windows 95+';
   VER_PLATFORM_WIN32_NT : begin
      OSStr := 'Windows NT';
      Reg := TRegistry.Create;
      Reg.RootKey := HKEY_LOCAL_MACHINE;
      if Reg.OpenKey ('SYSTEM\CurrentControlSet\Control\', False)
        then try
         s := Reg.ReadString ('ProductOptions')
        except s := ''
       end;
      if s = 'WINNT' then OSStr := OSStr + ' WorkStation'
      else if s = 'SERVERNT' then OSStr := OSStr + ' Server 3.5 & hi'
      else if s = 'LANMANNT' then OSStr := OSStr + ' Advanced server 3.1';
      Reg.Free;
  
  end;
   end;
  with OSVerInfo do OSStr := OSStr + Format (' %d.%d (выпуск %d)',
   [dwMajorVersion, dwMinorVersion, LoWord(dwBuildNumber)]);
end;

function OSisNT : boolean;
var
  s : string;
  i : DWORD;
begin
  GetOSVerInfo (i, s);
  Result := (i = VER_PLATFORM_WIN32_NT);
end;

procedure GetCPUInfo (var CPUID : DWORD; var CPUStr : string);
var SI : TSystemInfo;
begin
  GetSystemInfo (SI);
  CPUID := SI.dwProcessorType;
  case CPUID of
    386: CPUStr := '80386-совместимый процессор';
    486: CPUStr := '80486-совместимый процессор';
    586: CPUStr := 'Pentium-совместимый процессор';
  
 else CPUStr := 'Неизвестный процессор';
   end;
{  case SI.wProcessorArchitecture of
    PROCESSOR_ARCHITECTURE_INTEL: ;
    MIPS
    ALPHA
    PPC
    UNKNOWN
   end;}
end;

procedure GetMemInfo (var MemStr : string);
var MemInfo : TMemoryStatus;
begin
  MemInfo.dwLength := SizeOf (MemInfo);
  GlobalMemoryStatus (MemInfo);
  with MemInfo do MemStr := Format ('ОЗУ: %0.2f M (свободно %0.2f M)'#$d+
   ' Файл подкачки: %0.2f M (свободно: %0.2f M)'#$d,
   [(dwTotalPhys div 1024) / 1024,
    (dwAvailPhys div 1024) / 1024,
    (dwTotalPageFile div 1024) / 1024,
    (dwAvailPageFile div 1024) / 1024]);
end;

end.

PS Возможно, эти процедуры не всегда дату возвращают
но то что практически всегда для разных материнских/видео
плат возвращаются разные значения - проверено, что мне
собственно и требовалось.
Andrey Sorokin from sunny
Russian Technology http://attend.to/rt anso@rt.spb.ru

Автор:

Song

Взято из





Пользователи, пароли, защита информации


Пользователи, пароли, защита информации



Cодержание раздела:







См. также статьи в других разделах:




Ползунок компонента TScrollBar все время мигает. Как это отключить?


Ползунок компонента TScrollBar все время мигает. Как это отключить?




Установите свойтсво ScrollBar.TabStop в False.



Помещение компонентов в DBGrid


Помещение компонентов в DBGrid




Данный совет и сопутствующий код показывает как просто поместить любой компонент в ячейку сетки данных. Компонент в данном контексте может означать любой видимый элемент управления - от простого combobox до сложного диалогового окна. Методы, описанные ниже, применимы практически к любому визуальному компоненту. Если Вы можете поместить его на форму, то, вероятно, сможете поместить и в ячейку DBGrid.

Здесь нет новых идей, фактически основная технология работы заключается в имитации-трансплантации внешних компонентов в DBGrid. Идея в том, чтобы получить контроль над табличной сеткой. Практически DBGrid состоит из набора компонентов TDBEdit. Вводя данные в ячейку, вы работаете непосредственно с TDBEdit. Остальные без фокуса ячейки в данный момент реально являются статичной картинкой. В данном совете Вы узнаете как поместить в сфокусированную ячейку другой, отличный от TDBEdit, визуальный компонент.

КОМПОНЕНТ #1 - TDBLOOKUPCOMBO
Вам нужна форма с компонентом DBGrid на ней. Создайте новый проект и поместите на основную форму DBGrid.

Далее поместите на форму TTable, установите псевдоним (Alias) в DBDEMOS, TableName в GRIDDATA.DB и присвойте свойству Active значение True. Поместите DataSource и сошлитесь в свойстве DataSet на Table1. Вернитесь к DBGrid и укажите в свойстве DataSource компонент DataSource1. Данные из GRIDDATA.DB должные появиться в табличной сетке...

Первый элемент, который мы собираемся поместить в DBGrid - TDBLookupCombo, т.к. нам нужна вторая таблица для поиска. Поместите второй TTable на форму. Установите псевдоним (Alias) в DBDEMOS, TableName в CUSTOMER.DB и присвойте свойству Active значение True. Поместите второй DataSource и сошлитесь в свойстве DataSet на Table2.

Теперь нужно поместить компонент TDBLookupCombo из палитры Data Controls на любое место формы - это не имеет никакого значения, т.к. он обычно будет невидим или будет нами имплантирован в табличную сетку. Установите свойства компонента LookuoCombo следующим образом:



DataSourceDataSource1
DataField       CustNo
LookupSource    DataSource2
LookupField     CustNo
LookupDisplay   CustNo  {Вы можете изменить это на Company позже,
                         но сейчас пусть это будет CustNo)




Пока мы только настроили компоненты. Теперь давайте создадим некоторый код.

Первое, что Вам необходимо - сделать так, чтобы DBLookupCombo, который Вы поместили на форму, во время запуска приложения оставался невидимым. Для этого выберите Form1 в инспекторе объектов, перейдите на закладку Events (события) и дважды щелкните на событии onCreate. Delphi немедленно сгенерит и отобразит скелет кода будущего обработчика события onCreate:



procedure TForm1.FormCreate(Sender: TObject);
begin

end;




Присвойте свойству Visible значение False в LookupCombo следующим образом:



procedure TForm1.FormCreate(Sender: TObject);
begin
  DBLookupCombo1.Visible := False;
end;




Наверняка многим стало интересно, почему я не воспользовался инспектором объектов для изменения свойств компонента. Действительно, можно было бы и так. Лично я таким способом инициализирую компоненты, чьи свойства могут изменяться во время работы приложения. Я изменил статическое свойство, которое не отображается во время проектирования (если воспользоваться инспектором объктов). Я думаю это делает код легче для понимания.

Теперь нам необходимо "прикрутить" компонент к нашей табличной сетке. Наша задача - автоматически отобразить DBLookupCombo в ячейке во время получения ею фокуса (или перемещении курсора). Для этого необходимо написать код для обработчиков двух событий: OnDrawDataCell и OnColExit. Первым делом обработаем событие OnDrawDataCell. Дважды щелкните на строчке OnDrawDataCell в инспекторе объектов и введите следующий код:



procedure TForm1.DBGrid1DrawDataCell(Sender: TObject; const Rect: TRect;
  Field: TField; State: TGridDrawState);
begin
  if (gdFocused in State) then
  begin
    if (Field.FieldName = DBLookupCombo1.DataField) then
    begin
      DBLookupCombo1.Left := Rect.Left + DBGrid1.Left;
      DBLookupCombo1.Top := Rect.Top + DBGrid1.top;
      DBLookupCombo1.Width := Rect.Right - Rect.Left;
      { DBLookupCombo1.Height := Rect.Bottom - Rect.Top; }
      DBLookupCombo1.Visible := True;
    end;
  end;
end;




Причины чрезмерного использования конструкций begin/end скоро станут понятны. В коде "говорится", что если параметр State имеет значение gdFocused, то данная ячейка имеет фокус (в любой момент времени только одна ячейка в табличной сетке может иметь фокус). Далее: если это выделенная ячейка и ячейка имеет тоже имя поля как и поле данных DBLookupCombo, DBLookupCombo необходимо поместить над этой ячейкой и сделать его видимым. Обратите внимание на определение позиции DBLookupCombo: она определяется относительно формы, а не ячейки. Так, например, положение левой стороны LookupCombo должно учитывать положение сетки (DBGrid1.Left) плюс положение соответствующей ячейки относительно сетки (Rect.Left).

Также обратите внимание на то, что определение высоты LookupCombo в коде закомментарено. Причина в том, что LookupCombo имеет минимальную высоту. Вы просто не сможете сделать ее меньше. Минимальная высота LookupCombo больше высоты ячейки. Если Вы раскомментарили строку, касающуюся высоты LookupCombo, Ваш код изменит размер компонента и Delphi немедленно его перерисует. Это вызовет неприятное моргание компонента. Бороться с этим невозможно. Позвольте, чтобы LookupCombo был немного больше, чем ячейка. Это выглядит немного странным, но это работает.

Теперь ради шутки запустите программу. Заработала? Сразу после запуска переместите курсор на одну из ячеек табличной сетки. Вы ожидали чего-то большего? Да! Мы только в середине пути. Теперь нам нужно спрятать LookupCombo при покидании курсором колонки. Напишем обработчик события onColExit. Это должно выглядеть примерно так:



procedure TForm1.DBGrid1ColExit(Sender: TObject);
begin
  If DBGrid1.SelectedField.FieldName = DBLookupCombo1.DataField then
    DBLookupCombo1.Visible := false;
end;




Код использует свойство TDBGrids SelectedField для ассоциации имени поля ячейки (FieldName) с нашим LookupCombo. Код "говорит": "Если ячейка была в колонке с DBLookupCombo (имя поля ячейки совпадает с именем поля DBLookupCombo), его необходимо сделать невидимым".

Теперь снова запустите приложение. Чувствуете эффект?

Теперь вроде бы все правильно, но мы забыли об одной вещи. Попробуйте ввести новое значение в одно из LookupCombo. Проблема в том, что нажатие клавиши обрабатывает DBGrid, а не LookupCombo. Чтобы исправить это, нам нужно написать для табличной сетки обработчик события onKeyPress. Это должно выглядеть примерно так:



procedure TForm1.DBGrid1KeyPress(Sender: TObject; var Key: Char);
begin
  if (key <> chr(9)) then
  begin
    if (DBGrid1.SelectedField.FieldName = DBLookupCombo1.DataField) then
    begin
      DBLookupCombo1.SetFocus;
      SendMessage(DBLookupCombo1.Handle, WM_Char, word(Key), 0);
    end;
  end;
end;




В данном коде "говорится": если нажатая клавиша не является клавишей Tab (Chr(9)) и текущее поле в табличной сетке LookupCombo, тогда установите фокус на LookupCombo и передайте сообщение с кодом нажатой клавиши LookupCombo. Здесь я воспользовался WIN API функцией. Вам не нужно знать как это работает, достаточно того, что это просто работает.

Небольшое пояснение я все же дам. Для того, чтобы функция Window SendMessage послала сообщение "куда надо", ей в качестве параметра необходим дескриптор ("адрес") нужного компонента. Используйте свойство компонента Handle. Затем нужно сообщить компоненту что мы от него хотим. В нашем случае это Windows-сообщение WM_CHAR, извещающее LookupCombo о том, что ему посылается символ. Наконец, мы передаем ему сам символ нажатой клавиши - word(Key). Word(key) - приведение к типу word параметра Key события нажатия клавиши. Все достаточно просто, правда? Все, что Вам действительно необходимо сделать - заменить имя DBLookupCombo1 нашего вымышленного компонента на имя реального компонента, который будет участвовать в "модернизации" табличной сетки. Более подробную информацию о функции SendMessage Вы можете почерпнуть из электронной справки, поставляемой вместе с Delphi.

Запустите снова Ваше приложение и попробуйте что-нибудь ввести. Это работает! Экспериментируя, Вы увидите что с помощью клавиши Tab Вы можете перейти из режима редактирования в режим перемещения курсора и наоборот.

Теперь перейдите к инспектору объектов и измнените у компонента DBLookupCombo свойство LookupDIsplay на Company. Снова запустите. Это то, что Вы ожидали?

КОМПОНЕНТ #2 - TDBCOMBO

Здесь я не собираюсь обсуждать технологию имплантации DBCombo, так как она практически не отличается от той, что была показана выше. Все написанное в пункте #1 имеет силу и здесь. Вот пошагово разработанный код для вашего компонента.



procedure TForm1.FormCreate(Sender: TObject);
begin
  DBLookupCombo1.Visible := False;
  DBComboBox1.Visible := False;
end;

procedure TForm1.DBGrid1DrawDataCell(Sender: TObject; const Rect: TRect;
  Field: TField; State: TGridDrawState);
begin
  if (gdFocused in State) then
  begin
    if (Field.FieldName = DBLookupCombo1.DataField) then
    begin
      DBLookupCombo1.Left := Rect.Left + DBGrid1.Left;
      DBLookupCombo1.Top := Rect.Top + DBGrid1.top;
      DBLookupCombo1.Width := Rect.Right - Rect.Left;
      DBLookupCombo1.Visible := True;
    end
    else if (Field.FieldName = DBComboBox1.DataField) then
    begin
      DBComboBox1.Left := Rect.Left + DBGrid1.Left;
      DBComboBox1.Top := Rect.Top + DBGrid1.top;
      DBComboBox1.Width := Rect.Right - Rect.Left;
      DBComboBox1.Visible := True;
    end
  end;
end;

procedure TForm1.DBGrid1ColExit(Sender: TObject);
begin
  if DBGrid1.SelectedField.FieldName = DBLookupCombo1.DataField then
    DBLookupCombo1.Visible := false
  else if DBGrid1.SelectedField.FieldName = DBComboBox1.DataField then
    DBComboBox1.Visible := false;
end;

procedure TForm1.DBGrid1KeyPress(Sender: TObject; var Key: Char);
begin
  if (key <> chr(9)) then
  begin
    if (DBGrid1.SelectedField.FieldName = DBLookupCombo1.DataField) then
    begin
      DBLookupCombo1.SetFocus;
      SendMessage(DBLookupCombo1.Handle, WM_Char, word(Key), 0);
    end
    else if (DBGrid1.SelectedField.FieldName = DBComboBox1.DataField) then
    begin
      DBComboBox1.SetFocus;
      SendMessage(DBComboBox1.Handle, WM_Char, word(Key), 0);
    end;
  end;
end;



КОМПОНЕНТ #3 - TDBCHECKBOX
Технология работы с компонентом DBCheckBox более интересна. В этом случае нам необходимо дать понять пользователю о наличие компонента DBCheckBox в ячейках без фокуса. Вы можете вставлять статическое изображение компонента или динамически изменять изображение в зависимости от логического состояния элемента управления. Я выбрал второе. Я создал два BMP-файла - включенный (TRUE.BMP) и выключенный (FALSE.BMP) DBCheckBox. Поместите два компонента TImage на форму, присвойте им имена ImageTrue и ImageFalse и назначьте соответствующие BMP-файлы в свойстве Picture. Да, чуть не забыл: Вам также необходимо поместить на форму два компонента DBCheckbox. Установите набор данных обоих компонентов в DataSource1 и присвойстве свойству Color значение clWindow. Для начала создадим для формы обработчик события onCreate:



procedure TForm1.FormCreate(Sender: TObject);
begin
  DBLookupCombo1.Visible := False;
  DBCheckBox1.Visible := False;
  DBComboBox1.Visible := False;
  ImageTrue.Visible := False;
  ImageFalse.Visible := False;
end;




Теперь нам нужен обработчик события onDrawDataCell чтобы делать что-то с ячейками, не имеющими фокуса. Здесь подойдет следующий код:



procedure TForm1.DBGrid1DrawDataCell(Sender: TObject; const Rect: TRect;
  Field: TField; State: TGridDrawState);
begin
  if (gdFocused in State) then
  begin
    if (Field.FieldName = DBLookupCombo1.DataField) then
    begin
      // ...СМОТРИ ВЫШЕ
    end
    else if (Field.FieldName = DBCheckBox1.DataField) then
    begin
      DBCheckBox1.Left := Rect.Left + DBGrid1.Left + 1;
      DBCheckBox1.Top := Rect.Top + DBGrid1.top + 1;
      DBCheckBox1.Width := Rect.Right - Rect.Left { - 1};
      DBCheckBox1.Height := Rect.Bottom - Rect.Top { - 1};
      DBCheckBox1.Visible := True;
    end
    else if (Field.FieldName = DBComboBox1.DataField) then
    begin
      // ...СМОТРИ ВЫШЕ
    end
  end
  else {в этом месте помещаем статическое изображение компонента}
  begin
    if (Field.FieldName = DBCheckBox1.DataField) then
    begin
      if TableGridDataCheckBox.AsBoolean then
        DBGrid1.Canvas.Draw(Rect.Left, Rect.Top, ImageTrue.Picture.Bitmap)
      else
        DBGrid1.Canvas.Draw(Rect.Left, Rect.Top, ImageFalse.Picture.Bitmap)
    end
  end;
end;




Самое интересное место - последний участок кода. Он выполняется в случае, когда состояние не равно gdFocused и сам CheckBox находится в колонке. В нем осуществляется проверка данных поля: если они равны True, то выводится рисунок TRUE.BMP, в противном случае - FALSE.BMP. Предварительно я создал два изображения, представляющие собой "слепок" двух логических состояния компонента, теперь будет очень трудно обнаружить отсутствие компонента в ячейках с фокусом и без оного. Теперь напишем обработчик события onColExit:



procedure TForm1.DBGrid1ColExit(Sender: TObject);
begin
  If DBGrid1.SelectedField.FieldName = DBLookupCombo1.DataField then
    DBLookupCombo1.Visible := false
  else
  If DBGrid1.SelectedField.FieldName = DBCheckBox1.DataField then
    DBCheckBox1.Visible := false
  else
  If DBGrid1.SelectedField.FieldName = DBComboBox1.DataField then
    DBComboBox1.Visible := false;
end;




Организуйте обработку события onKeyPress как показано ниже:



procedure TForm1.DBGrid1KeyPress(Sender: TObject; var Key: Char);
begin
  if (key <> chr(9)) then
  begin
    if (DBGrid1.SelectedField.FieldName = DBLookupCombo1.DataField) then
    begin
      DBLookupCombo1.SetFocus;
      SendMessage(DBLookupCombo1.Handle, WM_Char, word(Key), 0);
    end
    else if (DBGrid1.SelectedField.FieldName = DBCheckBox1.DataField) then
    begin
      DBCheckBox1.SetFocus;
      SendMessage(DBCheckBox1.Handle, WM_Char, word(Key), 0);
    end
    else if (DBGrid1.SelectedField.FieldName = DBComboBox1.DataField) then
    begin
      DBComboBox1.SetFocus;
      SendMessage(DBComboBox1.Handle, WM_Char, word(Key), 0);
    end;
  end;
end;

 


Наконец, последняя хитрость. Для удобства пользователя заголовку компонента нужно присвоить текущее логическое значение. С самого начала у меня была идея поручить это обработчику события onChange, но проблема в том, что событие может возникнуть неединожды. Итак, я должен снова воспользоваться функцией Windows API и послать компоненту соответствующее значение: "SendMessage(DBCheckBox1.Handle, BM_GetCheck, 0, 0)", которая возвращает 0 в случае если компонент невключен и любое другое число в противном случае.



procedure TForm1.DBCheckBox1Click(Sender: TObject);
begin
  if SendMessage(DBCheckBox1.Handle, BM_GetCheck, 0, 0) = 0 then
    DBCheckBox1.Caption := ' ' + 'Ложь'
  else
    DBCheckBox1.Caption := ' ' + 'Истина'
end;

 


Это все. Надеюсь, Вы узнали для себя что-то новое. Я пробовал данную технологию с диалоговыми окнами. Делается достаточно просто и великолепно работает. Радует простота реализации. Вам даже не нужно знать как это работает, единственное, что Вам придется - заменить в тексте кода имена вымышленных компонентов на те, которые Вы реально хотите отображать в табличной сетке.

Ревизия

Вышеприведенный код оказался несвободным от недостатков - после первой публикации совета дотошные программисты таки обнаружили две значительные недоработки. Первая проблема - если компонент имеет фокус, то для перемещения на следующую ячейку необходимо двукратное нажатие клавиши Tab. Вторая проблема возникает при добавлении новой записи.

Проблема # 1 - Необходимость двойного нажатия клавиши Tab.

Действительно, компонент, используемый для имплантации существует сам по себе, а не является частью табличной сетки. В случае, когда DBGrid имеет фокус, то для перемещения на следующую ячейку необходимо двукратное нажатие клавиши Tab. Первое нажатие клавиши перемещает фокус из имплантированного компонента на текущую ячейку, находящуюся под этим компонентом, и только второе нажатие клавиши Tab перемещает нас в следующую ячейку. Попробуем это исправить.

Для начала в форме, содержащей табличную сетку, опишем логическую переменную WasInFloater следующим образом:



type

TForm1 = class(TForm)
...
...
private
{ Private declarations }
WasInFloater : Boolean;
...
...
end;




Затем для компонента LookupCombo напишем обработчик события onEnter, где присвоим переменной WasInFloater значение True. Это позволит нам понять где в данный момент находится фокус.



procedure TForm1.DBLookupCombo1Enter(Sender: TObject);
begin
  WasInFloater := True;
end;

 


И, наконец, создаем хитрый обработчик события onKeyUp, позволяющий исправить досадный недостаток.



procedure TForm1.DBGrid1KeyUp(Sender: TObject; var Key: Word;
  Shift: TShiftState);
begin
  if (Key in [VK_TAB]) and WasInFloater then
  begin
    SendMessage(DBGrid1.Handle, WM_KeyDown, Key, 0);
    WasInFloater := False;
  end;
end;

 


Данный код реагирует на нажатие клавиши и позволяет в случае, когда фокус передался из имплантированного элемента управления табличной сетеке, вторично эмулировать нажатие клавиши Tab (передается код нажатой клавиши, т.е. Tab). Это работает как для отдельной клавиши Tab, так и для комбинации Shift-Tab.

Проблема #2 - Новая запись исчезает, когда компонент получает фокус.

Вторая проблема - в случае, когда вы нажимаете в навигаторе кнопку "добавить", запись добавляется, но, когда Вы после щелкаете на одном из компонентов, имплантированных в табличную сетку, новая запись таинственным образом исчезает. Причина этого - странный флаг dgCancelOnExit в опциях DBGrid, который имеет значение True по умолчанию. Установите это в False и вышеназванная проблема исчезает.

По-моему, Borland неправильно поступил, назначив такое значение по умолчанию, флаг должен иметь значение False. Я все время сталкиваюсь с данной проблемой, да и не только я, судя по новостным конференциям. Данная опция действует в случае потери компонентом фокуса и отменяет последние результаты редактирования. Во всяком случае во всех моих проектах я первым делом сбрасываю данный флаг.

Взято с






Помещение компонентов в StringGrid


Помещение компонентов в StringGrid




Автор: Neil Rubenking

Некоторое время тому назад такой вопрос уже ставился: возможно ли поместить элемент управления, например, CheckBox или ComboBox внутрь компонента ...Grid. Я сегодня помозговал и нашел неплохую, на мой взгляд, технологию. Это работает! Вот решение для тех, кто этим интересуется:


При создании компонента (в обработчике OnCreate), создайте его объекты Objects[C,R], например TCheckBox.Create(Self). Имейте в виду, что вы должны присвоить ячейкам Cells[C,R] какие-либо значения прежде, чем чем вы сможете иметь доступ к Objects[C,R]. Установите у вновь созданного компонента свойство Visible в FALSE, а свойство parent в SELF. Осуществите другую необходимую инициализацию. Имейте в виду, что вы должны внести необходимые модули в список uses, если создаете тип компонента, которого нигде кроме как на форме нет.

Создайте процедуру, берущую координаты колонки/строки и правильно позиционирующую соотвествующий объект в пределах прямоугольника ячейки, например:


procedureTForm1.FixObjPosn(vCol, vRow: LongInt);
{Размещаем содержимое компонента в области прямоугольника ячейки}
var
  R: TRect;
begin
  R := StringGrid1.CellRect(vCol, vRow);
  if StringGrid1.Objects[vCol, vRow] is TControl then
    with TControl(StringGrid1.Objects[vCol, vRow]) do
      if R.Right = R.Left then {прямоугольник ячейки невидим}
        Visible := False
      else
      begin
        InflateRect(R, -1, -1);
        OffsetRect(R, StringGrid1.Left + 1, StringGrid1.Top + 1);
        BoundsRect := R;
        Visible := True;
      end;
end;




смещение позиции необходимо, поскольку CellRect расчитывается относительно верхнего левого угла строки сетки, и родителем компонента является форма).


В обработчике события сетки OnSelectCell проверьте, располагается ли элемент Objects в текущей колонке Col и строке Row TControl - если так, установите его свойство visible в FALSE. Теперь вызовите процедуру установления координат из шага 2 для *НОВЫХ* Col и Row, передавая их из параметров обработчика события в параметры функции.

В обработчике OnTopLeftChanged просто вызовите FixObjPosn

В обработчике события OnDrawCell во-первых, если ячейка выбрана, EXIT. Если элемент ячейки Objects не TControl, также EXIT. В противном случае вам нужно создать код, обеспечивающий отрисовку "фасада" каждого типа элемента управления, которого вы разместили в сетке.

Обратите внимание на то, что если вы делаете что-либо с элементом управления, на который влияют ДРУГИЕ элементы управления (например, изменение статуса какой-либо радиокнопки из группы, или операции enable/disable), вы должны вызвать метод сетки Refresh.

Опс! Это звучит немного запутанно, но это работает. Успехов!


Взято с






Помещение VCL компонентов в область заголовка


Помещение VCL компонентов в область заголовка




Здесь есть хитрость:

Нужно разместить все необходимые элементы управления в отдельной форме, которая должна отслеживать перемещение и изменение размеров основной формы. Данная форма будет всегда находится над областью заголовка основной формы.

Нижеприведенный проект включает в себя 2 формы и выпадающий список (combobox). После запуска программы список появляется в области заголовка главной формы. Два ключевых вопроса: 1) организация перехвата сообщения WM_MOVE главной формы; и 2) возвращение фокуса в главную форму после того, как пользователь нажмет на каком-либо элементе управления, способным иметь фокус (например, TComboBox, TButton и др.)

Я использую 32-битную Delphi 2.0 под Win95, тем не менее данный код должен работать с любой версией Delphi.

Вот исходный код главной формы:



unitUnit1;

interface

uses
  Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms,
  Dialogs, StdCtrls;

type
  TForm1 = class(TForm)
    procedure FormResize(Sender: TObject);
    procedure FormShow(Sender: TObject);
    procedure FormHide(Sender: TObject);
  private
    { Private declarations }
  public
    { Public declarations }
    procedure WMMove(var Msg: TWMMove); message WM_MOVE;
  end;

var
  Form1: TForm1;

implementation

uses Unit2;

{$R *.DFM}

procedure TForm1.FormResize(Sender: TObject);
begin
  with Form2 do
  begin
    {Заменим мои магические числа реальной информацией SystemMetrics}
    Width := Form1.Width - 120;
    Top := Form1.Top + GetSystemMetrics(SM_CYFRAME);
    Left := ((Form1.Left + Form1.Width) - Width) - 60;
  end;
end;

procedure TForm1.FormShow(Sender: TObject);
begin
  Form2.Show;
end;

procedure TForm1.FormHide(Sender: TObject);
begin
  Form2.Hide;
end;

procedure TForm1.WMMove(var Msg: TWMMove);
begin
  inherited;
  if (Visible) then
    FormResize(Self);
end;

end.




Вот исходный код для псевдо-заголовка. Данная форма может содержать любые элементы управления VCL, которые вы хотите установить в области заголовка главной формы. По существу, это - независимый диалог со следующими свойствами:



Caption='' {NULL строка}
Height={высота области заголовка}
Width={высота всех компонентов на форме}
BorderIcons=[] {пусто}
BorderStyle=bsNone
FormStyle=fsStayOnTop

 


И, наконец, исходный код для Form2:



unit Unit2;

interface

uses
  Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms,
  Dialogs, StdCtrls;

type
  TForm2 = class(TForm)
    ComboBox1: TComboBox;
    procedure FormCreate(Sender: TObject);
    procedure ComboBox1Change(Sender: TObject);
    procedure FormResize(Sender: TObject);
  private
    { Private declarations }
  public
    { Public declarations }
  end;

var
  Form2: TForm2;

implementation

uses Unit1;

{$R *.DFM}

procedure TForm2.FormCreate(Sender: TObject);
begin
  Height := ComboBox1.Height - 1;
  Width := ComboBox1.Width - 1;
end;

procedure TForm2.ComboBox1Change(Sender: TObject);
begin
  Form1.SetFocus;
end;

procedure TForm2.FormResize(Sender: TObject);
begin
  ComboBox1.Width := Width;
end;

end.




Файл проекта (.DPR) довольно простой:



program Project1;

uses
  Forms,
  Unit1 in 'Unit1.pas' {Form1},
  Unit2 in 'Unit2.pas' {Form2};

{$R *.RES}

begin
  Application.Initialize;
  Application.CreateForm(TForm1, Form1);
  Application.CreateForm(TForm2, Form2);
  Application.Run;
end.




Это все!

Хотя некоторые авторы книг утверждают:

"Вы не можете установить компоненты Delphi в заголовок окна, точнее, не существует никакого способа установить их там."

Зато существует иллюзия...


Взято с






Помогите спрятать программу из списка задач?


Помогите спрятать программу из списка задач?



Или Как заказать сервисный процесс ?


unit Stealth;

interface
uses
WinTypes, WinProcs, Classes, Forms, SysUtils, Controls, Messages;

type
TStealth = class(TComponent)  
private  
fHideApp: Boolean;  
procedure SetHideApp(Value: Boolean);  
protected  
{ Protected declarations }  
procedure HideApplication;  
procedure ShowApplication;  
public  
{ Public declarations }  
constructor Create(AOwner: TComponent); override;  
destructor Destroy; override;  
// procedure Loaded; override;  
published  
{ Published declarations }  
property HideApp: Boolean read fHideApp write SetHideApp default false;  
end;  
 
function RegisterServiceProcess(dwProcessID, dwType: Integer): Integer; stdcall; external 'KERNEL32.DLL';

procedure Register;

implementation

destructor TStealth.Destroy;
begin
ShowApplication;  
inherited destroy;  
end;

constructor TStealth.Create(AOwner: TComponent);
begin
inherited Create(AOwner);  
// fHideform := true;  
end;

procedure TStealth.SetHideApp(Value: Boolean);
begin
fHideApp := Value;  
if Value then HideApplication else ShowApplication;  
end;

procedure TStealth.HideApplication;
begin
if not (csDesigning in ComponentState) then  
RegisterServiceProcess(GetCurrentProcessID, 1);  
end;

procedure TStealth.ShowApplication;
begin
if not (csDesigning in ComponentState) then  
RegisterServiceProcess(GetCurrentProcessID, 0);  
end;

procedure Register;
begin
RegisterComponents('My', [TStealth]);  
end;

end.

Автор ответа: Admin
Взято с Vingrad.ru




Понимание многопоточности в VCL для веб-серверных ISAPI-расширений


Понимание многопоточности в VCL для веб-серверных ISAPI-расширений



Автор: Andrew Kachanov (www.arisesoft.com)

В среде Delphi можно создавать высокоэффективные веб-серверные ISAPI-расширения на основе технологии WebBroker. Создайте проект с помощью мастера (New -> Web Server Application - ISAPI DLL). Прилагаемая справочная документация, а так же демонстрационный пример "$(DELPHI)\Demos\Webserv" позволяют достаточно быстро освоиться в приемах написания веб-серверных ISAPI-расширений. На выходе у вас получится обычная DLL (далее по тексту - библиотека).
Сложность заключается в том, что веб-сервер (для ускорения обработки поступающих запросов) вызывает нашу библиотеку в много-поточном режиме. В результате чего на разработчика ложиться ответственность за написание поточно-безопасного кода. Не беспокойтесь, ребята из Borland постарались упростить вам жизнь настолько, насколько это возможно. Когда я понял смысл "обертки" TWebApplication и наследника TISAPIApplication, то был восхищен, и вдохновлен поделиться этими знаниями с вами!
Согласно спецификации ISAPI-расширений, созданная библиотека имеет всего три экспортируемые функции: GetExtensionVersion, HttpExtensionProc, TerminateExtension. Нас интересует только HttpExtensionProc, через которую выполняется вся работа: получение запросов с веб-сервера (Request), обработка и обратная отправка результата (Response).
Итак, рассмотрим весь путь прохождения данных. Запрос веб-сервера поступает через экспортируемую библиотекой функцию HttpExtensionProc в TISAPIApplication через инкапсулированный метод с одноименным названием (объект Application, как и в любом VCL-приложении другого вида, присутствует всегда: создается при инициализации и разрушается при завершении приложения, однако в данном случае имеет тип TISAPIApplication):

function TISAPIApplication.HttpExtensionProc(var ECB: TEXTENSION_CONTROL_BLOCK): DWORD;
var
  HTTPRequest: TISAPIRequest; 
  HTTPResponse: TISAPIResponse;
  { ^ локально объявленные переменные запроса и ответа }
begin
  try
    HTTPRequest := NewRequest(ECB); 
    { ^ инициализация переменной запроса по структуре ECB, полученной от веб-сервера }
    try
      HTTPResponse := NewResponse(HTTPRequest);
      { ^ инициализация переменной ответа }
      try
        if HandleRequest(HTTPRequest, HTTPResponse) then
        { ^ обработка переходит к TWebApplication.HandleRequest }
          Result := HSE_STATUS_SUCCESS
        else Result := HSE_STATUS_ERROR;
      finally
        HTTPResponse.Free;
      end;
    finally
      HTTPRequest.Free;
    end;
  except
    HandleServerException(Exception(ExceptObject), ECB);
    Result := HSE_STATUS_ERROR;
  end;
end;

Из приведенного кода видно, что переменные HTTPRequest и HTTPResponse объявлены локально, и объекты соответствующих типов создаются для каждого поступающего запроса веб-сервера. После инициализации этих переменных обработка переходит к TWebApplication.HandleRequest:

function TWebApplication.HandleRequest(Request: TWebRequest;
  Response: TWebResponse): Boolean;
var
  DataModule: TDataModule;
  Dispatcher: TCustomWebDispatcher;
  I: Integer;
begin
  Result := False;
  DataModule := ActivateWebModule; 
  { ^ назначает объект, который не используется другими потоками }
  if DataModule <> nil then
  try
    if DataModule is TCustomWebDispatcher then
      Dispatcher := TCustomWebDispatcher(DataModule)
    else with DataModule do
    begin
      Dispatcher := nil;
      for I := 0 to ComponentCount - 1 do
      begin
        if Components[I] is TCustomWebDispatcher then
        begin
          Dispatcher := TCustomWebDispatcher(Components[I]);
          Break;
        end;
      end;
    end;
    if Dispatcher <> nil then
    begin
      Result := TWebDispatcherAccess(Dispatcher).DispatchAction(Request, Response);
      { ^ обработка переходит к TWebDispatcher.DispatchAction }
      if Result and not Response.Sent then
        Response.SendResponse;
        { ^ отправка ответа веб-серверу }
    end else raise Exception.CreateRes(@sNoDispatcherComponent);
  finally
    DeactivateWebModule(DataModule);
    { ^ переводит в список неиспользуемых объектов - FInactiveWebModules }
  end;
end;

Тут следующая хитрость: локально объявленная переменная DataModule получает ссылку на объект от метода TWebApplication.ActivateWebModule. Для каждого потока предоставляется неиспользуемый в настоящее время другими потоками объект типа TDataModule, для чего выполняется перемещение этих объектов между списками FInactiveWebModules и FActiveWebModules. Если список FInactiveWebModules исчерпан, то создается новый экземпляр объекта типа TDataModule. В результате этих манипуляций для каждого потока используется собственный экземпляр объекта типа TDataModule, и разработчик может быть уверен в поточно-безопасном объявлении полей данных своего объекта TWebModule! Но это еще не все.

Локально объявленные в TISAPIApplication.HttpExtensionProc переменные HTTPRequest и HTTPResponse, о которых говорилось выше, переданы методу TWebApplication.HandleRequest в качестве параметров Request и Response, который в свою очередь передает их методу TCustomWebDispatcher.DispatchAction:

function TCustomWebDispatcher.DispatchAction(Request: TWebRequest;
  Response: TWebResponse): Boolean;
var
  I: Integer;
  Action, Default: TWebActionItem;
  Dispatch: IWebDispatch;
begin
  FRequest := Request;
  FResponse := Response;
  {...}
end;

Тут выполняется присваивание переменных Request и Response полям объекта TWebModule (как наследнику TCustomWebDispatcher). А нам уже известно, что экземпляр объекта TWebModule у каждого потока - собственный. Теперь посмотрим правде в глаза: у каждого запроса веб-сервера есть собственные экземпляры объектов TRequest и TResponse в полях TWebModule.Request и TWebModule.Response; и они поточно-безопасны.

Далее путь лежит через метод TWebActionItem.DispatchAction, который вызывается в TCustomWebDispatcher.DispatchAction. Тут может вступать в действие ваш код обработки запроса, после чего подготовленному ответу предстоит обратная дорога.

Как видно из приведенного выше фрагмента кода TWebApplication.HandleRequest - DataModule передается в качестве параметра методу TWebApplication.DeactivateWebModule, в котором может быть переведен в список FInactiveWebModules, или вовсе разрушен (если выключено свойство CacheConnections - этим не стоит пользоваться без необходимости, так как существенно снижается производительность обработки запросов). После чего обработка возвращается к TISAPIApplication.HttpExtensionProc и ответ передается веб-серверу вызовом Response.SendResponse.

Отдельно следует отметить. Мне несколько раз попадались на глаза рекомендации устанавливать глобальную переменную IsMultiThread к True в dpr-файл проекта - этого делать не нужно, т.к. в конструкторе TWebApplication эта работа уже выполняется!
Если вы используете доступ к BDE посредством наследников TBDEDataSet (TTable, TQuery, TStoredProc) то все что вам нужно сделать для обеспечения поточно-безопасности, это присвоить в конструкторе TWebModule: Session.AutoSessionName := True (подробнее смотри в справочной документации: "Managing multiple sessions").

Реализация инкапсуляции WinSock в компонентах TClientSocket и TServerSocket, которые вам могут потребоваться, так же поточно-безопасна.

Конечно, если используется файловый ввод-вывод, а так же прямые вызовы WinSock, то тогда все же нужно выполнять много-поточную защиту самостоятельно и вам все же придется прочитать раздел документации "Programming with Delphi - Using threads". :-)

Замечание: изложенное выше относится к Delphi 5.


Взято с Исходников.ru



Понятие интерфейса


Понятие интерфейса



Тут наконец проявляется одно из ключевых понятий COM - интерфейс(interface).
Наша запись ICalc - это он и есть. То есть интерфейс - это таблица содержашаяя указатели на функции. Когда вы работаете с COM объектом, несмотря на то, что это выглядит так, как будто вы работаете с самим объектом, вы работаете с его интерфейсами. Реализация здесь может быть разная, это может быть указатели на внешнии функции, как это сделанно у нас (так практическм никто не делает), но чаще всего это указатели на методы класса. Пользователя это не волнует - он получает интерфейс и с ним работает, а уж ваша задача потрудиться над тем, чтобы работа с вашим интерфейсом проходила корректно.

Мы можем создать несколько интерфейсов. Допустим, добавим в наш класс две функции:
  procedure MyCalc.Mult;   //умножение
  begin 
    result:=fx*fy;
  end;

  procedure MyCalc.Divide; //деление
  begin
    result:=fx div fy;
  end;

ну и придется добавить еще две внешнии функции:

 procedure Mult;  
 begin
  Calc.Mult
 end; 

 procedure Divide; 
 begin
  Calc.Divide;
 end; 

и переделаем GetInterface;

 procedure GetInterface(IID:integer; var Calc:ICalc); //IID - Interface ID(индефикатор интерфейса)
 begin
   CreateObject;
   if IID=1 then
    begin
     Calc.Sum:=Sum;
     Calc.Diff:=Diff;
    end
   else
   If IID=2 then
    begin
     Calc.Sum:=Mult;
     Calc.Diff:=Divide;
    end;
   Calc.SetOpers:=SetOperands;
   Calc.Release:=ReleaseObject;
 end;

Теперь пользователь может ввести какой он хочет интерфейс сложение/вычитание или умножение/деление и получить соответсвующую таблицу методов.

Слышу, слышу. Читатели уже начинают замечать сколько несуразностей в нашем коде. Давайте попробуем приводести его в нормальный вид.

Во первых, неплохо бы избавиться от внешних функций. Сейчас нам приходилось на каждый метод нашего класса добавлять еще одну внешнюю функцию, чтобы этот метод вызывать. Почему мы не можем передпть указатели на методы класса? Дело в том, что указатель на методы класса должен содержать в себе также и указатель на экземпляр класса, чтобы метод мог обращаться к членам этого класса. В Делфи можно задать указатель на функцию класса:

  MethodPointer:procedure of object;

Такое обявление увеличивает размер указателя с 4 до 8 байт, что позволяет хранить в нем указатель на экземпляр класса. В принципе, возможно этим воспользоваться и описать процедуры нашего интерфейса как объектные, но это не будет шаг в сторону COM. Так как COM должен обеспечивать единый стандарт в нем используются указатели стандартного размера 4 байта. Как же нам все-таки избавиться от неудобных внешних функций? В разных средах разработки это может быть реализованно по разному, но раз уж мы начали с Delhpi, рассмотрим как это реализованно в нем.

В Delphi вводиться ключевое слово - interface. Объявление инерфейса - это и есть объявление таблицы методов. Выглядит это так

  IMyInterface=interface
   [{GUID}]
   <метод1>
   <метод2>
   ...
  end; 

GUID - необязательное поле индефицируеющая интерфейс. Тут надо сказать, что GUID(он же UUID, CLSID) - это 128-битное число, алгоритм генерации которого гарантирует его уникальность во вселенной. В Windows его можно получить функцией CoCreateGuid или UuidCreate. В Делфи это очень удобно встроенно в среду, и вы его можете получить нажав Ctrl+Shift+G.

В нашем простом случае это будет выглядить так:

 ICalc=interface
  ['{149D0FC0-43FE-11D6-A1F0-444553540000}']
  procedure SetOperands(x,y:integer);
  function Sum:integer;
  function Diff:integer;
  procedure Release; 
 end; 

Объявленный таким образом интерфейс можно прицепить к классу. Причем заметье, что методы интерфейса имплементируются только в классе, к которому они прицеплены. То есть вот так вы написать не можете:

function ICalc.Sum:integer;
begin 
 Result:=0;
end;

Как и было сказанно, объявление интерфейса это всего лишь объявление таблицы методов. А имплементируется это так:

 MyCalc=class(TObject,ICalc) //интерфейс указывается в списке наследования!
   fx,fy:integer;
 public
   procedure SetOperands(x,y:integer);
   function Sum:integer;
   function Diff:integer;
   procedure Release;
 end;

Все методы класса у нас уже имплементированны, кроме Release. Ну с ним все понятно:

procedure MyCalc.Release;
begin
 Free; 
end;

По умолчанию, методы привязываются по именам. То есть если в ICalc указан метод Sum, то компилятор будет искать метод Sum в классе MyCalc. Однако вы можете указать явно другие имена. Например:

 MyCalc=class(TObject,ICalc)
   fx,fy:integer;
 public
   function ICalc.Diff = Difference; //задаем нужнок имя (Difference)
   procedure SetOperands(x,y:integer);
   function Sum:integer;
   function Difference:integer;  //другое имя
   procedure Release;
 end;

В нашем случае, удобно промаппить метод Release к методу Free, это избавит нас от необходимости имплементировать Release в нашем классе.

 MyCalc=class(TObject,ICalc)
   fx,fy:integer;
 public
   function ICalc.Release = Free;
   procedure SetOperands(x,y:integer);
   function Sum:integer;
   function Diff:integer; 
 end;

Что же происходит при добовлении к классу интерфейса? Здесь для каждого экземпляра нашего класса создается специальная таблица(interface table), в которой храняться все записи о поддерживаемых интерфейсах. Каждая такая запись содержит адрес соответствующего интерфейса, который в свою очередь, как уже было сказанно является таблицей методов. То есть если мы получим адрес, допустим, нашего ICalc, то вызывая функцию по этому же адресу, мы вызовем метод SetOperands класса MyCalc. Ecли вы вызовете вызовете функцию по адресу <адрес ICalc>+4 то вызовется метод Sum. Еще +4 байта будет метод Diff. То есть как вы видете, здесь указатели на функции имеют размер 4 байта, и адрес нужной функции получают прибавлением нужного смещения к адресу интерфейса.
Получить же адрес нужного интерфейса можно с помощью метода GetInterface класса TObject.

Забудем пока, что мы делали два интерфейса, и вернмся к варианту с одним интерфейсом. Перепишим наш GetInterface.
 procedure GetInterface(var ACalc:ICalc); 
 begin
   CreateObject;
   Calc.GetInterface(ICalc,ACalc);
 end;

Мы воспользовались методом GetInterface, который вышлядит так:

function TObject.GetInterface(const IID: TGUID; out Obj): Boolean;

этот возвращает в параметре Obj указатель на интерфейс, по указанному индификатору GUID. Допускается вместо переменной типа TGIUD поставить имя интерфейса - компилятор сам подставит его GUID если он ему известен.

Все. Выбрасывайте все внешнии функции, кроме GetInterface. Теперь нам придется сказать спасибо Borland'у и сделать несколько дополнительных действий. Дело в том, что по стандарту COM каждый COM объект должен имплементировать интерфейс IUnknown. Он содержит три метода и выглядит так:

  IUnknown = interface
    ['{00000000-0000-0000-C000-000000000046}']
    function QueryInterface(const IID: TGUID; out Obj): HResult; stdcall;
    function _AddRef: Integer; stdcall;
    function _Release: Integer; stdcall;
  end;

Хочу еще раз отметить, что эти примеры пишутся для Делфи, однако суть от этого не меняется. Как бы не выглядил интерфейс в других средах разработки, он всегда остается таблицой с адресами функций. И если говорить о IUnkown, то он всегда должен содержать эти же методы, в этом же порядке. В С++ он например выглядит так:

 struct IUnknown
 { 
   HRESULT QueryInterface(REFIID iid, void ** ppvObject);
   ULONG AddRef(void);
   ULONG Release(void);
 }

Так вот, в Delhpi все интерфейсы наследуются от IUnknown. Так что и наш интерфейс тоже содержит эти методы, а значит и компилятор потребует от вас их имплементации. Ну что ж. Добавтье пока пустые методы QueryInterface, _AddRef и _Release, позже мы их имплементируем правильно.

Теперь не забудтье поменять тип ICalc на интерфейс в тестере, и убедитесь, что все работает. :)

Продолжение следует...




Понятие о запросе (Query)


Понятие о запросе (Query)



Итак, это пожалуй почти всё, что мы можем "выжать" из компонента TTable. Почуствовали мощь и удобство работы с базами данных? - Ой, вряд ли! Скорее всего ощущение заумности, убогости и неудобства в сочетании с крайней медлительностью операций... Действительно доступ к базе данных через TTable является самым прямым и самым неудобным, какие же основные недостатки? Наверное уже многие задались вопросами:

1) А если мне надо 1000 записей изменить, так мне надо в цикле крутить приведенный код? Так это ж как долго!

2) Ну хорошо, у меня есть табличка на сотню тысяч записей, и мне нужно из неё выбрать только, например, 1000 записей касательно "Иванова", так мне прийдётся всю таблицу в цикле крутить пока не найду то что мне нужно?

Все эти проблемы решены, и решены великолепно - просто, очень эффективно и с минимальными затратами.

Рассмотрим в кратце общий алгоритм доступа к информации который был рассмотрен:

1.1) Передать данные из таблицы в программу
1.2) Программа сама занимается поиском данных

А что если изменить схему:
2.1) Отдать команду драйверу на поиск нужной информации
3.2) Драйвер найдёт инфу
2.3) Найденная информация будет возвращена программе.


На первый взгляд разница только в том что работу, которую делает программный код в первом случае, мы пробуем свалить на драйвера базы данных. Ну и зачем? Оказывается есть зачем! В первой схеме - есть несколько моментов на которые я бы хотел обратить внимание:

1) В любом случае манипулирование базой производится драйвером, следовательно код драйвера в любом случае работает. Драйвер написан под конкретную базу данных, и "знает" каким образом манипулировать с базой самым быстрым способом, а програмный код неизбежно подвергается "транслированию", многочисленным преобразованиям данных для обеспечения совместимости.
2) А если база данных находится на другом компьютере? Тогда программа вынуждена "вытащить" все данные на локальный компьютер перед манипулированием данными, что есть совсем не быстрая операция. Кстати пока мы тащим гигабайтную таблицу к себе, ваш сосед Вася уже успел там что-то поменять, и что теперь? Тащим заново, или посылаем Васю подальше, и не даём ему работать с базой пока сами не закончим?

А во втором способе всё будет куда лучше! Программа попросит данные и получет только те данные которые запрошены, а не всю таблицу, никаких трансляций данных - мы транслируем только те данные, которые уже отобраны, а не всё подряд, всю работу мы переложили на плечи драйвера, который был написан очень оптимально, который точно знает как работать именно с этой версией базы данных, а не со всеми подряд. А Вася нас тоже пока не интересует, драйвер сам разберётся как с ним поступать - нас это не касается (пока по крайней мере).

И как же это реализовано? Это реализовано с помощью языка запросов: SQL. Подробнее этот язык рассмотивается в разделе Базы данных, мы же не заостряя внимание на самих запросах, рассмотрим простейшие случаи как этот язык можно применить внутри программы на Дельфи и какие выгоды можем мы получить используя запросы.

Итак, из нашего тестового проекта удаляем компонент Table1. Вместо него ставим компонент TQuery. Устанавливаем Alias (DatabaseName) и связываем его с DataSource таким же образом как и таблицу.

Пока вы найдёте 2 радикальных отличия от TTable:
1) Нет свойства TableName
2) Открытие (Active:=true) квери приводит к ошибке

Query должна содержать запрос. Для этого есть свойство SQL, являющееся самым обыкновенным TStringList. Откроем это свойство и напишем примерно следующее:

   
Select * from biolife    

Теперь можно попытаться открыть квери (установить Active в True) и вы получите точно тоже что и в первом примере - грид заполненный данными из таблицы Biolife.db. Мало того, всё что мы проделывали с таблицей - позиционирование строки, чтение и запись полей и т.п. вы можете с успехом сделать и с Query - причём синтаксис тот же самый! Пока мы только сделали замену компоненту TTable и не более того.

Я здесь не буду подробно останавливаться на синтаксисе SQL запроса, материал по этой теме вы найдёте здесь:



Однако простейшие приёмы работы я покажу. В нескольких дальнейших примерах мы будем менять свойство "SQL". Перед каждым изменением этого свойства Вы должны закрывать квери (в дизайне устанавливать Active в False). В run-time изменения SQL должны выглядеть примерно так:

Query1.active:=false; 
Query1.sql.text:='Select * from biolife'; 
Query1.active:=true;   




Понятия Instance, Database etc


Понятия Instance, Database etc




Автор: Nomadic

Перевод документации:

Что такое ORACLE Database?

Это данные которые будут обрабатываться как единое целое. Database состоит из файлов операционной системы. Физически существуют database files и redo log files. Логически database files содержат словари, таблицы пользователей и redo log файлы. Дополнительно database требует одну или более копий control file.

Что такое ORACLE Instance?

ORACLE Instance обеспечивает программные механизмы доступа и управления database. Instance может быть запущен независимо от любой database (без монтирования или открытия любой database). Один instance может открыть только одну database. В то время как одна database может быть открыта несколькими Instance.

Instance состоит из:

SGA (System Global Area), которая обеспечивает коммуникацию между процессами;
до пяти (в последних версиях больше) бэкграундовых процессов.

От себя добавлю - database включает в себя tablespace, tablespace включает в себя segments (в одном файле данных может быть один или несколько сегментов, сегменты не могут быть разделены на несколько файлов). segments включают в себя extents.

Взято из





Порты


Порты


Cодержание раздела:


















См. также другие разделы:






См. также статьи в других разделах:








Посылаем нажатия клавиш другому приложению


Посылаем нажатия клавиш другому приложению



Автор: Gert v.d. Venis

Компонент Sendkeys:


unit SendKeys;

interface

uses
  Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs;

type
  TSendKeys = class(TComponent)
  private
    fhandle:HWND;
    L:Longint;
    fchild: boolean;
    fChildText: string;
    procedure SetIsChildWindow(const Value: boolean);
    procedure SetChildText(const Value: string);
    procedure SetWindowHandle(const Value: HWND);
  protected

  public

  published
    Procedure GetWindowHandle(Text:String);
    Procedure SendKeys(buffer:string);
    Property WindowHandle:HWND read fhandle write SetWindowHandle;
    Property IsChildWindow:boolean read fchild write SetIsChildWindow;
    Property ChildWindowText:string read fChildText write SetChildText;
  end;

procedure Register;

implementation

var temps:string;{й utilizado para ser acessivel pelas funcs q sao
                  utilizadas como callbacks}
    HTemp:Hwnd;
    ChildText:string;
    ChildWindow:boolean;

procedure Register;
begin
  RegisterComponents('Standard', [TSendKeys]);
end;

{ TSendKeys }


function PRVGetChildHandle(H:HWND; L: Integer): LongBool;
var p:pchar;
    I:integer;
    s:string;
begin
  I:=length(ChildText)+2;
  GetMem(p,i+1);
  SendMessage(H,WM_GetText,i,integer(p));
  s:=strpcopy(p,s);
  if pos(ChildText,s)<>0 then
   begin
     HTemp:=H;
     Result:=False
   end else
    Result:=True;
  FreeMem(p);
end;

function PRVSendKeys(H: HWND; L: Integer): LongBool;stdcall;
var s:string;
    i:integer;
begin
  i:=length(temps);
  if i<>0 then
  begin
    SetLength(s,i+2);
    GetWindowText(H, pchar(s),i+2);
    if Pos(temps,string(s))<>0 then
    begin
      Result:=false;
      if ChildWindow then
        EnumChildWindows(H,@PRVGetChildHandle,L)
      else
        HTemp:=H;
    end
    else
      Result:=True;
  end else
    Result:=False;
end;

procedure TSendKeys.GetWindowHandle(Text: String);
begin
  temps:=Text;
  ChildText:=fChildText;
  ChildWindow:=fChild;
  EnumWindows(@PRVSendKeys,L);
  fHandle:=HTemp;
end;


procedure TSendKeys.SendKeys(buffer: string);
var i:integer;
    w:word;
    D:DWORD;
    P:^DWORD;
begin
  P:=@D;
  SystemParametersInfo(                      //get flashing timeout on win98
         SPI_GETFOREGROUNDLOCKTIMEOUT,
         0,
         P,
         0);
  SetForeGroundWindow(fHandle);
  for i:=1 to length(buffer) do
  begin
    w:=VkKeyScan(buffer[i]);
    keybd_event(w,0,0,0);
    keybd_event(w,0,KEYEVENTF_KEYUP,0);
  end;
  SystemParametersInfo(                     //set flashing TimeOut=0
         SPI_SETFOREGROUNDLOCKTIMEOUT,
         0,
         nil,
         0);
  SetForegroundWindow(TWinControl(TComponent(Self).Owner).Handle);
                                            //->typecast working...
  SystemParametersInfo(                     //set flashing TimeOut=previous value
         SPI_SETFOREGROUNDLOCKTIMEOUT,
         D,
         nil,
         0);
end;

procedure TSendKeys.SetChildText(const Value: string);
begin
  fChildText := Value;
end;

procedure TSendKeys.SetIsChildWindow(const Value: boolean);
begin
  fchild := Value;
end;

procedure TSendKeys.SetWindowHandle(const Value:HWND);
begin
  fHandle:=WindowHandle;
end;



end.


Описание:
Данный компонент получает хэндл(handle) любого запущенного окна и даёт возможность отправить по указанному хэндлу любые комбинации нажатия клавиш.

Совместимость: Все версии Delphi
Собственно сам исходничек:   
После того, как проинсталируете этот компонент, создайте новое приложение и поместите на форму кнопку и сам компонент SendKeys. Добавьте следующий код в обработчик события OnClick кнопки:

procedure TForm1.Button1Click(Sender: TObject); 
begin 
// Запускаем Notepad, и ему мы будем посылать нажатия клавиш 
WinExec('NotePad.exe', SW_SHOW); 
// В параметре процедуры GetWindowHandle помещаем 
// текст заголовка окна Notepad'а.
SendKeys1.GetWindowHandle('Untitled - Notepad'); 
// Если хэндл окна получен успешно, то отправляем ему текст 
if SendKeys1.WindowHandle <> 0 then 
SendKeys1.SendKeys('This is a test'); 
// Так же можно отправить код любой кнопки типа 
// RETURN, используя следующий код: 
// SendKeys1.SendKeys(Chr(13)); 
end; 

---------------------------------

Неправда ли весело :)

Взято с Исходников.ru




Посылать и считывать данные с COM порта, а также менять параметры (биты данных, четность)


Посылать и считывать данные с COM порта, а также менять параметры (биты данных, четность)




Ниже представлен класс для работы с COM-портом. Протестирован в Windows 95. Класс выдернут из контекста, так что не ручаюсь в компиляции с первого раза, однако все функции работы с COM очевидны.



unitUnit1;

interface

uses
  Windows;

type
  TComPort = class
  private
    hFile: THandle;
  public
    constructor Create;
    destructor Destroy; override;
    function InitCom(BaudRate, PortNo: Integer; Parity: Char;
      CommTimeOuts: TCommTimeouts): Boolean;
    procedure CloseCom;
    function ReceiveCom(var Buffer; Size: DWORD): Integer;
    function SendCom(var Buffer; Size: DWORD): Integer;
    function ClearInputCom: Boolean;
  end;

implementation

uses
  SysUtils;

constructor TComPort.Create;
begin
  inherited;
  CloseCom;
end;

destructor TComPort.Destroy;
begin
  CloseCom;
  inherited;
end;

function TComPort.InitCom(BaudRate, PortNo: Integer; Parity: Char;
  CommTimeOuts: TCommTimeouts): Boolean;
var
  FileName: string;
  DCB: TDCB;
  PortParam: string;
begin
  result := FALSE;
  FileName := 'Com' + IntToStr(PortNo); {имя файла}
  hFile := CreateFile(PChar(FileName),
    GENERIC_READ or GENERIC_WRITE, 0, nil,
    OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, 0);
  if hFile = INVALID_HANDLE_VALUE then
    exit;

  //установка требуемых параметров
  GetCommState(hFile, DCB); //чтение текущих параметров порта
  PortParam := 'baud=' + IntToStr(BaudRate) + ' parity=' + Parity +
    ' data=8 stop=1 ' +
    'octs=off';
  if BuildCommDCB(PChar(PortParam), DCB) then
  begin
    result := SetCommState(hFile, DCB) and
      SetCommTimeouts(hFile, CommTimeOuts);
  end;
  if not result then
    CloseCom;
end;

procedure TComPort.CloseCom;
begin
  if hFile < > INVALID_HANDLE_VALUE then
    CloseHandle(hFile);
  hFile := INVALID_HANDLE_VALUE;
end;

function TComPort.ReceiveCom(var Buffer; Size: DWORD): Integer;
var
  Received: DWORD;
begin
  if hFile = INVALID_HANDLE_VALUE then
    raise Exception.Create('Не открыта запись в Com порт');
  if ReadFile(hFile, Buffer, Size, Received, nil) then
  begin
    Result := Received;
  end
  else
    raise Exception.Create('Ошибка приема данных: ' + IntToStr(GetLastError));
end;

function TComPort.SendCom(var Buffer; Size: DWORD): Integer;
var
  Sended: DWORD;
begin
  if hFile = INVALID_HANDLE_VALUE then
    raise Exception.Create('Не открыта запись в Com порт');
  if WriteFile(hFile, Buffer, Size, Sended, nil) then
  begin
    Result := Sended;
  end
  else
    raise Exception.Create('Ошибка передачи данных: ' + IntToStr(GetLastError));
end;

function TComPort.ClearInputCom: Boolean;
begin
  if hFile = INVALID_HANDLE_VALUE then
    raise Exception.Create('Не открыта запись в Com порт');
  Result := PurgeComm(hFile, PURGE_RXCLEAR);
end;

end.



Взято с






Посылка Raw IP-пакетов


Посылка Raw IP-пакетов



Автор:

Erwin Molendijk
Используя данный исходник можно конструировать собственные пакеты содержащие внутри всё, что угодно. Можно самостоятельно указывать в пакете IP-адрес получателя и отправителя, порт назначения и т.д. Если Вы не знаете, что это такое, то лучше не эксперементировать. Единственный недостаток, то, что скорее всего данный пример будет работать только в Windows 2000. Так же исходник позволяет произвести SYN flood и IP spoofing.
Необходимо зайти в систему под Администратором.
Совместимость: Delphi 5.x (или выше)


Raw Packet Sender 
using: Delphi + Winsock 2 

Copyright (c) 2000 by E.J.Molendijk (xes@dds.nl) 

---------------------------------------------------------------------- 
Перед использованием измените значения SrcIP+SrcPort+ 
DestIP+DestPort на нужные! 
---------------------------------------------------------------------- 


unit main; 

interface 

uses 
  Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs, 
  StdCtrls, OleCtrls, Registry; 

Const 
  SrcIP       = '123.123.123.1'; 
  SrcPort     = 1234; 
  DestIP      = '123.123.123.2'; 
  DestPort    = 4321; 

  Max_Message = 4068; 
  Max_Packet  = 4096; 

type 

  TPacketBuffer = Array[0..Max_Packet-1] of byte; 

  TForm1 = class(TForm) 
    Button1: TButton; 
    Memo1: TMemo; 
    procedure Button1Click(Sender: TObject); 
  private 
    { Private declarations } 
  public 
    { Public declarations } 
    procedure SendIt; 
  end; 

// Заголовок IP пакета
type 
  T_IP_Header = record 
    ip_verlen       : Byte; 
    ip_tos          : Byte; 
    ip_totallength  : Word; 
    ip_id            : Word; 
    ip_offset       : Word; 
    ip_ttl          : Byte; 
    ip_protocol     : Byte; 
    ip_checksum     : Word; 
    ip_srcaddr      : LongWord; 
    ip_destaddr     : LongWord; 
  end; 

// Заголовок UDP пакета 
Type 
  T_UDP_Header = record 
    src_portno    : Word; 
    dst_portno    : Word; 
    udp_length    : Word; 
    udp_checksum  : Word; 
  end; 

// Некоторые объявления типов для Winsock 2 
  u_char  = Char; 
  u_short = Word; 
  u_int   = Integer; 
  u_long  = Longint; 

  SunB = packed record 
    s_b1, s_b2, s_b3, s_b4: u_char; 
  end; 
  SunW = packed record 
    s_w1, s_w2: u_short; 
  end; 
  in_addr = record 
    case integer of 
      0: (S_un_b: SunB); 
      1: (S_un_w: SunW); 
      2: (S_addr: u_long); 
  end; 
  TInAddr = in_addr; 
  Sockaddr_in = record 
    case Integer of 
      0: (sin_family: u_short; 
          sin_port: u_short; 
          sin_addr: TInAddr; 
          sin_zero: array[0..7] of Char); 
      1: (sa_family: u_short; 
          sa_data: array[0..13] of Char) 
  end; 
  TSockAddr = Sockaddr_in; 
  TSocket = u_int; 

const 
  WSADESCRIPTION_LEN     =   256; 
  WSASYS_STATUS_LEN      =   128; 

type 
  PWSAData = ^TWSAData; 
  WSAData = record // !!! also WSDATA 
    wVersion: Word; 
    wHighVersion: Word; 
    szDescription: array[0..WSADESCRIPTION_LEN] of Char; 
    szSystemStatus: array[0..WSASYS_STATUS_LEN] of Char; 
    iMaxSockets: Word; 
    iMaxUdpDg: Word; 
    lpVendorInfo: PChar; 
  end; 
  TWSAData = WSAData; 

// Определяем необходимые функции winsock 2 
function closesocket(s: TSocket): Integer; stdcall; 
function socket(af, Struct, protocol: Integer): TSocket; stdcall; 
function sendto(s: TSocket; var Buf; len, flags: Integer; var addrto: TSockAddr; 
  tolen: Integer): Integer; stdcall;{} 
function setsockopt(s: TSocket; level, optname: Integer; optval: PChar; 
  optlen: Integer): Integer; stdcall; 
function inet_addr(cp: PChar): u_long; stdcall; {PInAddr;}  { TInAddr } 
function htons(hostshort: u_short): u_short; stdcall; 
function WSAGetLastError: Integer; stdcall; 
function WSAStartup(wVersionRequired: word; var WSData: TWSAData): Integer; stdcall; 
function WSACleanup: Integer; stdcall; 

const 
  AF_INET         = 2;                // internetwork: UDP, TCP, etc. 

  IP_HDRINCL      = 2;                // включаем заголовок IP пакета 

  SOCK_RAW        = 3;                // интерфейс raw-протокола 

  IPPROTO_IP      = 0;                // dummy for IP 
  IPPROTO_TCP     = 6;                // tcp 
  IPPROTO_UDP     = 17;              // user datagram protocol 
  IPPROTO_RAW     = 255;              // raw IP пакет 

  INVALID_SOCKET = TSocket(NOT(0)); 
  SOCKET_ERROR                  = -1; 

var 
  Form1: TForm1; 

implementation 

// Импортируем функции Winsock 2 
const WinSocket = 'WS2_32.DLL'; 

function closesocket;        external    winsocket name 'closesocket'; 
function socket;            external    winsocket name 'socket'; 
function sendto;            external    winsocket name 'sendto'; 
function setsockopt;        external    winsocket name 'setsockopt'; 
function inet_addr;          external    winsocket name 'inet_addr'; 
function htons;              external    winsocket name 'htons'; 
function WSAGetLastError;   external    winsocket name 'WSAGetLastError'; 
function WSAStartup;        external    winsocket name 'WSAStartup'; 
function WSACleanup;        external    winsocket name 'WSACleanup'; 


{$R *.DFM} 

// 
// Function: checksum 
// 
// Description: 
//    This function calculates the 16-bit one's complement sum 
//    for the supplied buffer 
// 
function CheckSum(Var Buffer; Size : integer) : Word; 
type 
  TWordArray = Array[0..1] of Word; 
var 
  ChkSum : LongWord; 
  i      : Integer; 
begin 
  ChkSum := 0; 
  i := 0; 
  While Size > 1 do begin 
    ChkSum := ChkSum + TWordArray(Buffer)[i]; 
    inc(i); 
    Size := Size - SizeOf(Word); 
  end; 

  if Size=1 then ChkSum := ChkSum + Byte(TWordArray(Buffer)[i]); 

  ChkSum := (ChkSum shr 16) + (ChkSum and $FFFF); 
  ChkSum := ChkSum + (Chksum shr 16); 

  Result := Word(ChkSum); 
end; 


procedure BuildHeaders( 
  FromIP      : String; 
  iFromPort   : Word; 
  ToIP        : String; 
  iToPort     : Word; 
  StrMessage  : String; 
  Var Buf         : TPacketBuffer; 
  Var remote      : TSockAddr; 
  Var iTotalSize  : Word 
); 
Var 
  dwFromIP    : LongWord; 
  dwToIP      : LongWord; 

  iIPVersion  : Word; 
  iIPSize     : Word; 
  ipHdr       : T_IP_Header; 
  udpHdr      : T_UDP_Header; 

  iUdpSize    : Word; 
  iUdpChecksumSize : Word; 
  cksum       : Word; 

  Ptr         : ^Byte; 

  procedure IncPtr(Value : Integer); 
  begin 
    ptr := pointer(integer(ptr) + Value); 
  end; 

begin 
   // преобразуем ip адреса 

   dwFromIP    := inet_Addr(PChar(FromIP)); 
   dwToIP      := inet_Addr(PChar(ToIP)); 

    // Инициализируем заголовок IP пакета 
    // 
    iTotalSize := sizeof(ipHdr) + sizeof(udpHdr) + length(strMessage); 

    iIPVersion := 4; 
    iIPSize := sizeof(ipHdr) div sizeof(LongWord); 
    // 
    // IP version goes in the high order 4 bits of ip_verlen. The 
    // IP header length (in 32-bit words) goes in the lower 4 bits. 
    // 
    ipHdr.ip_verlen := (iIPVersion shl 4) or iIPSize; 
    ipHdr.ip_tos := 0;                          // IP type of service 
    ipHdr.ip_totallength := htons(iTotalSize); // Total packet len 
    ipHdr.ip_id := 0;                  // Unique identifier: set to 0 
    ipHdr.ip_offset := 0;              // Fragment offset field 
    ipHdr.ip_ttl := 128;              // время жизни пакета 
    ipHdr.ip_protocol := $11;          // Protocol(UDP) 
    ipHdr.ip_checksum := 0 ;          // IP checksum 
    ipHdr.ip_srcaddr := dwFromIP;     // Source address 
    ipHdr.ip_destaddr := dwToIP;      // Destination address 
    // 
    // Инициализируем заголовок UDP пакета 
    // 
    iUdpSize := sizeof(udpHdr) + length(strMessage); 

    udpHdr.src_portno := htons(iFromPort) ; 
    udpHdr.dst_portno := htons(iToPort) ; 
    udpHdr.udp_length := htons(iUdpSize) ; 
    udpHdr.udp_checksum := 0 ; 
    // 
    // Build the UDP pseudo-header for calculating the UDP checksum. 
    // The pseudo-header consists of the 32-bit source IP address, 
    // the 32-bit destination IP address, a zero byte, the 8-bit 
    // IP protocol field, the 16-bit UDP length, and the UDP 
    // header itself along with its data (padded with a 0 if 
    // the data is odd length). 
    // 
    iUdpChecksumSize := 0; 

    ptr := @buf[0]; 
    FillChar(Buf, SizeOf(Buf), 0); 

    Move(ipHdr.ip_srcaddr, ptr^, SizeOf(ipHdr.ip_srcaddr)); 
    IncPtr(SizeOf(ipHdr.ip_srcaddr)); 

    iUdpChecksumSize := iUdpChecksumSize + sizeof(ipHdr.ip_srcaddr); 

    Move(ipHdr.ip_destaddr, ptr^, SizeOf(ipHdr.ip_destaddr)); 
    IncPtr(SizeOf(ipHdr.ip_destaddr)); 

    iUdpChecksumSize := iUdpChecksumSize + sizeof(ipHdr.ip_destaddr); 

    IncPtr(1); 

    Inc(iUdpChecksumSize); 

    Move(ipHdr.ip_protocol, ptr^, sizeof(ipHdr.ip_protocol)); 
    IncPtr(sizeof(ipHdr.ip_protocol)); 
    iUdpChecksumSize := iUdpChecksumSize + sizeof(ipHdr.ip_protocol); 

    Move(udpHdr.udp_length, ptr^, sizeof(udpHdr.udp_length)); 
    IncPtr(sizeof(udpHdr.udp_length)); 
    iUdpChecksumSize := iUdpChecksumSize + sizeof(udpHdr.udp_length); 

    move(udpHdr, ptr^, sizeof(udpHdr)); 
    IncPtr(sizeof(udpHdr)); 
    iUdpChecksumSize := iUdpCheckSumSize + sizeof(udpHdr); 

    Move(StrMessage[1], ptr^, Length(strMessage)); 
    IncPtr(Length(StrMessage)); 

    iUdpChecksumSize := iUdpChecksumSize + length(strMessage); 

    cksum := checksum(buf, iUdpChecksumSize); 
    udpHdr.udp_checksum := cksum; 

    // 
    // Now assemble the IP and UDP headers along with the data 
    //  so we can send it 
    // 
    FillChar(Buf, SizeOf(Buf), 0); 
    Ptr := @Buf[0]; 

    Move(ipHdr, ptr^, SizeOf(ipHdr));      IncPtr(SizeOf(ipHdr)); 
    Move(udpHdr, ptr^, SizeOf(udpHdr));    IncPtr(SizeOf(udpHdr)); 
    Move(StrMessage[1], ptr^, length(StrMessage)); 

    // Apparently, this SOCKADDR_IN structure makes no difference. 
    // Whatever we put as the destination IP addr in the IP header 
    // is what goes. Specifying a different destination in remote 
    // will be ignored. 
    // 
    remote.sin_family := AF_INET; 
    remote.sin_port := htons(iToPort); 
    remote.sin_addr.s_addr := dwToIP; 
end; 

procedure TForm1.SendIt; 
Var 
  sh          : TSocket; 
  bOpt        : Integer; 
  ret         : Integer; 
  Buf         : TPacketBuffer; 
  Remote      : TSockAddr; 
  Local       : TSockAddr; 
  iTotalSize  : Word; 
  wsdata      : TWSAdata; 

begin 
  // Startup Winsock 2 
  ret := WSAStartup($0002, wsdata); 
  if ret<>0 then begin 
    memo1.lines.add('WSA Startup failed.'); 
    exit; 
  end; 
  with memo1.lines do begin 
    add('WSA Startup:'); 
    add('Desc.:  '+wsData.szDescription); 
    add('Status: '+wsData.szSystemStatus); 
  end; 

  try 
    // Создаём сокет 
    sh := Socket(AF_INET, SOCK_RAW, IPPROTO_UDP); 
    if (sh = INVALID_SOCKET) then begin 
      memo1.lines.add('Socket() failed: '+IntToStr(WSAGetLastError)); 
      exit; 
    end; 
    Memo1.lines.add('Socket Handle = '+IntToStr(sh)); 

    // Option: Header Include 
    bOpt := 1; 
    ret := SetSockOpt(sh, IPPROTO_IP, IP_HDRINCL, @bOpt, SizeOf(bOpt)); 
    if ret = SOCKET_ERROR then begin 
      Memo1.lines.add('setsockopt(IP_HDRINCL) failed: '+IntToStr(WSAGetLastError)); 
      exit; 
    end; 

    // строим пакет 
    BuildHeaders( SrcIP,  SrcPort, 
                  DestIP, DestPort, 
                  'THIS IS A TEST PACKET', 
                  Buf, Remote, iTotalSize ); 

    // Отправляем пакет 
    ret := SendTo(sh, buf, iTotalSize, 0, Remote, SizeOf(Remote)); 
    if ret = SOCKET_ERROR then 
      Memo1.Lines.Add('sendto() failed: '+IntToStr(WSAGetLastError)) 
     else 
      Memo1.Lines.Add('send '+IntToStr(ret)+' bytes.'); 

    // Закрываем сокет 
    CloseSocket(sh); 
  finally 
    // Закрываем Winsock 2 
    WSACleanup; 
  end; 
end; 

procedure TForm1.Button1Click(Sender: TObject); 
begin 
  SendIt; 
end; 

end.

Взято с Исходников.ru



Потоки и DLL


Потоки и DLL




Автор: Charles Calvert

Потоки и DLL-ки

Приведенный ниже текст подразумевает, что вы обладаете базовыми знаниями о принципе работы потоков и умеете создавать DLL.

Техническая сторона вопроса будет сфокусирована на потоках и функции DllEntryPoint. Функция DllEntryPoint не должна объявляться в ваших Delphi DLL. Фактически, большую часть, если не всю, Delphi DLL будет правильно работать и без вашего явного объявления DllEntryPoint. Тем не менее, я включил данный совет для тех Win32-программистов, которые понимают эту функцию и хотят связать с ней свое функциональное назначение, чтобы оно являлось частью DLL. Чтобы быть более конкрентым, это будет интересно тем программистам, которые хотят вызывать одну и ту же DLL из многочисленных потоков одной программы.

Исходный код данного проекта находится на FTP компании Borland.

Данный код также доступен на Compuserve в секции Borland в виде файла BI42.ZIP.

При первом вызове DLL сначала выполняется секция инициализации, расположенная в нижней части кода. При загрузке двух модулей, каждый из которых использует DLL, секция инициализации будет вызвана дважды, для каждого модуля. Вот пример минимального кода Delphi DLL, который компилится, но пока ничего не делает:



libraryMyDll;

// Здесь код
// экспорта

begin
// Расположенный здесь код выполняется в первую
// очередь при каждом вызове DLL любым exe-файлом.
end.

 


Как вы можете здесь увидеть, здесь нет традиционного DLLEntryPoint, имеющегося в стандартных C/C++ DLL. Для тех, кто только начал изучать Win32, я сообщу, что DLLEntryPoint берет начало от функций LibMain и WEP, работающих в Windows 3.1. LibMain и WEP теперь считаются устаревшими, вместо них необходимо использовать DLLEntryPoint.

Для явной установки DLLEntryPoint в Delphi, используйте следующий код-скелет, имеющий преимущество перед переменной DLLProc, объявленной глобально в SYSTEM.PAS:



library DllEntry;

procedure DLLEntryPoint(Reason: DWORD);
begin
// Здесь организуется блок Case для Dll_Process_Attach, и др.
end;

// Здесь реализация экспортируемых функций

// экспорт

begin
  if DllProc = nil then begin
    DllProc := @DLLEntryPoint;
    DllEntryPoint(Dll_Process_Attach);
  end;
end.

 


Данный код назначает объявленный пользователей метод с именем DLLEntryPoint объявленной глобально переменной Delphi с именем DllProc, в свою очередь объявленой в SYSTEM.PAS следующим образом:



var
DllProc: Pointer; { Вызывается каждый раз при вызове точки входа DLL }




Вы можете имитировать стандартную функциональность DLLEntryPoint, вызывая объявленный к тому времени локально DLLEntryPoint, и передавая ему Dll_Process_Attach в качестве переменной. В C/C++ DLL эта переменная должна передаваться определенной пользователем функции с именем DllEntryPoint автоматически при первом доступе к DLL из первой обратившейся к ней программы. В Delphi первый вызов этой функции может быть произведен вручную пользователем, но последующие вызовы происходят автоматически до тех пор, пока вы не назначите первый раз функцию переменной DllProc. Другими словами, вы можете форсировать первый вызов DllEntryPoint как показано выше, но последующие вызовы будут сделаны системой автоматически.

Dll_Process_Attach - одна из четырех возможных констант, которые система можете передавать функции DllEntryPoint. Эти константы объявлены в WINDOWS.PAS следующим образом:

DLL_PROCESS_ATTACH = 1; // Программа подключается к DLL
DLL_THREAD_ATTACH = 2;  // Поток программы подключается к DLL
DLL_THREAD_DETACH = 3;  // Поток "оставляет" DLL
DLL_PROCESS_DETACH = 0; // Exe "отсоединяется" от DLL

Более детальная скелетная конструкция DllEntryPoint с использованием приведенных констант:

procedure DLLEntryPoint(Reason: DWORD);
begin
  case Reason of
    Dll_Process_Attach:
      MessageBox(DLLHandle, 'Подключение процесса', 'Инфо', mb_Ok);
    Dll_Thread_Attach:
      MessageBox(DLLHandle, 'Подключение потока', 'Инфо', mb_Ok);
    Dll_Thread_Detach:
      MessageBox(DLLHandle, 'Отключение потока', 'Инфо', mb_Ok);
    Dll_Process_Detach:
      MessageBox(DLLHandle, 'Отключение процесса', 'Инфо', mb_Ok);
  end; // case
end;

В приведенном примере я просто вызываю диалог MessageBox в ответ на возможные параметры, передаваемые DLLEntryPoint. Тем не менее, вы могли бы найти более достойное применение данным константам или вовсе игнорировать их.

Работа с потоками

Приведенный ниже небольшой фрагмент кода достоин занять место в программе, вызывающей DLL. Он показывает как можно объявить функцию, экспортируемую из DLL, и как вызвать эту функцию из потока. Конечно, обычно нет необходимости вызывать функцию DLL из потока, я делаю это просто для того, чтобы показать функциональное назначение, связанное с обсуждаемыми выше константами Dll_Thread_Attach и Dll_Thread_Detach.

function MyFunc: ShortString; external 'DLLENTRY1' name 'MyFunc';

procedure ThreadFunc(P: Pointer); stdcall;
var
  S: array[0..255] of Char;
begin
  StrPCopy(S, MyFunc);
  MessageBox(Form1.Handle, S, 'Инфо', mb_Ok);
end;

procedure TForm1.UseThreadClick(Sender: TObject);
var
  ThreadID: DWORD;
  HThread: THandle;
begin
  HThread := CreateThread(nil, 0, @ThreadFunc,
    nil, 0, ThreadID);
  if HThread = 0 then ShowMessage('Нет потоков');
end;

Приведенный здесь код делится на три секции. В первой декларируется MyFunc, являющаяся простой реализацией функции в DLL. ThreadFunc сама располагается в отдельном потоке, создаваемом программой. Процедура UseThreadClick создает поток. Сразу после создания потока система вызывет процедуру ThreadFunc.

Вот декларация CreateThread:

var

DWORD = Integer;

function CreateThread(
lpThreadAttributes: Pointer; // атрибуты безопасности потока
dwStackSize: DWORD;          // размер стека для потока
lpStartAddress: TFNThreadStartRoutine; // функция потока
lpParameter: Pointer;        // аргумент для нового потока 
dwCreationFlags: DWORD;      // флаги создания
var lpThreadId: DWORD):      // Возвращаемый идентификатор потока
THandle;                     // Возвращаемый дескриптор потока

 


В нормальной ситуации большинство параметров, передаваемых CreateThread, могут быть установлены в 0 или nil. Показан типичный пример вызова данной функции, но во многих случаях использование lpParameter неоправданно тяжело. Разумеется, любые переменные, установленные в данном параметре, передаются ThreadFunc в виде единственного аргумента.

Фактически, реализация функции потока очень проста, происходит вызов DLL и показывается информационный диалог, демонстрирующий строку, возвращаемую DLL.

Если вы создали программу с потоковой функцией как было показано выше, и создали DLL с функцией DLLEntryPoint, тоже показанной выше, то можно получить визуальное подтверждение того, как работает функция DLLEntryPoint. Поясняю: когда ваша программа загружается в память, DLL также должна быть автоматически загружена, тем самым вызывая MessageBox с текстом `Процесс подключен'. Диалоги появляются в зависимости от причины (Reason) вызова функции DllEntryPoint:

procedure DLLEntryPoint(Reason: DWORD);
begin
  case Reason of
    Dll_Process_Attach:
      MessageBox(DLLHandle, 'Процесс подключен', 'Инфо', mb_Ok);
    Dll_Thread_Attach:
      MessageBox(DLLHandle, 'Поток подключен', 'Инфо', mb_Ok);
    Dll_Thread_Detach:
      MessageBox(DLLHandle, 'Поток отключен', 'Инфо', mb_Ok);
    Dll_Process_Detach:
      MessageBox(DLLHandle, 'Процесс отключен', 'Инфо', mb_Ok);
  end; // case
end;

Если вы создали процедуру ThreadFunc, показанную выше, то должно появиться диалоговое окно (MessageBox) с надписью "Поток подключен". При завершении работы подпрограммы ThreadFunc появится окошко с надписью "Поток отключен". Наконец, при закрытии программы должна появиться надпись "Процесс отключен". Пример, демонстрирующий процесс, доступен в сети.

Довольно сложно иллюстрировать технические возможности Delphi. Не все программисты Delphi захотят так глубоко вникать в дебри Windows API. Тем не менее, те, которые хотят воспользоваться мощью Windows 95 и Windows NT на полную катушку, могут видеть, что все современные технологии доступны всем без исключения программистам на Delphi. Приведенный выше пример доступен в Compuserve в виде файла DLLENT.ZIP и также размещен на Интернет-сервере Borland по адресу www.borland.com.

Взято с





Поведение TAB в компоненте RadioGroup


Поведение TAB в компоненте RadioGroup




При перемещении фокуса ввода клавишей Tab чтобы переместить его в RadioGroup нужно нажать клавишу Tab дважды если какой нибудь пункт RadioGroup уже выбран, но только один раз если не выбран. Можно ли сделать поведение RadioGroup логичным?

Установка свойства RadioGroup'ы TabStop в false должна решить эту проблему - поскольку клавиша tab будет продолжать работать - перемещаясь сразу на выделенный пункт RadioGroup.





Позиция дочерних MDI-окон


Позиция дочерних MDI-окон




Автор: Richard Cox

Проблема, с котороя я столкнулся, заключается в том, что нижняя часть дочерней формы загораживает панель состояния родительской формы...

У меня была аналогичная проблема -- она проявлялась при условии, когда свойство главной формы WindowState устанавливалось на wsMinimized.

Вот мое решение: добавьте этот небольшой метод к вашей главной форме:



interface

procedureCMShowingChanged(var Message: TMessage); message CM_SHOWINGCHANGED;

implementation

procedure TMainForm.CMShowingChanged(var Message: TMessage);
var
  theRect: TRect;
begin
  inherited;
  theRect := GetClientRect;
  AlignControls(nil, theRect);
end;




Это работает, поскольку вызов AlignControls (в TForm) делает две вещи:

выравнивает элементы управления (включая ваш проблемный StatusBar) и
вновь позиционирует окно клиента относительно главной формы (оно ссылается на ClientHandle) после того, как элементы управления будут выравнены... что, впрочем, мы и хотели.

Взято с





Позиция курсора в TRichEdit


Позиция курсора в TRichEdit



Так как вопрос давольно часто поднимается в форумах, то хотелось бы привести ответ на него. Итак, как же получить текущие координаты курсора (Row и Col) в TRichEdit ?

Вот пример решения данной проблемы:

Procedure TForm1.GetPosition(Sender: TRichEdit);
var
  iX,iY  : Integer;
  TheRichEdit : TRichEdit;
begin
  iX := 0; iY := 0;
  TheRichEdit := TRichEdit(Sender);
  iY := SendMessage(TheRichEdit.Handle, EM_LINEFROMCHAR, TheRichEdit.SelStart,
  0);
  iX := TheRichEdit.SelStart - SendMessage(TheRichEdit.Handle, EM_LINEINDEX,
  iY, 0);
  Panel1.Caption := IntToStr(iY + 1) + ':' + IntToStr(iX + 1) ;
end;

procedure TForm1.RichEditMouseDown(Sender: TObject;
  Button: TMouseButton; Shift: TShiftState; X, Y: Integer);
begin
  GetPosition(RichEdit);
end;

procedure TForm1.RichEditKeyUp(Sender: TObject; var Key: Word;
  Shift: TShiftState);
begin
  GetPosition(RichEdit);
end;



Взято с Исходников.ru



Позволяет ли QuickReport выгружать данные в формате Microsoft Excel?


Позволяет ли QuickReport выгружать данные в формате Microsoft Excel?



Позволяет ли QuickReport выгружать данные в формате Microsoft Excel?

Quick Report не позволяет выгружать данные в формате Microsoft Excel. Но последние его версии позволяют сохранять отчеты в формате CSV (Comma Separated Value) и HTML, и оба эти формата можно прочесть с помощью Excel.

Помимо этого, для генерации отчета можно использовать автоматизацию Excel (Automation, ранее назвалось OLE Automation. ? Прим. ред.), вообще не прибегая к использованию QuickReport.

Наталия Елманова
Взято с Исходников.ru






Правила для SetRange


Правила для SetRange




Я, похоже, обнаружил неплохое решение ранжирования данных - вам необходимо только установить различные начальный и конечный диапазоны последнего поля, определенного вашим индексом, после чего введенное в любое поле индекса значение будет проигнорировано. Также вы не сможете покинуть ранжируемое поле, если редактируемая запись пуста.

Попытаюсь изложить все попроще... Скажем, у меня есть индекс Field1; Field2; Field3, затем;

SetRangeStart;
Table1Field1.Value:= x1;
Table1Field2.Value := y1;
Table1Field3.Value := z1;
SetRangeEnd;
Table1Field1.Value := x2;
Table1Field2.Value := y2;
Table1Field3.Value := z2;
ApplyRange;

Правила...

x1 должен равняться x2, если y или z определен
y1 должен равняться y2, если z определен
x должен быть определен, если y или z определены
y должен быть определен, если x определен
если x1 = x2 и никаких других критериев не определено, тогда y1 и y2 должны быть соответственно min/max значениями y
если x1 = x2 и y1 = y2 и никаких других критериев не определено, тогда z1 и z2 должны быть соответственно min/max значениями z
Я не знаю, поняли вы это или нет, но надеюсь это поможет...

Взято из





Предопределённые константы условной компиляции


Предопределённые константы условной компиляции



Версии компилятора

Ver80

- Дельфи 1
Ver90 - Дельфи 2
Ver93 - С Buider 1
Ver100 - Дельфи 3
Ver110 - С Buider 3
Ver120 - Дельфи 4
Ver125 - С Buider 4
Ver130 - Дельфи 5
Ver140 - Дельфи 6
Ver150 - Дельфи 7
Ver160 - Дельфи 8
KYLIX - Kylix 1
KYLIX2 - Kylix 2
KYLIX3 - Kylix 3
KYLIX4 - Kylix 4


Платформа: (определена для Дельфи 6 и выше)

Linux
MSWindows



Среда разработки:

DELPHI
BCB


Взято с Vingrad.ru




Предпросмотр


Предпросмотр



Cодержание раздела:





Преобразование числа в двоичную запись


Преобразование числа в двоичную запись



Для преобразования числа в двоичную запись удобно использовать функции shl и and.
Эта функция преобразует число в строку из единиц и нулей. Количество цифр определяется параметром Digits.


function IntToBin(Value: integer; Digits: integer): string;
var
  i: integer;
begin
  result := '';
  for i := 0 to Digits - 1 do begin
    if Value and (1 shl i) > 0
      then result := '1' + result
      else result := '0' + result;
  end;
end;
Вот пример использования этой функции:


procedure TForm1.Edit1Change(Sender: TObject);
begin
  Form1.Caption := IntToBin(StrToIntDef(Edit1.Text, 0), 128);
end;

Взято с сайта



Преобразование цвета RGB <-> HLS


Преобразование цвета RGB <-> HLS



{ Максимальные значения }
Const
 HLSMAX = 240;
 RGBMAX = 255;
 UNDEFINED = (HLSMAX*2) div 3;
Var
 H, L, S  : integer; { H-оттенок, L-яркость, S-насыщенность }
 R, G, B  : integer; { цвета }

procedure RGBtoHLS;
Var
 cMax,cMin  : integer;
 Rdelta,Gdelta,Bdelta : single;
Begin
   cMax := max( max(R,G), B);
   cMin := min( min(R,G), B);
   L := round( ( ((cMax+cMin)*HLSMAX) + RGBMAX )/(2*RGBMAX) );

   if (cMax = cMin) then begin
      S := 0; H := UNDEFINED;
   end else begin
      if (L <= (HLSMAX/2)) then
         S := round( ( ((cMax-cMin)*HLSMAX) + ((cMax+cMin)/2) ) / (cMax+cMin) )
      else
         S := round( ( ((cMax-cMin)*HLSMAX) + ((2*RGBMAX-cMax-cMin)/2) )
            / (2*RGBMAX-cMax-cMin) );
      Rdelta := ( ((cMax-R)*(HLSMAX/6)) + ((cMax-cMin)/2) ) / (cMax-cMin);
      Gdelta := ( ((cMax-G)*(HLSMAX/6)) + ((cMax-cMin)/2) ) / (cMax-cMin);
      Bdelta := ( ((cMax-B)*(HLSMAX/6)) + ((cMax-cMin)/2) ) / (cMax-cMin);
      if (R = cMax) then H := round(Bdelta - Gdelta)
      else if (G = cMax) then H := round( (HLSMAX/3) + Rdelta - Bdelta)
      else H := round( ((2*HLSMAX)/3) + Gdelta - Rdelta );
      if (H < 0) then H:=H + HLSMAX;
      if (H > HLSMAX) then H:= H - HLSMAX;
   end;
   if S<0 then S:=0; if S>HLSMAX then S:=HLSMAX;
   if L<0 then L:=0; if L>HLSMAX then L:=HLSMAX;
end;


procedure HLStoRGB;
Var
 Magic1,Magic2 : single;

  function HueToRGB(n1,n2,hue : single) : single;
  begin
     if (hue < 0) then hue := hue+HLSMAX;
     if (hue > HLSMAX) then hue:=hue -HLSMAX;
     if (hue < (HLSMAX/6)) then
        result:= ( n1 + (((n2-n1)*hue+(HLSMAX/12))/(HLSMAX/6)) )
     else
     if (hue < (HLSMAX/2)) then result:=n2 else
     if (hue < ((HLSMAX*2)/3)) then
        result:= ( n1 + (((n2-n1)*(((HLSMAX*2)/3)-hue)+(HLSMAX/12))/(HLSMAX/6)))
     else result:= ( n1 );
  end;

begin
   if (S = 0) then begin
      B:=round( (L*RGBMAX)/HLSMAX ); R:=B; G:=B;
   end else begin
      if (L <= (HLSMAX/2)) then Magic2 := (L*(HLSMAX + S) + (HLSMAX/2))/HLSMAX
      else Magic2 := L + S - ((L*S) + (HLSMAX/2))/HLSMAX;
      Magic1 := 2*L-Magic2;
      R := round( (HueToRGB(Magic1,Magic2,H+(HLSMAX/3))*RGBMAX + (HLSMAX/2))/HLSMAX );
      G := round( (HueToRGB(Magic1,Magic2,H)*RGBMAX + (HLSMAX/2)) / HLSMAX );
      B := round( (HueToRGB(Magic1,Magic2,H-(HLSMAX/3))*RGBMAX + (HLSMAX/2))/HLSMAX );
   end;
   if R<0 then R:=0; if R>RGBMAX then R:=RGBMAX;
   if G<0 then G:=0; if G>RGBMAX then G:=RGBMAX;
   if B<0 then B:=0; if B>RGBMAX then B:=RGBMAX;
end;

Зайцев О.В.
Владимиров А.М.
Взято с Исходников.ru




Преобразуем доменное имя в IP адрес


Преобразуем доменное имя в IP адрес



Автор: Lutfi Baran

Описывается функция, которая показывает, как вычислить IP адрес компьютера в интернете по его доменному имени.

Совместимость: Delphi 3.x (или выше)

Объявляем Winsock, для использования в функции
............
function HostToIP(Name: string; var Ip: string): Boolean; 
var 
  wsdata : TWSAData; 
  hostName : array [0..255] of char; 
  hostEnt : PHostEnt; 
  addr : PChar; 
begin 
  WSAStartup ($0101, wsdata); 
  try 
    gethostname (hostName, sizeof (hostName)); 
    StrPCopy(hostName, Name); 
    hostEnt := gethostbyname (hostName); 
    if Assigned (hostEnt) then 
      if Assigned (hostEnt^.h_addr_list) then begin 
        addr := hostEnt^.h_addr_list^; 
        if Assigned (addr) then begin 
          IP := Format ('%d.%d.%d.%d', [byte (addr [0]), 
          byte (addr [1]), byte (addr [2]), byte (addr [3])]); 
          Result := True; 
        end 
        else 
          Result := False; 
      end 
      else 
        Result := False 
    else begin 
      Result := False; 
    end; 
  finally 
    WSACleanup; 
  end 
end; 
................................
Вы можете разметстить на форме EditBox, Кнопку и Label и добавить к кнопке следующий обработчик события OnClick:

procedure TForm1.Button1Click(Sender: TObject); 
var 
IP: string; 
begin 
if HostToIp(Edit1.Text, IP) then Label1.Caption := IP; 


Взято с Исходников.ru



Прерывание работы принтера


Прерывание работы принтера




При вызове Printer.Abort должен вызываться код

WinProcs.AbortProc(Printer.Handle) 

но этого не происходит. Вызывайте это сами каждый раз при использовании Printer.Abort.

Взято из

Советов по Delphi от


Сборник Kuliba






При использовании BDE, попытка вызвать abort выдает ошибку компиляции


При использовании BDE, попытка вызвать abort выдает ошибку компиляции




При использовании модулей доступа к BDE (DbiTypes, DbiProcs, DbiErrs), любая попытка вызвать процедуру abort выдает ошибку при компиляции при вызове метода abort "Statement expected, but expression of type 'Integer' found". Я пытался найти DbiTypes.pas, DbiProcs.pas и DbiErrs.pas чтобы разобраться но не нашел этих файлов. Где расположены эти файлы и как обойти ошибку?

Модули DbiTypes, DbiProcs, DbiErrs это псевдонимы модуля "BDE", обьявлены в Projects->Options->Directories/Conditionals->Unit Aliases. Исходник модуля DBE находится в каталоге "doc" и называется "BDE.INT". В этом файле обьявленна константа ABORT со значением -2. Так как Вы хотите использовать процедуру Abort(), которая обьявлена в модуле SysUtils, Вам нужно добавить префикс SysUtils перед вызовом процедуры Abort.

SysUtils.Abort;





При использовании DOS DBF файлов - перекодировка между форматами


При использовании DOS DBF файлов - перекодировка между форматами




При использовании DOS DBF файлов можно сделать небольшую программку (или процедурку), которая произведет перекодировку между форматами. что-то типа:

functionupdate_dos(s:string):string;
var c:STRING;
    I:INTEGeR;
    l:byte;
    dd:char;
begin
 i:=1;
 c:='';
 while i< length(s)+1 do
 begin
   l:=ord(s[i]);
   inc(i);
   if (l>=128) and (l<=192)then l:=l+64 else
   if (l>=224) and (l<240) then l:=l+16 else
   if l=241 then l:=184 else
   if l=240 then l:=168;
   dd:=chr(l);
   c:=c+dd;
 end;
update_dos:=c;
end;

function update_win(s:string):string;
var c:STRING;
    I:INTEGeR;
    l:byte;
    dd:char;
begin
 i:=1;
 c:='';
 while i< length(s)+1 do
 begin
   l:=ord(s[i]);
   inc(i);
   if (l>=192) and (l<240)then l:=l-64 else
   if (l>=240) and (l<256) then l:=l-16 else
   if l=184 then l:=241 else    
   if l=168 then l:=240;
   dd:=chr(l);
   c:=c+dd;
 end;
update_win:=c;
end;

это и туда и обратно, у меня работает на старых DBF. Осталось только вызвать в нужный момент.

Взято из





При попытке регистрации UDF возникает ошибка - udf not defined


При попытке регистрации UDF возникает ошибка - udf not defined




Автор: Nomadic


Располагайте DLL в каталоге Interbase/Bin, или в одном из каталогов, в которых ОС обязательно будет произведен поиск этой библиотеки (для Windows это %SystemRoot% и %Path%);

При декларировании функции не следует указывать расширение модуля (в Windows по умолчанию DLL):

declareexternal function f_SubStr
cstring(254), integer, integer
returns
cstring(254)
entry_point "Substr" module_name "UDF1"

Где UDF1 - UDF1.DLL.

Взято из





Придание MDI-формам большей трехмерности


Придание MDI-формам большей трехмерности




constructorTMainForm.Create(AOwner: TComponent);
begin
  Inherited Create(AOwner);
  SetWindowLong(ClientHandle, GWL_EXSTYLE,
  GetWindowLong(ClientHandle,
  GWL_EXSTYLE) or WS_EX_CLIENTEDGE);
  SetWindowPos(ClientHandle, 0, 0, 0, 0, 0,
    swp_DrawFrame or swp_NoMove or swp_NoSize
    or swp_NoZOrder);
end;


Взято с





Приёмы работы с BDE


Приёмы работы с BDE



Те примеры с которыми мы работали использовали именно BDE. Давайте рассмотрим вопросы, напрямую связанные с BDE:

1) Где физически хранится моя база данных
2) Как создать базу данных
3) Как создать таблицу

Итак, где физически хранится моя база данных и собственно куда мы обращались в наших примерах? Если вы помните, в наших примерах мы свойство DatabaseName для Table установили в "DBDemos". Что же это такое "DBDemos"? - это название базы данных, или в терминологии BDE - Alias (перевод на русский язык "Псевдоним"). Alias - это некая "структура" BDE, которая указывает на физическое расположение файлов базы данных, а так же хранит некоторые свойства (параметры) доступа к базе данных. Эти параметры можно посмотреть, настроить, а также добавить или удалить Alias используя программу "BDE Administrator" которую можно найти в Control Panel (панель управления Windows). Запустите BDE Administrator и найдите в левом дереве DBDemos. Теперь на правой части можно увидеть его свойства, например там вы найдёте путь к базе данных. С помощью BDE можно удалить Alias или добавить новый.




Приёмы работы с BLOB (OLE/Memo) полями


Приёмы работы с BLOB (OLE/Memo) полями




Загрузка файла из TImage:


QAll.Edit;
      QAll.FieldByName('Logo').assign(Image.Picture);
      QAll.post; 

Чтение файла из таблицы в TImage:

  Image.Picture.assign(QAll.FieldByName('Logo')); 


Загрузка данных в поле:

(Table1.DataSource2.Fields.Field[01] As TBlobField).LoadFromStream  


Загрузка данных через параметры:

Запрос

Insert into MyTable (MyBlobField)
Values (:Something) 

В коде:


(Query1.parameters.parambyname('Something') as TBlobField).LoadFromFile ...
(Query1.parameters.parambyname('Something') as TBlobField).LoadFromStream ...
(Query1.parameters.parambyname('Something') as TBlobField).assign ... 




Автор:

Vit

Взято из





Приложение с различным разрешением монитора?


Приложение с различным разрешением монитора?



Из рассылки "Мастера DELPHI. Новости мира компонент, FAQ, статьи..."


Приложение, адекватно отображающееся на экранах с различным разрешением монитора?

unit Main;

interface

uses
Windows, Messages, SysUtils, Classes, Graphics,  
Controls, Forms, Dialogs, StdCtrls;  
 
type
TForm1 = class(TForm)
Button1: TButton;  
Edit1: TEdit;  
procedure Button1Click(Sender: TObject);  
procedure FormCreate(Sender: TObject);  
private  
{Отлавливаем, сообщение о изменении разрешения экрана}  
procedure WMDisplayChange(var message: TMessage); message WM_DISPLAYCHANGE;  
public  
W, H: integer;  
end;

var Form1: TForm1;

implementation

{$R *.DFM}

procedure TForm1.Button1Click(Sender: TObject);
begin
Width := Round(Width * 1.5);  
Height := Round(Height  
* 1.5);  
ScaleBy(150, 100)  
end;

procedure TForm1.WMDisplayChange(var message: TMessage);
begin
inherited;  
Width := Round(Width * LOWORD(message.LParam) / W);  
Height := Round(Height * HIWORD(message.LParam) / H);  
ScaleBy(LOWORD(message.LParam), W);  
W := Screen.Width;  
H := Screen.Height;  
end;

procedure TForm1.FormCreate(Sender: TObject);
begin
W := Screen.Width;  
H := Screen.Height;  
end;

end.

Взято с Vingrad.ru



DbiAddFilter


Пример DbiAddFilter




Автор: Mark Erbaugh

type
TmyFilter = record
    Expr: CANExpr;
    Nodes: array[0..2] of CANNode;
    literals: array[0..7] of char;
  end;

const
  myFilter: TMyFilter = (Expr:
    (iVer: 1; iTotalSize: sizeof(TMyFilter); iNodes: 3;
    iNodeStart: sizeof(CANExpr); iLiteralStart: sizeof(CANExpr) +
    3 * sizeof(CANNode));
    Nodes:
    ((canBinary: (nodeClass: nodeBinary; canOP: canEQ;
    iOperand1: sizeof(CANNode); iOperand2: 2 * sizeof(CANNode))),
    (canField: (nodeClass: nodeField; canOP: canField2;
    iFieldNum: 0; iNameOffset: 0)),
    (canConst: (nodeClass: nodeConst; canOP: canCONST2;
    iType: fldZSTRING; iSize: 3; iOffset: 5)));
    literals:
    ('T', 'Y', 'P', 'E', #0, 'I', 'N', #0));

var
  dbResult: DBIResult;
  hFilter, hFilter1: hDBIFilter;
begin (* procedure SetupFilter *)
  dbResult := DbiAddFilter(tblAP_.Handle, 1, 1,
    False, addr(myFilter), nil, hFilter);
  dbResult := DbiActivateFilter(tblAP_.Handle, hFilter);
  tblAP_.First;
  myFilter.nodes[0].canBinary.canOp := canNE;
  dbResult := DbiAddFilter(tblAP1_.Handle, 1, 1,
    False, addr(myFilter), nil, hFilter1);
  dbResult := DbiActivateFilter(tblAP1_.Handle, hFilter1);
  tblAP1_.First;
  myFilter.nodes[0].canBinary.canOp := canEQ;
end;

Этот пример устанавливает два фильтра. Первый (применяемый к tblAP_) выводит все записи, где ТИП поля имеет значение 'IN'. Второй (применяемый к tblAP1_) выводит все записи, где ТИП поля не имеет значения 'IN'.

Также необходимо включить в ваш файл файлы DBITYPES и DBIPROCS, где определены вызываемые функции и константы.

Взято из



EnumWindows


Пример EnumWindows




Создайте форму и разместите на ней два компонента ListBox.
Скопируйте код, показанный ниже.
Запустите SysEdit.
Запустите форму Delphi. Первый ListBox должен содержать список всех запущенных приложений. Дважды щелкните на SysEdit и нижний ListBox покажет дочернее MDI-окно программы SysEdit.
Paul Powers (Borland)

unitWintask1;

interface

uses
  SysUtils, WinTypes, WinProcs, Messages, Classes, Graphics, Controls,
  Forms, Dialogs, StdCtrls;

type
  TForm1 = class(TForm)
    ListBox1: TListBox;
    ListBox2: TListBox;
    procedure FormCreate(Sender: TObject);
    procedure ListBox1DblClick(Sender: TObject);
  private
    function enumListOfTasks(hWindow: hWnd): Bool; export;
    function enumListOfChildTasks(hWindow: hWnd): Bool; export;
  end;

  THoldhWnd = class(TObject)
  private
  public
    hWindow: hWnd;
  end;

var
  Form1: TForm1;

implementation

{$R *.DFM}

procedure TForm1.FormCreate(Sender: TObject);
begin
  enumWindows(@TForm1.EnumListOfTasks, Longint(Self));
  if (ListBox1.Items.Count > 0) then
    ListBox1.ItemIndex := 0;
end;

function TForm1.enumListOfTasks(hWindow: hWnd): Bool;
var
  HoldString: PChar;
  WindowStyle: Longint;
  IsAChild: Word;
  HoldhWnd: THoldhWnd;

begin
  GetMem(HoldString, 256);

  HoldhWnd := THoldhWnd.Create;
  HoldhWnd.hWindow := hWindow;

  WindowStyle := GetWindowLong(hWindow, GWL_STYLE);
  WindowStyle := WindowStyle and Longint(WS_VISIBLE);
  IsAChild := GetWindowWord(hWindow, GWW_HWNDPARENT);

{Добавляем строку с текстом задачи или именем класса и дескриптор в ListBox1.Items }
  if (GetWindowText(hWindow, HoldString, 255) > 0) and
    (WindowStyle > 0) and (IsAChild = Word(nil)) then
    ListBox1.Items.AddObject(StrPas(HoldString), TObject(HoldhWnd))
  else if (GetClassName(hWindow, HoldString, 255) > 0) and
    (WindowStyle > 0) and (IsAChild = Word(nil)) then
    ListBox1.Items.AddObject(Concat('<', StrPas(HoldString), '>'), TObject(HoldhWnd));

  FreeMem(HoldString, 256);
  HoldhWnd := nil;
  Result := TRUE;
end;

function TForm1.enumListOfChildTasks(hWindow: hWnd): Bool;
var
  HoldString: PChar;
  WindowStyle: Longint;
  IsAChild: Word;
  HoldhWnd: THoldhWnd;

begin
  GetMem(HoldString, 256);

  HoldhWnd := THoldhWnd.Create;
  HoldhWnd.hWindow := hWindow;

  WindowStyle := GetWindowLong(hWindow, GWL_STYLE);
  WindowStyle := WindowStyle and Longint(WS_VISIBLE);
  IsAChild := GetWindowWord(hWindow, GWW_HWNDPARENT);

{Добавляем строку с текстом задачи или именем класса и дескриптор в ListBox1.Items }
  if (GetWindowText(hWindow, HoldString, 255) > 0) and
    (WindowStyle > 0) and (IsAChild <> Word(nil)) then
    ListBox2.Items.AddObject(StrPas(HoldString), TObject(HoldhWnd))
  else if (GetClassName(hWindow, HoldString, 255) > 0) and
    (WindowStyle > 0) and (IsAChild = Word(nil)) then
    ListBox2.Items.AddObject(Concat('<', StrPas(HoldString), '>'), TObject(HoldhWnd));

  FreeMem(HoldString, 256);
  HoldhWnd := nil;
  Result := TRUE;
end;

procedure TForm1.ListBox1DblClick(Sender: TObject);
begin

  enumChildWindows(THoldhWnd(ListBox1.Items.Objects[ListBox1.ItemIndex]).hWindow, @TForm1.enumListOfChildTasks, Longint(Self));

  ListBox2.RePaint;
end;

end.

Дополнение

В Kuliba1000.chm Win32 API/Разное/Пример EnumWindows есть принципиальная ошибка в коде:

ЛЮБАЯ callback ( обратного вызова ) функция в Delphi должна сопровождаться директивой stdcall.

Предоставленный пример просто не работает.

Определение класса формы должно выглядеть как-то так:

type
  TForm1 = class(TForm)
    ListBox1: TListBox;
    ListBox2: TListBox;
    procedure FormCreate(Sender: TObject);
    procedure ListBox1DblClick(Sender: TObject);
  private
    function enumListOfTasks(hWindow: hWnd): Bool; stdcall;
    function enumListOfChildTasks(hWindow: hWnd): Bool; stdcall;
  end;

Директивы export (это написано в Help'е) просто не работают (игнорируются) под Win 32 :(

С наилучшими пожеданиями
Андрей Бреслав

Взято из

Советов по Delphi от


Сборник Kuliba