Рассылка закрыта
При закрытии подписчики были переданы в рассылку "Сетевой адаптер: осваиваем Интернет" на которую и рекомендуем вам подписаться.
Вы можете найти рассылки сходной тематики в Каталоге рассылок.
Все, что вы не знали, но хотели бы узнать о Delphi №12
Выпуск №12 Раздел: Язык Программирования Delphi Подраздел: Этот подраздел может показаться немного скучным, но не все же программированию быть интересным и занимательным? Уважаемый подписчик, О чем будет следующий раздел - решать вам. Варианты: VCL Системные функции и Winapi Базы данных Работа с файловой системой Репортинг, работа с принтером Работа с сетью, Интернетом, протоколами Работа с графикой, мультимедиа
Ваши предложения высылайте на В этом выпуске:
Использование ассемблера в Дельфи (статья)
// array of const function sprintf(out, fmt: Pchar; args: array of const): Integer; var I: Integer; BufPtr: Pchar; S: string; buf: array[0..1024] of 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 функции с ключевыми словами 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; export; stdcall; procedure ChangeString(AString : PChar); export; stdcall; 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.
Я создал следующие две функции, существенно повышающие произвотельность в приложениях, активно работающих с данными. Вам нужно всего-лишь обеспечить контроль типов и границ допустимого диапазона, все остальное они сделают с любым типом данных лучше нас :-) . 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 @5: XOR 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;
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
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 Variant) As Integer VB form code: Dim A As Variant Private Sub Command1_Click() A = Array(4, 3) MsgBox (TestMin(A)) End Sub Delphi DLL code: library NoelSArray; . . function TestMin(const Nums: Variant): integer; export; stdcall; var p1: Variant; begin p1 := VarArrayCreate([0, 1], VT_I4); p1:= Nums; if (p1[0] < p1[1]) then result:= p1[0] else Result:= p1[1]; end;
begin keybd_event(Key, 0, 0, 0); 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) $FF) and (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;
Application.ProcessMessages
Сайт рассылки Здесь Так же можете посетить несколько сайтов для заработка в Интернете: |
В избранное | ||