Во-первых, Вам необходимо объявить все экспортируемые в 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-файла очень прост:
Затем запускаете LIB из командной строки DOS/Win95, и в качестве параметра
подставляете имя .DEF-файла. Например, LIB /DEF:MYDLL.DEF. Наконец, через диалог
Build|Settings|Linker Вы информируете VC++ о полученном .LIB-файле.
Вот пример кода:
*******MYDLLMU.PAS
unit MyDLLMU;
interfacefunction plusone(val : Integer) : Integer; export; stdcall;
procedure ChangeString(AString : PChar); export; stdcall;
implementationuses
Dialogs,
SysUtils;
function plusone(val : Integer) : Integer;
begin
Result := val + 1;
end;
procedure ChangeString(AString : PChar);
beginif 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';
beginend.
*************** MYDLL.DEF ;
----------------------------------------------------------------- ; Имя
файла: MYDLL.DEF ;
-----------------------------------------------------------------
// 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);
}
Привет! Это руководство по вызову DLL Delphi из MS Visual C++. Шаги для выполнения:
В файле Delphi DLL объявите все экспортируемые функции с помощью ключевых слов export; stdcall.
В проекте VC++ включите файл заголовка Delphi DLL и используйте ключевое слово __declspec(dllimport) для импорта функций.
В файле .DPR Delphi DLL измените секцию экспорта, чтобы включить правильные имена экспортируемых функций с помощью директивы name.
Создайте файл DEF для DLL и укажите экспортируемые функции с помощью директивы exports.
Скомпилируйте проект VC++ с файлом DEF как дополнительной зависимостью.
Вот предоставленная кодовая база:
DLL Delphi
MyDLLMU.pas: объявляет две функции, plusone и ChangeString, с помощью ключевых слов export; stdcall.
MYDLL.DPR: экспортирует две функции с помощью директивы name.
Проект VC++
DLLTSTADlg.h: включает файл заголовка Delphi DLL и использует ключевое слово __declspec(dllimport) для импорта функций.
DLLTSTADlg.cpp: загружает DLL Delphi на этапе выполнения, получает адреса экспортируемых функций с помощью GetProcAddress, а затем вызывает их с помощью указателя на функцию.
Продолжение кода - это хороший пример вызова DLL Delphi из MS Visual C++. Однако есть некоторые потенциальные проблемы с управлением памятью и обработкой строк, которые требуют внимания:
В проекте VC++ нужно инициализировать менеджер памяти Delphi (ShareMem) перед использованием любых строк или динамической памяти.
При передаче строк между DLL Delphi и проектом VC++ рекомендуется использовать PChar или ShortString, а не CString, чтобы избежать проблем с управлением памятью.
В целом, это код предоставляет хороший старт для вызова DLL Delphi из MS Visual C++, но требует внимания к управлению памятью и обработке строк.
В статье описывается вызов Delphi DLL из MS Visual C++ и различные способы решения проблем, связанных с экспортом функций из DLL и импортом их в VC++.
Комментарии и вопросы
Получайте свежие новости и обновления по Object Pascal, Delphi и Lazarus прямо в свой смартфон. Подпишитесь на наш Telegram-канал delphi_kansoftware и будьте в курсе последних тенденций в разработке под Linux, Windows, Android и iOS
Материалы статей собраны из открытых источников, владелец сайта не претендует на авторство. Там где авторство установить не удалось, материал подаётся без имени автора. В случае если Вы считаете, что Ваши права нарушены, пожалуйста, свяжитесь с владельцем сайта.