I'm writing a MS Visual C++ program (I know I know - but I have to use
it) but would like to put some rutines in a DLL written using Delphi
2.0. I have tried but everything crashes when I call the DLL. Is there
some trick to doing this, or am I just not doing it right...
- kjaer
I am not sure what you are doing in your DLL, but this is what I now try to do
with D2 DLLs, if I want them to be calleable from other languages;
1. avoid using long strings
2. use STDCALL for functions
3. use pChars for string parameters
4. avoid functions that return long strings or short strings (use pChars
instead)
5. all functions return longints {this is not necessary, but I like it}
If you are only going to use your DLL with D2 programs, then none of the
above is necessary.
Regards,
The Chief,
--------
Dr. Abimbola A. Olowofoyeku (The African Chief)
Email: la...@keele.ac.uk
Author of: Chief's Installer Pro 2.91 for Win16 and Win32:
Winner of PC PLUS Magazine Gold Award (April 1995 U.K. edition)
http://ourworld.compuserve.com/homepages/African_Chief/chief.htm
>Thomas Kjær Nielsen (kj...@digianswer.com) wrote:
>: Hi there,
>:
>: I'm writing a MS Visual C++ program (I know I know - but I have to use
>: it) but would like to put some rutines in a DLL written using Delphi
>: 2.0. I have tried but everything crashes when I call the DLL. Is there
>: some trick to doing this, or am I just not doing it right...
>
>I am not sure what you are doing in your DLL, but this is what I now try to do
>with D2 DLLs, if I want them to be calleable from other languages;
>
>1. avoid using long strings
>2. use STDCALL for functions
>3. use pChars for string parameters
>4. avoid functions that return long strings or short strings (use pChars
>instead)
>5. all functions return longints {this is not necessary, but I like it}
>
>If you are only going to use your DLL with D2 programs, then none of the
>above is necessary.
I'm in the same position as the original poster : I have a D2 DLL I
wish to call from VC++ 4.2.
I'm doing all of the above that's relevant to me, but what I'd like to
know is if there's a relatively simple way to generate a VC++ .lib
file from a D2 DLL. I can live with LoadLibrary, but I don't want to.
It seems completely insane to me that Microsoft doesn't have their
own version of Implib..
- Stew
Make sure you define the DLL's function with PASCAL calling convention
in your C++ header files (using the WINAPI macro for example). Also
surround the definition with the proper C directive to prevent your
compiler from expecting name mangling. By the way, I don't think you
can use object interfaces between Delphi and C++ so your DLL functions
should all be "non objects".
Hope This Helps,
Alain Toutant
a.to...@sympatico.ca
Unfortunately, it is _impossible_ to create an implib that will be
accepted by VC++ 4.x. Microsoft, in their incredible wisdom, changed
the object format, and now actually decorate all function names
(even the ones that are 'extern C') with the total size of the
parameters.... Sigh.
According to what I've heard, it is still possible to create an
import library for a Delphi 2 DLL (or any other compiler-vendor's
DLLs) by using VC++ itself. If you create a dummy DLL project, with
all the right functions, in the right order, with the right
parameters, VC++ will create a lib file which, if you did everything
correctly, works! This, of course means, you actually needs two
versions of your DLL, one made in Delphi that actually does something,
and one made in VC++ that's just a bunch of empty functions.
M.
--
Martin Larsson, author of several unknown utilities for DOS and Windows.
mailto:martin....@delfi-data.msmail.telemax.no
http://www.delfidata.no/users/~martin
X.400:G=martin;S=larsson;O=delfi-data;P=msmail;A=telemax;C=no
>Stewart Loving-Gibbard wrote:
>>
>> I'm in the same position as the original poster : I have a D2 DLL I
>> wish to call from VC++ 4.2.
>>
>> I'm doing all of the above that's relevant to me, but what I'd like to
>> know is if there's a relatively simple way to generate a VC++ .lib
>> file from a D2 DLL. I can live with LoadLibrary, but I don't want to.
>> It seems completely insane to me that Microsoft doesn't have their
>> own version of Implib..
>
>Unfortunately, it is _impossible_ to create an implib that will be
>accepted by VC++ 4.x. Microsoft, in their incredible wisdom, changed
>the object format, and now actually decorate all function names
>(even the ones that are 'extern C') with the total size of the
>parameters.... Sigh.
>
[snip]
You can do this. It's a bit tedious, but not difficult.
First, you need to declare all the functions exported by your Delphi
DLL with the keywords export; stdcall;
Secondly, your VC++ header file should declare all the functions
as of type __declspec(dllexport) __stdcall (double leading
underscores, and should enclose the function prototypes
within extern "C" { ... } . ( You can probably use
__declspec(dllimport) instead...) For example:
extern "C" {
int __declspec(dllexport) __stdcall MyFirstDLLProc();
}
Thirdly, in VC++ the compiler insists on prepending a leading
underscore to all __stcall functions, so your Delphi DLL has
to export these functions with a leading underscore in their names.
I thought I had seen the last of this particular foolishness with
the old DOS C compilers, but...
FINALLY, you can easily create an import library using the LIB
utility supplied with VC++. To do it, you need to manually (!!)
create a .DEF file for your DLL, with an exports clause
listing the names and/or ordinals of all the functions the DLL
exports. The format of the .DEF file is simple:
library MYLIB
description 'My very own DLL'
exports
_MyFirstDLLProc,
_MySecondDLLProc,
etc., etc.
Then you execute LIB from the DOS/Win95 command
line, supplying your .DEF file as a command-line parameter.
(Run LIB /? for help on the syntax.) You tell VC++ about
your .LIB file in the Build|Settings dialog.
My reactions after all this: It really helps you appreciate Delphi!
Regards,
Bill Raike
>Stewart Loving-Gibbard wrote:
>>
>> I'm in the same position as the original poster : I have a D2 DLL I
>> wish to call from VC++ 4.2.
>>
>> I'm doing all of the above that's relevant to me, but what I'd like to
>> know is if there's a relatively simple way to generate a VC++ .lib
>> file from a D2 DLL. I can live with LoadLibrary, but I don't want to.
>> It seems completely insane to me that Microsoft doesn't have their
>> own version of Implib..
>
>Unfortunately, it is _impossible_ to create an implib that will be
>accepted by VC++ 4.x. Microsoft, in their incredible wisdom, changed
>the object format, and now actually decorate all function names
>(even the ones that are 'extern C') with the total size of the
>parameters.... Sigh.
>
[snip]
This is to correct a few errors in my earlier post on this topic.
The following method works: sample code appears at the end.
You can do this. It's a bit tedious, but not difficult.
First, you need to declare all the functions exported by your Delphi
DLL with the keywords export; stdcall;
Secondly, your VC++ header file should declare all the functions
as of type __declspec(dllexport) __stdcall (double leading
underscores, and should enclose the function prototypes
within extern "C" { ... } . ( You can also use
__declspec(dllimport) instead...) For example:
extern "C" {
int __declspec(dllexport) __stdcall plusone(int);
}
Thirdly, in VC++ the compiler does insist on decorating
__stcall function names, so your Delphi DLL has
to export these functions accordingly. The way to do it is
to modify the Delphi 2.0 .DPR file for your DLL by modifying
the names of all functions as they appear in the exports
clause. For example, if you are exporting a function
plusone(intval : Integer) you need to include it in the .DPR file's
exports clause as:
plusone name 'plusone@4'
The number following the @ symbol is the total length in bytes
of all the function's arguments. The simplest way to find out
the correct values is to try to link your VC++ program and inspect
the "unresolved external" linker errors that result.
FINALLY, you can easily create an import library using the LIB
utility supplied with VC++. To do it, you need to manually (!!)
create a .DEF file for your DLL, with an exports clause
listing the names and/or ordinals of all the functions the DLL
exports. The format of the .DEF file is simple:
library MYLIB
description 'My very own DLL'
exports
plusone@4
Then you execute LIB from the DOS/Win95 command
line, supplying your .DEF file as a command-line parameter.
For example, LIB /DEF:MYDLL.DEF . You tell VC++ about
your .LIB file in the Build|Settings|Linker dialog.
My reactions after all this: It really helps you appreciate Delphi!
Regards,
Bill Raike
_________
Sample code follows:
*******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 = 'Hello' then
StrPCopy(AString, 'World');
end;
end.
***********MYDLL.DPR
library mydll;
{ Important note about DLL memory management: ShareMem must be the
first unit in your library's USES clause AND your project's (select
View-Project Source) USES clause if your DLL exports any procedures
or
functions that pass strings as parameters or function results. This
applies to all strings passed to and from your DLL--even those that
are nested in records and classes. ShareMem is the interface unit to
the DELPHIMM.DLL shared memory manager, which must be deployed along
with your DLL. To avoid using DELPHIMM.DLL, pass string information
using PChar or ShortString parameters. }
uses
SysUtils,
Classes,
MyDLLMU in 'MyDLLMU.pas';
exports
plusone name 'plusone@4',
ChangeString name 'ChangeString@4';
begin
end.
*************** MYDLL.DEF
; -----------------------------------------------------------------
; File name: MYDLL.DEF
; -----------------------------------------------------------------
LIBRARY MYDLL
DESCRIPTION 'Test Delphi DLL, static loading into VC++ app'
EXPORTS
plusone@4
************** DLLTSTADlg.H
// DLLTSTADlg.h : header file
//
#define USELIB
#ifdef USELIB
extern "C" {
int __declspec(dllimport) __stdcall plusone(int);
}
#endif //USELIB
/////////////////////////////////////////////////////////////////////////////
// CDLLTSTADlg dialog
class CDLLTSTADlg : public CDialog
{
// Construction
public:
CDLLTSTADlg(CWnd* pParent = NULL); // standard constructor
~CDLLTSTADlg();
// Dialog Data
//{{AFX_DATA(CDLLTSTADlg)
enum { IDD = IDD_DLLTSTA_DIALOG };
CString m_sVal;
CString m_sStr;
//}}AFX_DATA
// ClassWizard generated virtual function overrides
//{{AFX_VIRTUAL(CDLLTSTADlg)
protected:
virtual void DoDataExchange(CDataExchange* pDX); // DDX/DDV support
//}}AFX_VIRTUAL
// Implementation
protected:
#ifndef USELIB
HINSTANCE hMyDLL;
FARPROC lpfnplusone;
typedef int (*pIIFUNC)(int);
pIIFUNC plusone;
#endif //USELIB
HICON m_hIcon;
// Generated message map functions
//{{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 : implementation file
//
#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 dialog
CDLLTSTADlg::CDLLTSTADlg(CWnd* pParent /*=NULL*/)
: CDialog(CDLLTSTADlg::IDD, pParent)
{
//{{AFX_DATA_INIT(CDLLTSTADlg)
m_sVal = _T("1");
m_sStr = _T("Hello");
//}}AFX_DATA_INIT
// Note that LoadIcon does not require a subsequent DestroyIcon in
Win32
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 message handlers
BOOL CDLLTSTADlg::OnInitDialog()
{
CDialog::OnInitDialog();
// Set the icon for this dialog. The framework does this
automatically
// when the application's main window is not a dialog
SetIcon(m_hIcon, TRUE); // Set big icon
SetIcon(m_hIcon, FALSE); // Set small icon
// TODO: Add extra initialization here
return TRUE; // return TRUE unless you set the focus to a control
}
// If you add a minimize button to your dialog, you will need the code
below
// to draw the icon. For MFC applications using the document/view
model,
// this is automatically done for you by the framework.
void CDLLTSTADlg::OnPaint()
{
if (IsIconic())
{
CPaintDC dc(this); // device context for painting
SendMessage(WM_ICONERASEBKGND, (WPARAM) dc.GetSafeHdc(), 0);
// Center icon in client rectangle
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;
// Draw the icon
dc.DrawIcon(x, y, m_hIcon);
}
else
{
CDialog::OnPaint();
}
}
// The system calls this to obtain the cursor to display while the
user drags
// the minimized window.
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);
}
****************** End of message