dave5050
asked on
Delphi DLL with exports and objects
I am trying to use the NMHTTP component in a DLL and export a function which will manipulate the component. I am not trying to export the components methods, only a function I write which will use the component. I cannot seem to successfully get the component created without a form, and even then I still cannot get it to work. Can anyone provide some sample code for using a component in a DLL and exporting functions which will control that component? I already have created the DLL with no components in it and I can call and retrieve the return from my other language just fine...
ASKER CERTIFIED SOLUTION
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
dave5050, you need to add the required units to a Uses statement to get the sample to compile...
ASKER
BlackMan, I did that and that resolved the problem, though I cannot reference the component anywhere...am I missing something with the scope?
Sorry it's not NMHTTP but TNMHTTP.
------------------------
library Project1;
uses
SysUtils,
nmhttp,
Classes;
var
SaveExit: Pointer;
nm_http: TNMHTTP;
procedure LibExit;
begin
// library exit code
nm_http.Free;
ExitProc := SaveExit; // restore exit procedure chain
end;
begin
// library initialization code
SaveExit := ExitProc; // save exit procedure chain
ExitProc := @LibExit; // install LibExit exit procedure
nm_http := TNMHTTP.Create(nil);
end.
------------------------
library Project1;
uses
SysUtils,
nmhttp,
Classes;
var
SaveExit: Pointer;
nm_http: TNMHTTP;
procedure LibExit;
begin
// library exit code
nm_http.Free;
ExitProc := SaveExit; // restore exit procedure chain
end;
begin
// library initialization code
SaveExit := ExitProc; // save exit procedure chain
ExitProc := @LibExit; // install LibExit exit procedure
nm_http := TNMHTTP.Create(nil);
end.
ASKER
Epsylon: You got the 500, but as I mentioned, for another 300-500 can you also provide a means for responding to this components events within the DLL? What you listed works well for init'ing the component and such, I can now call some methods of the component but in my other unit I have to redeclare the component again. Anyway, can you provide some info on responding to events? I don't know if I can keep this question open but still give you the 500...
Here is a TNMHTTP.Get example which uses an OnConnect Event. You can try it with a clean form in a new/clean project. Then add a button, a checkbox, two memo's and a NMHTTP component to the form:
------------------------
procedure TForm1.Button1Click(Sender : TObject);
begin
NMHTTP1.OnConnect := NMHTTP1Connect; // Initialize the eventhandler
NMHTTP1.InputFileMode := FALSE;
NMHTTP1.OutputFileMode := FALSE;
NMHTTP1.ReportLevel := 2; //Status_Basic - Deplhi 4 does not know 'Status_Basic' anymore I guess, maybe Delphi 3 does...
If CheckBox1.Checked then
Begin
NMHTTP1.Proxy := 'wwwproxy.server.com'; // change this to your own needs
NMHTTP1.ProxyPort := 8080; // change this to your own needs
End;
With NMHTTP1.HeaderInfo do
Begin
Cookie := 'Hello world';
LocalMailAddress := 'clinton@whitehouse.com'; // not nescessary
LocalProgram := ''; // You can use this if you want
Referer := ''; // You can use this if you want
UserID := ''; // You can use this if you want
Password := ''; // You can use this if you want
End;
NMHTTP1.Get('www.inprise.com');
Memo1.Text := NMHTTP1.Body;
Memo2.Text := NMHTTP1.Header;
If NMHTTP1.CookieIn <> '' then
ShowMessage('Cookie:'+#13# 10+NMHTTP1 .CookieIn) ;
end;
procedure TForm1.NMHTTP1Connect(Send er: TObject);
begin
ShowMessage('YES I am connected!!!');
end;
------------------------
Then add
procedure NMHTTP1Connect(Sender: TObject);
in the TForm1 = class(TForm) definition in the upper part of the source.
You can of course assign an eventhandler using the object inspector of delphi. You don't have to initialize the eventhandler in the Button1Click function then.
------------------------
procedure TForm1.Button1Click(Sender
begin
NMHTTP1.OnConnect := NMHTTP1Connect; // Initialize the eventhandler
NMHTTP1.InputFileMode := FALSE;
NMHTTP1.OutputFileMode := FALSE;
NMHTTP1.ReportLevel := 2; //Status_Basic - Deplhi 4 does not know 'Status_Basic' anymore I guess, maybe Delphi 3 does...
If CheckBox1.Checked then
Begin
NMHTTP1.Proxy := 'wwwproxy.server.com'; // change this to your own needs
NMHTTP1.ProxyPort := 8080; // change this to your own needs
End;
With NMHTTP1.HeaderInfo do
Begin
Cookie := 'Hello world';
LocalMailAddress := 'clinton@whitehouse.com'; // not nescessary
LocalProgram := ''; // You can use this if you want
Referer := ''; // You can use this if you want
UserID := ''; // You can use this if you want
Password := ''; // You can use this if you want
End;
NMHTTP1.Get('www.inprise.com');
Memo1.Text := NMHTTP1.Body;
Memo2.Text := NMHTTP1.Header;
If NMHTTP1.CookieIn <> '' then
ShowMessage('Cookie:'+#13#
end;
procedure TForm1.NMHTTP1Connect(Send
begin
ShowMessage('YES I am connected!!!');
end;
------------------------
Then add
procedure NMHTTP1Connect(Sender: TObject);
in the TForm1 = class(TForm) definition in the upper part of the source.
You can of course assign an eventhandler using the object inspector of delphi. You don't have to initialize the eventhandler in the Button1Click function then.
ASKER
ARRRGH!!...;) Epsylon...I know how to do such using a form and application, what I am having problems with is doing it in a DLL.
Using your code in the init section of the DLL I get the component created just fine, in the uses clause I have also
"uses unit1 in unit1.pas" in which I have to redeclare "nm_http: TNMHTTP" to be able to use it in that unit.
I export a function in the DLL called PostData index 1; and in the unit1.pas I have a function prototyped as "function PostData(var Type: Integer): LongBool; cdecl; export;" then in the function itself I do a nm_http.get(url) and then return a bool.
What I was asking regarding events, is how do I respond to nm_http events in the DLL?
procedure nm_http.OnPacketRecvd(Send er: TObject) does not work or trap the events...
what am I missing?
Thank you very much for the help you have been....want some contract work?...;)
Using your code in the init section of the DLL I get the component created just fine, in the uses clause I have also
"uses unit1 in unit1.pas" in which I have to redeclare "nm_http: TNMHTTP" to be able to use it in that unit.
I export a function in the DLL called PostData index 1; and in the unit1.pas I have a function prototyped as "function PostData(var Type: Integer): LongBool; cdecl; export;" then in the function itself I do a nm_http.get(url) and then return a bool.
What I was asking regarding events, is how do I respond to nm_http events in the DLL?
procedure nm_http.OnPacketRecvd(Send
what am I missing?
Thank you very much for the help you have been....want some contract work?...;)
My previous comment was a response to your comment on Sunday, January 24 1999 - 06:15PM. You posted another comment on Monday, January 25 1999 - 03:08PM I had not seen at that time. So I just give a quick example that works.
I WILL help you further with but give my some time, then will work it all out. After all, we want the DLL to work!
On the OnPacketRecvd event: you have to assign a function to the OnPackedRecvd 'property' (OnPackedRecvd := SomeMethod). Events are method pointers. And since there is no form, there is no method. So it's a bit tricky.
It's late now (past midnight) so I will try to work it out tomorrow.
I WILL help you further with but give my some time, then will work it all out. After all, we want the DLL to work!
On the OnPacketRecvd event: you have to assign a function to the OnPackedRecvd 'property' (OnPackedRecvd := SomeMethod). Events are method pointers. And since there is no form, there is no method. So it's a bit tricky.
It's late now (past midnight) so I will try to work it out tomorrow.
Hi Dave5050 or should I call you Dave. It works!
I created two Delphi projects: one for the DLL and one for testing the DLL. I will post the source code in the next comments. Use it as an example for your own code.
The 'DLLTester' app uses Form1 with:
- Button1
- Label1 with caption:='DLL timer active' and Visible:=false
- Label2
- Label3
- Edit1 with text:='http://www.inprise.com'
- Memo1
Click the button to active. Label1 should start blinking, Label2 should show the number of bytes received, Label3 should show 'Connected...' and Memo should contain the body of the requested url.
If you want to have the OnPacketRecvd event to call a handler INSIDE the DLL then remove the SetPacketRecvdEventHandler call from the DLL test app and add this to the DLL code:
type
TDLLHandlerObject = class
procedure mhoPacketRecvd(Sender: TObject);
end;
.....
var
DLLHandler: TDLLHandlerObject;
.....
procedure TDLLHandlerObject.mhoPacke tRecvd(Sen der: TObject);
Begin
// your eventhandler code
end;
To assign the eventhandler put in the library initialization code after the creation of the nm_http object:
DLLHandler := TDLLHandlerObject.Create;
SetPacketRecvdEventHandler (DLLHandle r.mhoPacke tRecvd);
and in the library exit code:
DLLHandler.Free;
well, I hope I have not forgotten anything.... good luck with it!
Let me know if it works.....
I created two Delphi projects: one for the DLL and one for testing the DLL. I will post the source code in the next comments. Use it as an example for your own code.
The 'DLLTester' app uses Form1 with:
- Button1
- Label1 with caption:='DLL timer active' and Visible:=false
- Label2
- Label3
- Edit1 with text:='http://www.inprise.com'
- Memo1
Click the button to active. Label1 should start blinking, Label2 should show the number of bytes received, Label3 should show 'Connected...' and Memo should contain the body of the requested url.
If you want to have the OnPacketRecvd event to call a handler INSIDE the DLL then remove the SetPacketRecvdEventHandler
type
TDLLHandlerObject = class
procedure mhoPacketRecvd(Sender: TObject);
end;
.....
var
DLLHandler: TDLLHandlerObject;
.....
procedure TDLLHandlerObject.mhoPacke
Begin
// your eventhandler code
end;
To assign the eventhandler put in the library initialization code after the creation of the nm_http object:
DLLHandler := TDLLHandlerObject.Create;
SetPacketRecvdEventHandler
and in the library exit code:
DLLHandler.Free;
well, I hope I have not forgotten anything.... good luck with it!
Let me know if it works.....
Here is the DLL code
-------------------------- ---------- ---------- ---------
library DLLProject;
uses
SysUtils,
Classes,
dialogs,
extctrls,
Psock,
NMHTTP;
var
SaveExit: Pointer;
Timer: TTimer;
nm_http: TNMHTTP;
procedure SetTimerEventHandler(event handler: TNotifyEvent);
begin
Timer.OnTimer := eventhandler;
end;
procedure SetPacketRecvdEventHandler (eventhand ler: TNotifyEvent);
begin
nm_http.OnPacketRecvd := eventhandler;
end;
procedure SetConnectEventHandler(eve nthandler: TNotifyEvent);
begin
nm_http.OnConnect := eventhandler;
end;
function nmhttpBytesRecvd:Longint;
begin
Result := nm_http.BytesRecvd;
end;
function nmhttpGet(url: String):String;
begin
with nm_http do
begin
InputFileMode := False;
OutputFileMode := False;
ReportLevel := Status_Basic; // defined in Psock unit
// Proxy := '192.168.0.1';
// ProxyPort := 80;
Get(url);
Result := Body;
end;
end;
procedure LibExit;
begin
// library exit code
nm_http.Free;
Timer.Free;
ExitProc := SaveExit; // restore exit procedure chain
end;
exports
SetTimerEventHandler index 1 name 'SetTimerEventHandler',
SetPacketRecvdEventHandler index 2 name 'SetPacketRecvdEventHandle r',
SetConnectEventHandler index 3 name 'SetConnectEventHandler',
nmhttpGet index 4 name 'nmhttpGet',
nmhttpBytesRecvd index 5 name 'nmhttpBytesRecvd';
begin
// library initialization code
Timer := TTimer.Create(nil);
Timer.Interval := 300;
Timer.Enabled := true;
nm_http := TNMHTTP.Create(nil);
SaveExit := ExitProc; // save exit procedure chain
ExitProc := @LibExit; // install LibExit exit procedure
end.
--------------------------
library DLLProject;
uses
SysUtils,
Classes,
dialogs,
extctrls,
Psock,
NMHTTP;
var
SaveExit: Pointer;
Timer: TTimer;
nm_http: TNMHTTP;
procedure SetTimerEventHandler(event
begin
Timer.OnTimer := eventhandler;
end;
procedure SetPacketRecvdEventHandler
begin
nm_http.OnPacketRecvd := eventhandler;
end;
procedure SetConnectEventHandler(eve
begin
nm_http.OnConnect := eventhandler;
end;
function nmhttpBytesRecvd:Longint;
begin
Result := nm_http.BytesRecvd;
end;
function nmhttpGet(url: String):String;
begin
with nm_http do
begin
InputFileMode := False;
OutputFileMode := False;
ReportLevel := Status_Basic; // defined in Psock unit
// Proxy := '192.168.0.1';
// ProxyPort := 80;
Get(url);
Result := Body;
end;
end;
procedure LibExit;
begin
// library exit code
nm_http.Free;
Timer.Free;
ExitProc := SaveExit; // restore exit procedure chain
end;
exports
SetTimerEventHandler index 1 name 'SetTimerEventHandler',
SetPacketRecvdEventHandler
SetConnectEventHandler index 3 name 'SetConnectEventHandler',
nmhttpGet index 4 name 'nmhttpGet',
nmhttpBytesRecvd index 5 name 'nmhttpBytesRecvd';
begin
// library initialization code
Timer := TTimer.Create(nil);
Timer.Interval := 300;
Timer.Enabled := true;
nm_http := TNMHTTP.Create(nil);
SaveExit := ExitProc; // save exit procedure chain
ExitProc := @LibExit; // install LibExit exit procedure
end.
Here is the test app code
-------------------------- ---------- ---------- ---------- -
unit DLLTester;
interface
uses
Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs,
StdCtrls, ExtCtrls;
type
TForm1 = class(TForm)
Button1: TButton;
Label1: TLabel;
Label2: TLabel;
Memo1: TMemo;
Label3: TLabel;
Edit1: TEdit;
procedure Button1Click(Sender: TObject);
private
procedure TimerCallback(Sender: TObject);
procedure PacketRecvdCallback(Sender : TObject);
procedure ConnectCallback(Sender: TObject);
{ Private declarations }
public
{ Public declarations }
end;
procedure SetTimerEventHandler(event handler: TNotifyEvent); external 'DLLProject.dll';
procedure SetPacketRecvdEventHandler (eventhand ler: TNotifyEvent); external 'DLLProject.dll';
procedure SetConnectEventHandler(eve nthandler: TNotifyEvent); external 'DLLProject.dll';
function nmhttpGet(url: String):String; external 'DLLProject.dll';
function nmhttpBytesRecvd:Longint; external 'DLLProject.dll';
var
Form1: TForm1;
implementation
{$R *.DFM}
procedure TForm1.TimerCallback(Sende r: TObject);
begin
Label1.Visible := not Label1.Visible;
end;
procedure TForm1.PacketRecvdCallback (Sender: TObject);
begin
Label2.Caption := IntToStr(nmhttpBytesRecvd) ;
end;
procedure TForm1.ConnectCallback(Sen der: TObject);
begin
Label3.Caption := 'Connected...';
end;
procedure TForm1.Button1Click(Sender : TObject);
begin
SetTimerEventHandler(Timer Callback);
SetPacketRecvdEventHandler (PacketRec vdCallback );
SetConnectEventHandler(Con nectCallba ck);
Memo1.Text := nmhttpGet(Edit1.Text);
end;
end.
--------------------------
unit DLLTester;
interface
uses
Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs,
StdCtrls, ExtCtrls;
type
TForm1 = class(TForm)
Button1: TButton;
Label1: TLabel;
Label2: TLabel;
Memo1: TMemo;
Label3: TLabel;
Edit1: TEdit;
procedure Button1Click(Sender: TObject);
private
procedure TimerCallback(Sender: TObject);
procedure PacketRecvdCallback(Sender
procedure ConnectCallback(Sender: TObject);
{ Private declarations }
public
{ Public declarations }
end;
procedure SetTimerEventHandler(event
procedure SetPacketRecvdEventHandler
procedure SetConnectEventHandler(eve
function nmhttpGet(url: String):String; external 'DLLProject.dll';
function nmhttpBytesRecvd:Longint; external 'DLLProject.dll';
var
Form1: TForm1;
implementation
{$R *.DFM}
procedure TForm1.TimerCallback(Sende
begin
Label1.Visible := not Label1.Visible;
end;
procedure TForm1.PacketRecvdCallback
begin
Label2.Caption := IntToStr(nmhttpBytesRecvd)
end;
procedure TForm1.ConnectCallback(Sen
begin
Label3.Caption := 'Connected...';
end;
procedure TForm1.Button1Click(Sender
begin
SetTimerEventHandler(Timer
SetPacketRecvdEventHandler
SetConnectEventHandler(Con
Memo1.Text := nmhttpGet(Edit1.Text);
end;
end.
ASKER
Adjusted points to 1000
ASKER
Epsylon, EXCELLANT. That is what I was looking for. I have not tested your code entirely but what I see is exactly what I was needing. I just need to apply it to my application. Here is 1000 points as promised and I appreciate your help. If you are interested in some contract work using Delphi 16/32 contact me. -Dave
dave@calinet.com
California Internet Connection
dave@calinet.com
California Internet Connection
ASKER