Link to home
Start Free TrialLog in
Avatar of dave5050
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
Avatar of Epsylon
Epsylon

Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial
Avatar of dave5050
dave5050

ASKER

Epsylon, Good answer but your sample does not compile. It barfs when declaring nm_http and such in the var section. For another 300-500 points can you provide a working sample also with a sample call to nm_http.get(url) and how to respond to events from the nm_http component?
dave5050, you need to add the required units to a Uses statement to get the sample to compile...
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.

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(Sender: 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.

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(Sender: 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?...;)
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.
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.mhoPacketRecvd(Sender: 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(DLLHandler.mhoPacketRecvd);

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(eventhandler: TNotifyEvent);
begin
  Timer.OnTimer := eventhandler;
end;

procedure SetPacketRecvdEventHandler(eventhandler: TNotifyEvent);
begin
  nm_http.OnPacketRecvd := eventhandler;
end;

procedure SetConnectEventHandler(eventhandler: 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 '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(eventhandler: TNotifyEvent); external 'DLLProject.dll';
  procedure SetPacketRecvdEventHandler(eventhandler: TNotifyEvent); external 'DLLProject.dll';
  procedure SetConnectEventHandler(eventhandler: 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(Sender: TObject);
begin
  Label1.Visible := not Label1.Visible;
end;

procedure TForm1.PacketRecvdCallback(Sender: TObject);
begin
  Label2.Caption := IntToStr(nmhttpBytesRecvd);
end;

procedure TForm1.ConnectCallback(Sender: TObject);
begin
  Label3.Caption := 'Connected...';
end;

procedure TForm1.Button1Click(Sender: TObject);
begin
  SetTimerEventHandler(TimerCallback);
  SetPacketRecvdEventHandler(PacketRecvdCallback);
  SetConnectEventHandler(ConnectCallback);
  Memo1.Text := nmhttpGet(Edit1.Text);
end;

end.

Adjusted points to 1000
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