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

Previous  Top  Next

    
 

 

 

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

 

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

 

Code:

extern "C" {

int __declspec(dllexport)     __stdcall plusone(int); }

 

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

 

Code:

plusone name 'plusone@4'

 

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

 

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

 

Code:

library MYLIB

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

exports

 

plusone@4

 

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

 

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

 

Code:

*******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

 

Code:

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

 

Code:

; -----------------------------------------------------------------

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

; -----------------------------------------------------------------

 

LIBRARY  MYDLL

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

EXPORTS

plusone@4

 

DLLTSTADlg.H

 

Code:

// 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

 

Code:

// 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:

 

Code:

{ Начало кода 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-приложени прототип функций, как показано ниже:

 

Code:

   int FAR PASCAL Min(int x, y);

   int FAR PASCAL Min(int x, y);

 

Теперь из любого места вашего приложения вы можете вызвать функции Min и Max.

©Drkb::00293

       

Взято с http://delphiworld.narod.ru