Отправляет email-рассылки с помощью сервиса Sendsay
  Все выпуски  

Все, что вы не знали, но хотели бы узнать о Delphi №12


Выпуск №12

Раздел: Язык Программирования Delphi

Подраздел:
Взаимодействие с другими языками (часть 1)

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

Уважаемый подписчик,

О чем будет следующий раздел - решать вам.

Варианты:

VCL

Системные функции и Winapi

Базы данных

Работа с файловой системой

Репортинг, работа с принтером

Работа с сетью, Интернетом, протоколами

Работа с графикой, мультимедиа

 

Ваши предложения высылайте на

formyreferal@rambler.ru

В этом выпуске:

Использование ассемблера в Дельфи (статья)
Вызов c-шной функции с переменным числом параметров
Вызов Delphi DLL из MS Visual C++
Аналог функции С memcmp
Соответствие типов С++ и Delphi
Using Visual Basic arrays in Delphi
Does Delphi have an equivalent to the Visual Basic SendKeys function?
Does Delphi have an equivalent for the VB function DoEvents?
Основное отличие EXE-файлов созданных Delphi и Visual Basic

 

Вызов c-шной функции с переменным числом параметров  




Комментарий к статье по поводу wsprintf

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



// Пишем функцию-переходник, маскируя с-шные "..." паскалевским
// array of const

function sprintf(out, fmt: Pchar; args: array of const): Integer;
var
  I: Integer;
  BufPtr: Pchar;
  S: string;
  buf: array[0..1024of char;
begin
  BufPtr := buf;
  // Формируем буффер параметров. Можно, конечно, и прямо на стеке,
  // но головной боли слишком много - проще так
  for I := low(Par) to High(Par) do
    case Par[I].VType of
      vtInteger: // Здесь все просто - 4 байта на стек
        begin
          Integer(Pointer(BufPtr)^) := Par[I].VInteger;
          Inc(BufPtr, 4);
        end;
      vtExtended: // Здесь хуже - слова надо местами поменять :-((
        begin
          Integer(Pointer(BufPtr)^) :=
            Integer(Pointer(Pchar(Par[I].VExtended) + 4)^);
          Inc(BufPtr, 4);
          Integer(Pointer(BufPtr)^) :=
            Integer(Pointer(Par[I].VExtended)^);
          Inc(BufPtr, 4);
        end;
      vtPChar: // Здесь тоже все хорошо - 4 байта
        begin
          Pointer(Pointer(BufPtr)^) := Par[I].VPchar;
          Inc(BufPtr, 4);
        end;
      vtString, vtAnsiString: // А здесь во избежание чудес надо
        // копию строки снять
        begin
          if Par[I].VType = vtString then
            S := Par[I].VString^
          else
            S := string(Par[I].VAnsiString);
          Pointer(Pointer(BufPtr)^ :=
            StrPCopy(StrAlloc(Length(S) + 1), S);
            Inc(BufPtr, 4);
        end;
    end;
  // Поддержку других типов доделывать самостоятельно,
  // вооружившись толковым пособием по с и ассемблеру

  I := (BufPtr - buf) div 4// Сколько раз на стек слово положить

  asm
      push dword ptr [out]
      push dword ptr [fmt]
      mov ecx, dword ptr [i]
      mov eax, dword ptr [buf]  // stdcall - параметры в прямом
                                // порядке
      @@1:
      push dword ptr [eax]
      add  eax, 4
      loop @@1
      call [wsprintf]
      mov  dword ptr [Result], eax // Сохранить результат
      mov eax, dword ptr [i]       // Привести в порядок стек
      shl eax, 2
      add eax, 8
      add esp, eax
  end;
  // Почистить строки
  for I := low(Par) to High(Par) do
    case Par[I].VType of
      vtInteger: Inc(BufPtr, 4);
      vtExtended: Inc(BufPtr, 8);
      vtPChar: Inc(BufPtr, 4);
      vtString, vtAnsiString:
        begin
          StrDispose(PChar(PPointer(BufPtr)^));
          Inc(BufPtr, 4);
        end;
    end;
end;




В таком виде методика уже имеет смысл. Изменения при типах вызова cdecl / pascal понятны.
 

Вызов Delphi DLL из MS Visual C++  


Во-первых, Вам необходимо объявить все экспортируемые в Delphi DLL функции с ключевыми словами export; stdcall;

Во-вторых, файл заголовка VC++ должен объявить все функции как тип __declspec(dllexport) __stdcall (применяйте двойное подчеркивание в секции объявления прототипа функции extern "C" { ... }. (вместо этого можно также использовать __declspec(dllimport)...). Для примера:

extern
 "C" {
int  __declspec(dllexport)     __stdcall plusone(int); } 

В-третьих, в VC++ компилятор настраивается на "украшающее" имена функций __stcall, так что Ваша Delphi DLL соответственно должна экспортировать эти функции. Для этого необходимо модифицировать файл Delphi 2.0 .DPR для Вашего DLL, модифицируя имена всех функций, прописанных в разделе экспорта. Для примера, если Вы экспортируете функцию function plusone (intval : Integer), Вам необходимо включить следующую строку в раздел экспорта .DPR-файла:

plusone name 'plusone@4' 

Число, следующее за символом @, является общей длиной в байтах всех функциональных аргументов. Самый простой путь для обнаружения неправильных значений - попытаться слинковать Вашу VC++ программу и посмотреть на наличие возможной ошибки компоновщика "unresolved external".

И, наконец, Вы можете легко создать библиотеку импорта, используя утилиту LIB из поставки VC++. Для этого необходимо вручную (!!) создать .DEF-файл для Вашей DLL с секцией экспорта, перечисляющей имена и/или порядковые номера всех экспортируемых DLL функций. Формат .DEF-файла очень прост:



library MYLIB
description 'Моя собственная DLL'
exports

plusone@4

 



Затем запускаете LIB из командной строки DOS/Win95, и в качестве параметра подставляете имя .DEF-файла. Например, LIB /DEF:MYDLL.DEF. Наконец, через диалог Build|Settings|Linker Вы информируете VC++ о полученном .LIB-файле.

Вот пример кода:

*******MYDLLMU.PAS 



unit MyDLLMU;

interface

function plusone(val : Integer) : Integer; exportstdcall;
procedure ChangeString(AString : PChar); exportstdcall;

implementation

uses

Dialogs,
SysUtils;

function plusone(val : Integer) : Integer;
begin

Result := val + 1;
end;

procedure ChangeString(AString : PChar);
begin

if AString = 'Здравствуй' then
StrPCopy(AString, 'Мир');
end;

end.




***********MYDLL.DPR



library mydll;

{ Существенное замечание об управлении памятью в DLL: Если DLL экспортирует функции со

строковыми параметрами или возвращающие строковые значения, модуль ShareMem надо
указывать в разделе Uses библиотеки и проекта первым. Это касается любых строк,
передаваемых как в DLL, так и из нее, даже если они размещаются внутри записей или
объектов. Модуль ShareMem служит интерфейсом менеджера разделяемой памяти
DELPHIMM.DLL, который должен разворачиваться одновременно с данной DLL. Чтобы избежать
применения DELPHIMM.DLL, строковую информацию можно передавать с помощью параметров
типа PChar или ShortString. }


uses

SysUtils,
Classes,
MyDLLMU in 'MyDLLMU.pas';

exports

plusone name 'plusone@4',
ChangeString name 'ChangeString@4';

begin
end.

 


*************** MYDLL.DEF
; -----------------------------------------------------------------
; Имя файла: MYDLL.DEF
; -----------------------------------------------------------------




LIBRARY  MYDLL

DESCRIPTION  'Тестовая Delphi DLL, статическая загрузка в VC++ приложение'

EXPORTS

plusone@4

 


************** DLLTSTADlg.H 



// DLLTSTADlg.h : заголовочный файл
//
#define USELIB
#ifdef USELIB
extern "C" {

int __declspec(dllimport) __stdcall plusone(int);
}
#endif //USELIB
/////////////////////////////////////////////////////////////////////////////
// Диалог CDLLTSTADlg

class CDLLTSTADlg : public CDialog
{
// Создание public:

CDLLTSTADlg(CWnd* pParent = NULL);      // стандартный конструктор
~CDLLTSTADlg();

// Данные диалога

//{{AFX_DATA(CDLLTSTADlg)
enum { IDD = IDD_DLLTSTA_DIALOG };
CString m_sVal;
CString m_sStr;
//}}AFX_DATA


// Перекрытая виртуальная функция, сгенерированная ClassWizard
//{{AFX_VIRTUAL(CDLLTSTADlg)
protected:
virtual void DoDataExchange(CDataExchange* pDX);        // Поддержка DDX/DDV
//}}AFX_VIRTUAL

// Реализация
protected:

#ifndef USELIB

HINSTANCE hMyDLL;
FARPROC lpfnplusone;
typedef int (*pIIFUNC)(int);
pIIFUNC plusone;
#endif //USELIB


HICON m_hIcon;


// Карта функций генераций сообщений
//{{AFX_MSG(CDLLTSTADlg)
virtual BOOL OnInitDialog();
afx_msg void OnPaint();
afx_msg HCURSOR OnQueryDragIcon();
afx_msg void OnBtnplusone();
afx_msg void OnBtnplusoneClick();
afx_msg void OnBtndostringClick();
//}}AFX_MSG
DECLARE_MESSAGE_MAP()
}; 

 


************ DLLTSTADlg.CPP 



// DLLTSTADlg.cpp : файл реализации
//

#include "stdafx.h"
#include "DLLTSTA.h"
#include "DLLTSTADlg.h"

#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif

extern CDLLTSTAApp theApp;

/////////////////////////////////////////////////////////////////////////////
// Диалог CDLLTSTADlg

CDLLTSTADlg::CDLLTSTADlg(CWnd* pParent /*=NULL*/)

: CDialog(CDLLTSTADlg::IDD, pParent)
{

//{{AFX_DATA_INIT(CDLLTSTADlg)
m_sVal = _T("1");
m_sStr = _T("Hello");
//}}AFX_DATA_INIT
// Имейте в виду, что в Win32 LoadIcon не требует последующего DestroyIcon
m_hIcon = AfxGetApp()->LoadIcon(IDR_MAINFRAME);

#ifndef USELIB

hMyDLL = LoadLibrary("C:\\delpwork\\MYDLL.DLL");
if(hMyDLL == NULL)
PostQuitMessage(1);
lpfnplusone = GetProcAddress(HMODULE(hMyDLL), "_plusone");
if(lpfnplusone == NULL)
PostQuitMessage(2);
plusone = pIIFUNC(lpfnplusone);
#endif //USELIB

}

CDLLTSTADlg::~CDLLTSTADlg()
{
#ifndef USELIB

if (hMyDLL != NULL)
FreeLibrary(hMyDLL);
#endif //USELIB
}

void CDLLTSTADlg::DoDataExchange(CDataExchange* pDX)
{

CDialog::DoDataExchange(pDX);
//{{AFX_DATA_MAP(CDLLTSTADlg)
DDX_Text(pDX, IDC_LBLINT, m_sVal);
DDX_Text(pDX, IDC_LBLSTRING, m_sStr);
//}}AFX_DATA_MAP
}

BEGIN_MESSAGE_MAP(CDLLTSTADlg, CDialog)

//{{AFX_MSG_MAP(CDLLTSTADlg)
ON_WM_PAINT()
ON_WM_QUERYDRAGICON()
ON_BN_CLICKED(IDC_BTNPLUSONE, OnBtnplusoneClick)
ON_BN_CLICKED(IDC_BTNDOSTRING, OnBtndostringClick)
//}}AFX_MSG_MAP
END_MESSAGE_MAP()

/////////////////////////////////////////////////////////////////////////////
// Дескрипторы сообщений CDLLTSTADlg

BOOL CDLLTSTADlg::OnInitDialog()
{

CDialog::OnInitDialog();


// Устанавливаем иконку для данного диалога.  В случае, когда главное
// окно программы не является диалогом, это происходит автоматически
SetIcon(m_hIcon, TRUE);                 // Устанавливаем большую иконку
SetIcon(m_hIcon, FALSE);                // Устанавливаем маленькую иконку


// TODO: Здесь добавляем дополнительную инициализацию


return TRUE;  // возвращает TRUE в случае отсутствия фокуса у диалога
}

// Если Вы добавляете в диалог кнопку минимизации, для создания иконки Вам
//  необходим код, приведенный ниже. Для MFC-приложений используйте
//  document/view model для автоматического создания скелета кода.

void CDLLTSTADlg::OnPaint()
{

if (IsIconic())
{
CPaintDC dc(this); // контекст устройства для рисования


SendMessage(WM_ICONERASEBKGND, (WPARAM) dc.GetSafeHdc(), 0);


// Центр иконки в области клиента
int cxIcon = GetSystemMetrics(SM_CXICON);
int cyIcon = GetSystemMetrics(SM_CYICON);
CRect rect;
GetClientRect(&rect);
int x = (rect.Width() - cxIcon + 1) / 2;
int y = (rect.Height() - cyIcon + 1) / 2;


// Рисование иконки
dc.DrawIcon(x, y, m_hIcon);
}
else
{
CDialog::OnPaint();
}
}

// Система вызывает данный код для получения курсора, выводимого если
//  пользователь пытается перетащить свернутое окно.
HCURSOR CDLLTSTADlg::OnQueryDragIcon()
{

return (HCURSOR) m_hIcon;
}

void CDLLTSTADlg::OnBtnplusoneClick() 
{

int iTemp;
char sTemp[10];



iTemp = atoi(m_sVal);
iTemp = plusone(iTemp);
m_sVal = itoa(iTemp, sTemp, 10);
UpdateData(FALSE);
}

void CDLLTSTADlg::OnBtndostringClick()
{

UpdateData(FALSE);



 


Во-первых, создайте в Delphi простую DLL:

{ Начало кода DLL }

library MinMax;

function Min(X, Y: Integer): Integer; export;
begin
  if X < Y then
    Min := X
  else
    Min := Y;
end;

function Max(X, Y: Integer): Integer; export;
begin
  if X > Y then
    Max := X
  else
    Max := Y;
end;

exports

  Min index 1,
  Max index 2;

begin
end.

{ Конец кода DLL }




Затем, для вызова этих функций из вашего C кода, сделайте следующее:

В вашем .DEF-файле добавьте следующие строки:

IMPORTS
Min =MINMAX.Min
Max =MINMAX.Max

Объявите в вашем C-приложени прототип функций, как показано ниже:

   int FAR PASCAL Min(int x, y);
    int FAR PASCAL Min(int x, y);
Теперь из любого места вашего приложения вы можете вызвать функции Min и Max.

 
Аналог функции С memcmp  


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

function
 Keys_are_Equal(var OldRec, NewRec;
KeyLn : word): boolean; assembler;
asm
  PUSH    DS
  MOV     AL,01
  CLD
  LES     DI,NewRec
  LDS     SI,OldRec
  MOV     CX,KeyLn
  CLI
  REPE    CMPSB
  STI
  JZ      @1
  XOR     AL,AL
  @1:
  POP     DS
end;

function First_Key_is_Less(var NewRec, OldRec; Keyln : word): boolean; assembler;
asm
  PUSH    DS
  MOV     AL,01
  CLD
  LES     DI,NewRec
  LDS     SI,OldRec
  MOV     CX,KeyLn
  CLI
  REPE    CMPSB
  STI
  JZ      @5
  JGE     @6
  @5XOR     AL,AL
  @6: POP     DS
end;

   
Примеры приведены для 16-битного Pascal'я и не могут использоваться в 32-битном Delphi! Зато можно делать так:
{ Возвращает -1 при X<Y, 0 при X=Y, 1 при X>Y. }
{ Сравнение идёт по DWord'ам, будто сравнивается массив чисел Integer или Cardinal, }
{ т.е. 01 02 03 04 05 06 07 08 > 01 02 03 04 05 06 08 07, }
{ т.к. 04030201 = 04030201, но 08070605 > 07080605 (hex). }
{ Однако, если Size and 3 <> 0, то последние Size mod 4 байт сравниваются побайтно! }

function memcmp(const X, Y; Size: DWord): Integer;
asm
  mov esi,X
  mov edi,Y
  mov ecx,Size
  mov dl,cl
  and dl,3
  shr ecx,2
  xor eax,eax
  rep cmpsd
  jb @@less
  ja @@great
  mov cl,dl
  rep cmpsb
  jz @@end
  ja @@great
 @@less:
  dec eax
  jmp @@end
 @@great:
  inc eax
 @@end:
end;
 
Соответствие типов С++ и Delphi  



C Data Type | Object Pascal |  Description 
----------------------------------------------
LPSTR       PAnsiChar;  String >pointer 
LPCSTR      PAnsiChar;  String >pointer 
DWORD       Integer;    Whole numbers 
BOOL        LongBool;   Boolean values 
PBOOL       ^BOOL;      Pointer to a Boolean value 
Pbyte       ^Byte;      Pointer to a byte value 
PINT        ^Integer;   Pointer to an integer value 
Psingle     ^Single;    Pointer to a single (floating point) value 
PWORD       ^Word;      Pointer to a 16-bit value 
PDWORD      ^DWORD;     Pointer to a 32-bit value 
LPDWORD     PDWORD;     Pointer to a 32-bit value 
UCHAR       Byte;       8-bit values (can represent characters) 
PUCHAR      ^Byte;      Pointer to 8-bit values 
SHORT       Smallint;   16-bit whole numbers 
UINT        Integer;    32-bit whole numbers. Traditionally, 
                        this was used to represent unsigned integers, 
                        but Object Pascal does not have a true 
                        unsigned integer data type. 
PUINT       ^UINT;      Pointer to 32-bit whole numbers 
ULONG       Longint;    32-bit whole numbers. Traditionally, 
                        this was used to represent unsigned integers, 
                        but Object Pascal does not have a true 
                        unsigned integer data type. 
PULONG      ^ULONG;     Pointer to 32-bit whole numbers 
PLongint    ^Longint;   Pointer to 32-bit values 
PInteger    ^Integer;   Pointer to 32-bit values 
PSmallInt   ^Smallint;  Pointer to 16-bit values 
PDouble     ^Double;    Pointer to double (floating point) values 
LCID        DWORD;      A local identifier 
LANGID      Word;       A language identifier 
THandle     Integer;    An object handle. Many Windows API functions return a value 
                        of type THandle, which identobject ifies that object within 
                        Windows'internal object tracking tables. 
PHandle     ^THandle;   A pointer to a handle 
WPARAM      Longint;    A 32-bit message parameter. Under earlier versions of Windows, 
                        this was a 16-bit data type. 
LPARAM      Longint;    A 32-bit message parameter 
LRESULT     Longint;    A 32-bit function return value 
HWND        Integer;    A handle to a window. All windowed controls, child windows, 
                        main windows, etc., have a corresponding window handle that 
                        identifies them within Windows'internal tracking tables. 
HHOOK       Integer;    A handle to an installed Windows system hook 
ATOM        Word;       An index into the local or global atom table for a string 
HGLOBAL     THandle;    A handle identifying a globally allocated dynamic memory object. 
                        Under 32-bit Windows, there is no distinction between globally 
                        and locally allocated memory. 
HLOCAL      THandle;    A handle identifying a locally allocated dynamic memory object. 
                        Under 32-bit Windows, there is no distinction between globally 
                        and locally allocated memory. 
FARPROC     Pointer;    A pointer to a procedure, usually used as a parameter type in 
                        functions that require a callback function 
HGDIOBJ     Integer;    A handle to a GDI object. Pens, device contexts, brushes, etc., 
                        all have a handle of this type that identifies them within 
                        Windows'internal tracking tables. 
HBITMAP     Integer;    A handle to a Windows bitmap object 
HBRUSH      Integer;    A handle to a Windows brush object 
HDC         Integer;    A handle to a device context 
HENHMETAFILE  Integer;  A handle to a Windows enhanced metafile object 
HFONT       Integer;    A handle to a Windows logical font object 
HICON       Integer;    A handle to a Windows icon object 
HMENU       Integer;    A handle to a Windows menu object 
HMETAFILE   Integer;    A handle to a Windows metafile object 
HINST       Integer;    A handle to an instance object 
HMODULE     HINST;      A handle to a module 
HPALETTE    Integer;    A handle to a Windows color palette 
HPEN        Integer;    A handle to a Windows pen object 
HRGN        Integer;    A handle to a Windows region object 
HRSRC       Integer;    A handle to a Windows resource object 
HKL         Integer;    A handle to a keyboard layout 
HFILE       Integer;    A handle to an open file 
HCURSOR     HICON;      A handle to a Windows mouse cursor object 
COLORREF    DWORD;      A Windows color reference value, containing values 
                        for the red, green, and of ;bsp;blue components of a color 
Using Visual Basic arrays in Delphi  

How do I pass arrays from VB to Delphi?

Arrays can be passed as variants:

VB module code:
Attribute VB_Name = "Module1"

Declare Function TestMin Lib "c:\windows\system\NoelSArr" 
   (Nums As VariantAs Integer

VB form code:
Dim A As Variant
Private Sub Command1_Click()
  A = Array(43)
  MsgBox (TestMin(A))
End Sub

Delphi DLL code:
library NoelSArray;
.
.
function TestMin(const Nums: Variant): integer; exportstdcall;
var
 p1: Variant;
begin
 p1 := VarArrayCreate([01], VT_I4);
 p1:= Nums;
  if (p1[0] < p1[1]) then
   result:= p1[0]
 else
   Result:= p1[1];
end;
 
Does Delphi have an equivalent to the Visual Basic SendKeys function?  


The following example demonstrates procedures that provide the
capibility of sending keystrokes to any window control capable of
receiving keyboard input. You may use this technique to toggle
the num lock, caps lock, and scroll lock keys under Windows NT.
This same technique works for toggling caps lock and scroll lock
keys under Windows 95, but it will not work for num lock.

Note that there are four procedures provided: SimulateKeyDown(),
SimulateKeyUp(), SimulateKeystroke(), and SendKeys(), to allow greater
control in your ability to send keystrokes.

The SimulateKeyDown(), SimulateKeyUp(), and SimulateKeystroke()
procedures expect a virtural key code (like VK_F1).
The SimulateKeystroke() procedure accepts an extra parameter that is
useful when simulating the PrintScreen key. When extra is set to zero,
the entire screen will be captured to the windows clipboard. When
extra is set to one, only the active window will be captured.

The four button click methods demonstrate the use of these functions:
ButtonClick1 - Toggles the cap lock.
ButtonClick2 - Captures the entire screen to the clipboard.
ButtonClick3 - Capture the active window to the clipboard.
ButtonClick4 - Set the focus to an edit control and sends it a string.

Example:

procedure SimulateKeyDown(Key : byte);
begin
  keybd_event(Key, 000);
end;

procedure SimulateKeyUp(Key : byte);
begin
  keybd_event(Key, 0, KEYEVENTF_KEYUP, 0);
end;

procedure SimulateKeystroke(Key : byte;
                            extra : DWORD);
begin
  keybd_event(Key,
              extra,
              0,
              0);
  keybd_event(Key,
              extra,
              KEYEVENTF_KEYUP,
              0);
end;

procedure SendKeys(s : string);
var
  i : integer;
  flag : bool;
  w : word;
begin
 {Get the state of the caps lock key}
  flag := not GetKeyState(VK_CAPITAL) and 1 = 0;
 {If the caps lock key is on then turn it off}
  if flag then
    SimulateKeystroke(VK_CAPITAL, 0);
  for i := 1 to Length(s) do begin
    w := VkKeyScan(s[i]);
   {If there is not an error in the key translation}
    if ((HiByte(w)  $FFand
        (LoByte(w)  $FF)) then begin
     {If the key requires the shift key down - hold it down}
      if HiByte(w) and 1 = 1 then
        SimulateKeyDown(VK_SHIFT);
     {Send the VK_KEY}
      SimulateKeystroke(LoByte(w), 0);
     {If the key required the shift key down - release it}
      if HiByte(w) and 1 = 1 then
        SimulateKeyUp(VK_SHIFT);
    end;
  end;
 {if the caps lock key was on at start, turn it back on}
  if flag then
    SimulateKeystroke(VK_CAPITAL, 0);
end;

procedure TForm1.Button1Click(Sender: TObject);
begin
 {Toggle the cap lock}
  SimulateKeystroke(VK_CAPITAL, 0);
end;

procedure TForm1.Button2Click(Sender: TObject);
begin
 {Capture the entire screen to the clipboard}
 {by simulating pressing the PrintScreen key}
  SimulateKeystroke(VK_SNAPSHOT, 0);
end;

procedure TForm1.Button3Click(Sender: TObject);
begin
 {Capture the active window to the clipboard}
 {by simulating pressing the PrintScreen key}
  SimulateKeystroke(VK_SNAPSHOT, 1);
end;

procedure TForm1.Button4Click(Sender: TObject);
begin
 {Set the focus to a window (edit control) and send it a string}
  Application.ProcessMessages;
  Edit1.SetFocus;
  SendKeys('Delphi Is RAD!');
end;

 

Does Delphi have an equivalent for the VB function DoEvents?  

Application.ProcessMessages
 
Основное отличие EXE-файлов созданных Delphi и Visual Basic  



Основное отличие EXE-файлов созданных Delphi и Visual Basic

Существует два важных различия между файлами EXE, созданными в Delphi, и файлами EXE, созданными VB. Delphi создает чисто машинный код, непосредственно исполняемый компьютером, в то время как VB транслирует исходный код в промежуточную форму (р-код). Файл EXE, сгенерированный VB, в действительности является программой-интерпретатором р-кода с добавленным в конце р-кодом программы пользователя.

"Библиотека времени выполнения" (run-time library) стандартных функций для всех программ VB хранится в файле VBRUN300.DLL. Каждая программа VB, попавшая к конечному пользователю, должна включать этот файл, либо приходится расчитывать, что такой файл у пользователя уже есть. Дистрибутивный комплект программы должен также содержать файлы VBX для каждого управляющего средства VB, не включенного в VBRUN300.DLL.

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

 

 

Сайт рассылки Здесь

Так же можете посетить несколько сайтов для заработка в Интернете:

Hit&Host

 

Raskrutim.ru

 

WmSearch

 


В избранное