How to call functions in EXE from DLLS ?

Hi
Is there anyway by which I can call a function contained in an EXE from a dll?
The dll is loaded by the exe.GetProcAddress doesn't seem to work on exes.
Regards and thanks in advance
Paras
paraskafleyAsked:
Who is Participating?
I wear a lot of hats...

"The solutions and answers provided on Experts Exchange have been extremely helpful to me over the last few years. I wear a lot of hats - Developer, Database Administrator, Help Desk, etc., so I know a lot of things but not a lot about one thing. Experts Exchange gives me answers from people who do know a lot about one thing, in a easy to use platform." -Todd S.

brainwareCommented:
I do NOT think that is possiple, but would not mind if it was possiple tho.
i searched everywhere for such once, but learned that it was also not needed if you code a good System "plugin" etc that work good together..
0
simonetCommented:
You can use an EXE just like you use any DLL. After all, DLLs are simply EXEs with only one different bit in its header.

Both have entry points, resources, imports table, exports tables, etc. They are both PE files, and so are OCX, BPL, DPL, etc. All are the same kind of files.

In order to call, from a DLL, a function that is in an EXE, you proceed just as you would with any DLL, with no differences in the process (which I outline below):

1) Export the functions that will be visible to other modules. You can export functions from EXEs as long as the functions/procedures are not class procedures.

2) Define the prototype of the function to be imported in the calling module.

3) Load the module that contains the exported functions. You can do this using LoadLibrary.

4) Using GetProcAddress using the handle returned by the LoadLibrary call.

5) Use the function.

There are, howeverm tricks one can use to prevent problems that may arise from using the process above using EXEs (like executing the EXEs entry-point). The two tricks are:

Trick 1:
Statically link the EXE TO THE DLL, so that it won't be mapped again and you don't have to deal with LoadLibrary, GetProcAddress and the like. This also makes coding and maintenance much easier.

Trick 2:
If the EXE will be executed first, then load the DLL and then the DLL must call functions that were exported by the EXE, then you can simply pass the EXE's hInstance to the DLL. This way you don't have to call LoadLibrary from within the DLL in order to map the EXE again. just pass the global variable hInstance from the EXE to the DLL. The DLL will using this in the GetProcAddress.

There's no way of doing it without exporting functions from the EXE, unless you are willing to handle TypeLibs and the like, which are usually a major pain in the butt.

The code below is not the actual code for your specific problem, but just an example to show you how EXEs can export functions and how to call functions from the EXEs. The code was taken from a question I answered to another user, which had a similar (not identical) problem to yours. Although the import and export process in made in the same EXE, there's little - if any - difference in the approach and technique described below and the one I first told you about.


----------------

According to the common belief, EXEs cannot export functions. That's absolutely not true as you'll see by the project below. EXEs can export stuff and they can use stuff they export.

The method below outlines the basics of what I am suggesting. Once you understand the basics of it, you'll only have to adequate it to your own needs.

First of all, create a new application. In form1, put a TListBox with the following items:

ThisIsProcedure1
ThisIsProcedure2
ThisIsProcedure3
ProcedureWithParam

Create a new button.

Here's the source code for the project.

########## Listing for Project1.dpr

program Project1;

uses
  Forms,
  Unit1 in 'Unit1.pas' {Form1};

{$R *.RES}

exports
  ThisIsProcedure1,
  ThisIsProcedure2,
  ThisIsProcedure3,
  ProcedureWithParam;


begin
  Application.Initialize;
  Application.CreateForm(TForm1, Form1);
  Application.Run;
end.


########## Listing for unit1.pas

unit Unit1;

interface

uses
  Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs,
  StdCtrls;

type
  TForm1 = class(TForm)
    ListBox1: TListBox;
    Edit1: TEdit;
    Button1: TButton;
    Label1: TLabel;
    procedure Button1Click(Sender: TObject);
  private
    { Private declarations }
  public
    { Public declarations }
  end;

var
  Form1: TForm1;

type
  TWildProcedure = procedure (AnyInt : integer);


// All the procedures must follow the prototype defined by TWildProcedure.
// Otherwise they will need another "procedure type".
// Even if the procedure doesn't need any parameter, a "bumb" parameter
// must be defined.
// Not doing so will screw the stack up or not load the procedure.
procedure ThisIsProcedure1(Dumb : integer);
procedure ThisIsProcedure2(Dumb : integer);
procedure ThisIsProcedure3(Dumb : integer);
procedure ProcedureWithParam(Value : integer);


implementation

{$R *.DFM}

procedure ThisIsProcedure1(Dumb : integer);
begin
  Showmessage('procedure #1 executed!');
end;


procedure ThisIsProcedure2(Dumb : integer);
begin
  Showmessage('procedure #2 executed!');
end;

procedure ThisIsProcedure3(Dumb : integer);
begin
  Showmessage('procedure #3 executed!');
end;

procedure ProcedureWithParam(Value : integer);
begin
  ShowMessage('Sent value was '+ inttostr(Value));
end;

procedure TForm1.Button1Click(Sender: TObject);
var
  MyProc : TWildProcedure;
begin
  @MyProc := GetProcAddress(hInstance, pchar(listbox1.items[listbox1.itemindex]));
  if (@MyProc<>nil) then
     MyProc(30);
end;

end.

################## that's it!

Assign the Onclick event of the TButton to Button1OnClick. Run the project. See how it works great?!

See, no confused calls, everything is simple. The trick here is to export the functions in the EXE (yes, an EXE can export functions and work like a DLL!). Another part of the trick is that all functions/procedures must have the exact same number and types of arguments/parameters (see the remarks on the source code).

Just another thing: the GetProcAddress stuff can be in any unit, not necessarily in the one that defines "ThisIsProcedureXXX". THe only requirement is that the other unit sees the definition for TWildProcedure.

In your specific case, the method (the procedure) to be called cannot be a class method. You'll have to make a "standalone" function/procedure. Optionally, you can pass the object you're calling it from as one of the paramters.
In this model, TWildProcedure would look like this:

type TWildProcedure = procedure (Sender : TMyObject; Param1, Param2 : longint; ParamStr : string);

Create the exported functions according to TWildProcedure:

procedure ExportedProc1(Sender : TMyObject; Param1, Param2 : longint; ParamStr : string);
begin
  Sender.dosomething;
  Sender.Property1 := Param1 + 20;
end;

---------------

If you have questions regarding the code, let me know.

Yours,

Alex
0

Experts Exchange Solution brought to you by

Your issues matter to us.

Facing a tech roadblock? Get the help and guidance you need from experienced professionals who care. Ask your question anytime, anywhere, with no hassle.

Start your 7-day free trial
brainwareCommented:
Ale.. ur brilliant :)
i never TRYED. stuppid me..
mabye becuse at that time i already did enough crashes and memory leaks i stopped playing with it :)
0
paraskafleyAuthor Commented:
thanks
0
It's more than this solution.Get answers and train to solve all your tech problems - anytime, anywhere.Try it for free Edge Out The Competitionfor your dream job with proven skills and certifications.Get started today Stand Outas the employee with proven skills.Start learning today for free Move Your Career Forwardwith certification training in the latest technologies.Start your trial today
Delphi

From novice to tech pro — start learning today.