 |
BorlandTalk.com Borland discussion newsgroups
|
| View previous topic :: View next topic |
| Author |
Message |
Jim Sawyer Guest
|
Posted: Thu Jul 08, 2004 8:59 pm Post subject: Using C++ DLL in Delphi Application |
|
|
I have generated the following tiny program: (the procedure ClosePort
is in the DLL and just closes a port, provided it is open):
unit Recv;
interface
uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs, RzButton;
type
TForm1 = class(TForm)
SendButton: TRzBitBtn;
CloseButton: TRzBitBtn;
procedure SendButtonClick(Sender: TObject);
procedure CloseButtonClick(Sender: TObject);
private
{ Private declarations }
public
{ Public declarations }
end;
procedure ClosePort; stdcall; external 'IDXVETLAB.DLL';
var
Form1: TForm1;
implementation
{$R *.dfm}
procedure TForm1.SendButtonClick(Sender: TObject);
begin
ClosePort;
end;
procedure TForm1.CloseButtonClick(Sender: TObject);
begin
Close;
end;
end.
when I try to run the program, I get the error
The procedure entry point ClosePort could not be located in
the dynamic link library IDXVETLAB.DLL.
I think it's finding the DLL because when it I change the reference
to a ficticious name, it tells me it can't find it. So I conclude that
I'm not giving it some instruction related to where in the DLL the
procedure ClosePort is located.
I'm new at this DLL use thing, so any help will be appreciated. I've
been fighting this for a couple of weeks now.
|
|
| Back to top |
|
 |
Jim Sawyer Guest
|
Posted: Fri Jul 09, 2004 2:40 am Post subject: Re: Using C++ DLL in Delphi Application |
|
|
Leon - I'm now working with the below bit of code:
unit Recv;
interface
uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs, RzButton;
type
TForm1 = class(TForm)
TestButton: TRzBitBtn;
CloseButton: TRzBitBtn;
procedure TestButtonClick(Sender: TObject);
procedure CloseButtonClick(Sender: TObject);
private
{ Private declarations }
public
{ Public declarations }
end;
procedure ClosePort; stdcall; external 'IDXVETLAB.DLL' index 1;
function OpenPort( sPort: String ): Integer; stdcall; external
'IDXVETLAB.DLL' index 1;
var
Form1: TForm1;
implementation
{$R *.dfm}
procedure TForm1.TestButtonClick(Sender: TObject);
var
nPort: Integer;
begin
nPort := OpenPort( 'COM1' );
ClosePort;
ShowMessage( IntToStr( nPort ) );
end;
procedure TForm1.CloseButtonClick(Sender: TObject);
begin
Close;
end;
end.
Adding the "index 1" to the end of each declaration made
it work... sort of. Here is what happens. I breakpoint the
debugger on the
nPort := OpenPort( 'COM1' );
line. The unit runs and I depress the test button and the
debugger breaks. I then step past the next three lines and
both the function and the procedure execute. Then the
"ShowMessage" box displays 0 . I "enter" and the
execution stops on the
end;
line. I step one more time and the the error message
Receive.exe faulted with message: 'privileged
instruction at 0x0012fc3c.' Process stopped.
Use step or run to continue.
Questions:
1. What does the "INDEX 1" contribute? I added that
only because I saw it on an example while searching
good ol' Google.
2. What is the error code and why does it occur only
when the 'OnClick' code ends?
Also, the spec for the DLL that I have specifies some
properties such as
Destingation Property
syntax:
Object.Destination [ = Value ]
where Value is the ASCII value of the port number.
3. How do I use such properties as this?
Thanks,
Jim
"Leon Zandman" <NOSPAMusenet (AT) wirwar (DOT) com> wrote
| Quote: | I'm new at this DLL use thing, so any help will be appreciated. I've
been fighting this for a couple of weeks now.
Did you specify the parameters correctly? Maybe it should be a function
instead of a procedure. And maybe it returns some value? E.g:
function ClosePort(): boolean; stdcall; .....
Or maybe the calling convention isn't stdcall but cdecl of fastcall.
Greetz,
Leon
|
|
|
| Back to top |
|
 |
Jim Sawyer Guest
|
Posted: Sat Jul 10, 2004 3:27 pm Post subject: Re: Using C++ DLL in Delphi Application |
|
|
Leon -
I'm now trying to use the code
|
|
| Back to top |
|
 |
Jim Sawyer Guest
|
Posted: Sat Jul 10, 2004 3:41 pm Post subject: Re: Using C++ DLL in Delphi Application |
|
|
Leon -
I am now trying the code below:
unit Recv;
interface
uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs, RzButton;
type
TForm1 = class(TForm)
TestButton: TRzBitBtn;
CloseButton: TRzBitBtn;
procedure TestButtonClick(Sender: TObject);
procedure CloseButtonClick(Sender: TObject);
private
{ Private declarations }
public
{ Public declarations }
end;
TAddOpenPort = function( sPort: String ): Integer; stdcall;
function OpenPort( sPort: String ): Integer; stdcall; external
'IDXVETLAB.DLL';
var
Form1: TForm1;
implementation
{$R *.dfm}
procedure TForm1.TestButtonClick(Sender: TObject);
var
hLib: HMODULE;
fOpenPort: TAddOpenPort;
i: Integer;
begin
hLib := LoadLibrary('IDXVETLAB.DLL');
if ( hLib <> 0 ) then
begin
@fOpenPort := GetProcAddress( hLib, 'OpenPort' );
if ( @fOpenPort <> NIL ) then
i := fOpenPort( 'COM1' )
else
MessageDlg( 'Can'' find OpenPort function!', mtError, [mbOK], 0 );
FreeLibrary( hLib );
end
else
MessageDlg( 'Can''t load IDXVETLAB.DLL', mtError, [mbOK], 0 );
end;
procedure TForm1.CloseButtonClick(Sender: TObject);
begin
Close;
end;
end.
Since, on execution, I get the message
Can't find OpenPort function!
I conclude that the 'IDXVETLAB.DLL' is successfully loading, but
that the OpenPort function can't be found. Do you see anything
wrong? I have the DLL user's spec and also am in daily phone
contact with the writer of the DLL, so I'm sure the OpenPort
function is in the DLL, that it has one string argument and
returns an integer value. The DLL writer is expert in C++ (DLL's
language, VB, etc., but not Delphi, so he's lost.
Can you see anything wrong?
Thanks for your patience...
Jim Sawyer
Texas
|
|
| Back to top |
|
 |
Jim Sawyer Guest
|
Posted: Sat Jul 10, 2004 4:57 pm Post subject: Re: Using C++ DLL in Delphi Application |
|
|
Leon -
Removing the @ gives the same result (Can't find OpenPort function!).
For whatever it's worth, when I monitor the value of fOpenPort during
execution, the debugger gives the message 'Not enough parameters'. The
value @fOpenPort is NIL.
I've also tried replacing "stdcall" with
register
pascal
cdecl
safecall
The result stays the same in all cases.
????
Jim Sawyer
"Leon Zandman" <NOSPAMusenet (AT) wirwar (DOT) com> wrote
| Quote: | @fOpenPort := GetProcAddress( hLib, 'OpenPort' );
Since, on execution, I get the message
Can't find OpenPort function!
Mmmm... Do you need the "@"? I don't think so. You can do:
fOpenPort := GetProcAddress(hLib,'OpenPort');
Maybe that causes the error?
Greetz,
Leon
|
|
|
| Back to top |
|
 |
Jim Sawyer Guest
|
Posted: Sat Jul 10, 2004 6:28 pm Post subject: Re: Using C++ DLL in Delphi Application |
|
|
Leon -
To avoid the difficulty of passing a string to C++, I changed the code to
use a procedure in the Dll, as follows:
unit Recv;
interface
uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs, RzButton;
type
TForm1 = class(TForm)
TestButton: TRzBitBtn;
CloseButton: TRzBitBtn;
procedure TestButtonClick(Sender: TObject);
procedure CloseButtonClick(Sender: TObject);
private
{ Private declarations }
public
{ Public declarations }
end;
TAddClosePortFunction = procedure; stdcall;
procedure ClosePort; stdcall; external 'IDXVETLAB.DLL';
var
Form1: TForm1;
implementation
{$R *.dfm}
procedure TForm1.TestButtonClick(Sender: TObject);
var
hLib: HMODULE;
fClosePort: TAddClosePortFunction;
begin
hLib := LoadLibrary('IDXVETLAB.DLL');
if ( hLib <> 0 ) then
begin
@fClosePort := GetProcAddress( hLib, 'ClosePort' );
if ( @fClosePort <> NIL ) then
fClosePort
else
MessageDlg( 'Can'' find ClosePort procedure!', mtError, [mbOK], 0 );
FreeLibrary( hLib );
end
else
MessageDlg( 'Can''t load IDXVETLAB.DLL', mtError, [mbOK], 0 );
end;
procedure TForm1.CloseButtonClick(Sender: TObject);
begin
Close;
end;
end.
I still get the
Can't find ClosePort procedure!
error with both the above code and after changing the
@fClosePort := GetProcAddress( hLib, 'ClosePort' )
to
fClosePort := GetProcAddress( hLib, 'ClosePort' );
Thanks for all your help!
Jim Sawyer
"Leon Zandman" <NOSPAMusenet (AT) wirwar (DOT) com> wrote
| Quote: | TAddOpenPort = function( sPort: String ): Integer; stdcall;
that it has one string argument and
I forgot: you also have to be careful about using a string here.
Delphi's string type (AnsiString) is totally different and incompatible
with C++ strings (STL's std::string or Microsoft's CString). You can't
use them in Delphi. When you need to pass strings from a Delphi app to a
C++ DLL you want to use char pointers. Delphi has a function called
PChar() for this. You have to tell the DLL writer not to use a string
type but an array of chars (char *).
Leon
|
|
|
| Back to top |
|
 |
Jim Sawyer Guest
|
Posted: Sat Jul 10, 2004 7:11 pm Post subject: Re: Using C++ DLL in Delphi Application |
|
|
To make sure I'm not missing something, here is the way the DLL spec defines the ClosePort procedure and a PortInquiry function. Am I missing something?
ClosePort Subroutine
Closes the currently opened port. If no port has been opened, the command is ignored.
.. Syntax
Object.ClosePort
PortInquiry Function
Sends a port inquiry to the destination device and returns an integer representing a member of
the enumeration SND_STATUS. Only a VetTest or a VetStation should send a PortInquiry
message.
.. Syntax
Object.PortInquiry
|
|
| Back to top |
|
 |
Jim Sawyer Guest
|
Posted: Sat Jul 10, 2004 7:14 pm Post subject: Re: Using C++ DLL in Delphi Application |
|
|
To make sure I'm not missing something, here is the way the DLL spec
defines the ClosePort procedure and a PortInquiry function. Am I missing
something?
Jim Sawyer
ClosePort Subroutine
Closes the currently opened port. If no port has been opened, the command is
ignored.
.. Syntax
Object.ClosePort
PortInquiry Function
Sends a port inquiry to the destination device and returns an integer
representing a member of
the enumeration SND_STATUS. Only a VetTest or a VetStation should send a
PortInquiry
message.
.. Syntax
Object.PortInquiry
|
|
| Back to top |
|
 |
Jim Sawyer Guest
|
Posted: Sun Jul 11, 2004 4:21 pm Post subject: Re: Using C++ DLL in Delphi Application |
|
|
Leon -
I read your last post, and immediately ran TDump on the DLL. This is what
it yielded:
Export ord:0001 = 'DLLConUnloadNow'
Export ord:0002 = 'DLLGetClassObject'
Export ord:0003 = 'DLLRegisterServer'
Export ord:0004 = 'DLLUnregisterServer'
That is all. There is no mention of any of the routines or properties, such
as the
procedure "ClosePort" that are contained in the DLL spec. And the spec does
not
mention any of the above four routines.
It seems that this DLL is not merely a collection of routines for me to use.
Instead,
it seems to me to be a "little engine" to interface with the com port and
the data from
the the lab equipment which comes through that com port, and to present it
for my
use in a "cleaned up" form. Am I thinking correctly? If so, I have no idea
how to
implement this thing. Do I understand from your last post that Delphi can't
use
such a DLL if it is written in C++? Am I up the proverbial creek?
Thanks
Jim
|
|
| Back to top |
|
 |
Jim Sawyer Guest
|
Posted: Mon Jul 12, 2004 12:54 am Post subject: Re: Using C++ DLL in Delphi Application |
|
|
Leon! My new best friend! We (meaning you) did it! It is working! I just
have to learn the DLL now. You have spent a lot of time helping, and you
have given very clear explanations and instruction throughout. I owe you
one, friend.
Jim Sawyer
"Leon Zandman" <NOSPAMusenet (AT) wirwar (DOT) com> wrote
| Quote: | Jim,
I read your last post, and immediately ran TDump on the DLL. This is
what
it yielded:
Export ord:0001 = 'DLLConUnloadNow'
Export ord:0002 = 'DLLGetClassObject'
Export ord:0003 = 'DLLRegisterServer'
Export ord:0004 = 'DLLUnregisterServer'
Ah, that explains everything The DLL you're trying to use isn't a
regular DLL. Instead it's a COM library (ActiveX). This is a special
kind of library that is usable from a lot of different programming
environments. The four functions that TDump showed are used by software
e.g. for registering that object onto your system. Once the library is
registered you can use it from a lot of different environments (Delphi,
C++, VBScript, Visual Basic).
First you have to register the library on your system. You can do this
by going to a command prompt and enter the following command:
regsvr32.exe IDXVETLAB.DLL
A messagebox should appear saying that the registration succeeded. By
the way, you can unregister it using the following command:
regsvr32.exe /U IDXVETLAB.DLL
The next step is to convert the type library that should be included in
the DLL to a Delphi stub. Just start Delphi, start a new project and
select "Import Type Library" from the project menu. A dialog will show
up containing a list of all registered ActiveX libraries on your system.
Locate the one that belongs the the DLL (the name should be in your
documents) and select it. You can then click install (make sure
"generate component wrapper" is checked) and a new component will be
installed on your component palette. You can use this component to
access the OpenPort and ClosePort methods.
Do I understand from your last post that Delphi can't
use such a DLL if it is written in C++? Am I up the proverbial creek?
Well, there are problems when the DLL expects native C++ data types as
parameter type. But since this DLL obviously is an ActiveX DLL, those
problems shouldn't occur. An ActiveX DLL has to follow some rules in
order to be usable by a lot of different programming environments. And
one of those rules is, that it's interface must use COM data types.
Delphi supports those types, you I'm sure you can use the DLL.
By the way: you don't need the component wrapper that I've explained
above. You can also uncheck the checkbox and select "Create Unit"
instead of "Install". Then you can use this unit in your project to
create instances of the ActiveX object without using it as a component.
But it would be too much to explain all of that here...
Greetings and I hope you can get it working now,
Leon Zandman
|
|
|
| Back to top |
|
 |
|
|
You cannot post new topics in this forum You cannot reply to topics in this forum You cannot edit your posts in this forum You cannot delete your posts in this forum You cannot vote in polls in this forum
|
|