Solved

Multiple Concurrent DLLs

Posted on 2004-09-11
9
245 Views
Last Modified: 2010-04-05
I have a DLL which is called from an Office productivity app.   However, the initialisation data (provided by the caller) is unique to that instance.   This initial data is subsequently used for correct functioning of the DLL ....   At present it all works fine when I have just a single instance of the app & DLL active, but I want to progress to multiple documents ...

My question is, how do I handle multiple instances ?   I can have multiple instances of the app, and/or multiple document instances.   Can I tell the DLL to create a new instance each time (its not that big, so memory is not an issue), or should I create a new data structure for each instance with the unique data stored therein, or is there some other way ?

I would imagine this is a fairly common thing with MDI applications these days, but would like a 'heads up' before I start so I can go directly for the best solution.

Does anyone have any code snippets on this (preferably Delphi, but could convert VB or C code is necessary) ?   All help, references etc appreciated.

Thanks
Geoff
0
Comment
Question by:geoffdb
[X]
Welcome to Experts Exchange

Add your voice to the tech community where 5M+ people just like you are talking about what matters.

  • Help others & share knowledge
  • Earn cash & points
  • Learn & ask questions
9 Comments
 
LVL 2

Expert Comment

by:gary_williams
ID: 12033811
Am I correct in assuming that your DLL is an "old style" DLL, i.e., not an ActiveX library?
0
 

Author Comment

by:geoffdb
ID: 12037619
Yes, correct.   In fact, its actually an XLL (a compiled equivalent of an Excel add-in), which is in effect a DLL with some additional special functions.

Geoff
0
 
LVL 34

Accepted Solution

by:
Slick812 earned 250 total points
ID: 12041069
?????????
I really do not understand your request?
As I have used librarys, the Program that loads a DLL, has that DLL as a "Part" of it's  program's memory space. . . and if you start another instance of that same program, and load that same DLL, the two loaded DLL's will NOT have any connection to each other , variables are not shared and the two programs do not share any memory, and their DLL's do NOT share any memory (in Delphi, although in C++ you can specify some shared variable memory, and in Delphi you can have a Memory Mapped File  to share data), , ,.
And if you have a MDI, the DLL is NOT loaded more than once, no matter how many times you call LoadLibrary( ), so in a MDI you will need to have methods to have separate DATA for each Document. . . .
so you will need to have a separate DLL function for the "initialisation data" for each Document, and then keep an Array of Document Data, or other Data storage for each document. . .
maybe more information about your MDI problems would help you get a solution?
0
Independent Software Vendors: We Want Your Opinion

We value your feedback.

Take our survey and automatically be enter to win anyone of the following:
Yeti Cooler, Amazon eGift Card, and Movie eGift Card!

 
LVL 17

Expert Comment

by:Wim ten Brink
ID: 12044775
You can only load a DLL once per application. Not multiple times. Thus you can't create multiple instances of the DLL. But of whatever you do inside your DLL is up to you. You control if the objects in the DLL can be created only once or multiple times.

I'd advise to use a global variable to use for the DLL handle when you load it. Then you can share the DLL handle within all other parts of your application.
0
 

Author Comment

by:geoffdb
ID: 12062034
Alex & Slick812

Thanks for both your answers.   I understand better now.   I was hoping for some way to easily load a new DLL each time a new document was created (in the MDI instance), but it sounds like that is not possible.

Do you have, (or are able to point me to), some sample code of a simple example on this ?

Thanks
Geoff
0
 
LVL 34

Assisted Solution

by:Slick812
Slick812 earned 250 total points
ID: 12080709
Example of WHAT?, can not see what you want? I guess you can do a DLL, since you say you have one that works? ? So I guess you want some, I do not know? Store Data in DLL I GUESS? ? ?

OK some code, but this is a just one way of Thousands to store Data, Here is a Library Code that has 3 export functions -

function AddToStorage(pName: PChar; Int1, Int2: Integer): Integer;
  // this will add a storage Item and set three datas to Item

function GetStorage(Index: Integer; out pName: PChar;
                    out Int1, Int2: Integer): Bool; export;
  // this will Get three datas from storage Item Index

function DeleteStorage(Index: Integer): Bool;
  // this will Delete a Storage Item

I use a TList in the DLL for the Storage, a TList has several methods for Item addition and changes, you should look at the Delphi Help for "TList" if you need any more methods in your DLL.

code for library - - -


library demoDLL;

uses
  SysUtils, Classes,
  Windows, Messages;


type
  PInfo = ^TInfo;
  TInfo = record
    Name: String;
    Int1, Int2: Integer;
    end;


var
Storage: TList;


// do NOT use Strings in a export DLL function
function AddToStorage(pName: PChar; Int1, Int2: Integer): Integer; export;
var
pInfo1: PInfo;
begin
// adds a new Item to Storage and returns it's index, or -1 for ERROR
Result := -1;
New(pInfo1);
pInfo1.Name := pName;
pInfo1.Int1 := Int1;
pInfo1.Int2 := Int2;
try  // not to have exception in DLL is beter, just return an ERROR result for function
  Storage.Add(pInfo1);
  except
  Exit;
  end;
Result := Storage.Count-1;
end;


function GetStorage(Index: Integer; out pName: PChar;
                    out Int1, Int2: Integer): Bool; export;
var
pInfo1: PInfo;
begin
// retrives Info data from Storage Item Index
Result := False;
pName := nil;
if (Index < 0) or (Index > Storage.Count-1) then Exit;

try
pInfo1 := Storage.Items[Index];
  except
  Exit;
  end;
pName := PChar(pInfo1.Name);
Int1 := pInfo1.Int1;
Int2 := pInfo1.Int2;
Result := True;
end;

function DeleteStorage(Index: Integer): Bool; export;
begin
// deletes an Index Item from storage
Result := False;
if (Index < 0) or (Index > Storage.Count-1) then Exit;
try
  Dispose(Storage.Items[Index]);
  Storage.Delete(Index);
  except
  Exit;
  end;
Result := True;
end;


procedure AttatchProc(cReason: Cardinal);
var
i: Integer;
begin
if (cReason = Dll_Process_Detach) then
 begin
 for i := 0 to Storage.Count -1 do
   Dispose(Storage.Items[i]);
 FreeAndNil(Storage);
 end;
end;

exports
  AddToStorage,
  GetStorage,
  DeleteStorage;


begin
DLLProc := @AttatchProc;
Storage := TList.Create;
end.


 = = = = = = = = =  = = =  = = = = = = = = =  = = = =

code for button Click in program to use DLL - - - -



procedure TForm1.sbut_DoStorageDLLClick(Sender: TObject);
var
hLibS: THandle;
AddToStorage: function(pName: PChar; Int1, Int2: Integer): Integer;
GetStorage: function(Index: Integer; out pName: PChar;
                    out Int1, Int2: Integer): Bool;
DeleteStorage: function(Index: Integer): Bool;

Int1, Int2, Index: Integer;
Name: String;
pName: PChar;

begin
// button Click
hLibS := LoadLibrary('demoDLL.dll');
if hLibS = 0 then
  begin
  ShowMessage('Did not load the DLL');
  Exit;
  end;

@AddToStorage := GetProcAddress(hLibS, 'AddToStorage');
if @AddToStorage = nil then
  begin
  ShowMessage('AddToStorage is nil');
  FreeLibrary(hLibS);
  Exit;
  end;

Name := 'John Programmer';
Int1 := 111;
Int2 := 222;

{when you create a NEW Document, you can store Info for that Document
with AddToStorage}
Index := AddToStorage(PChar(Name), Int1, Int2);
if Index > -1 then
  ShowMessage('AddToStorage Worked, Index is '+IntToStr(Index))
  else
  ShowMessage('ERROR - AddToStorage   FAILED');

Name := 'SomeOne Else Jr';
Int1 := 333;
Int2 := 444;

Index := AddToStorage(PChar(Name), Int1, Int2);
if Index > -1 then
  ShowMessage('AddToStorage Worked, Index is '+IntToStr(Index))
  else
  ShowMessage('ERROR - AddToStorage   FAILED');

{getStorage will get Data from Index Item}
@GetStorage := GetProcAddress(hLibS, 'GetStorage');
if @GetStorage = nil then
  begin
  ShowMessage('GetStorage is nil');
  FreeLibrary(hLibS);
  Exit;
  end;

if GetStorage(0, pName, Int1, Int2) then
  begin
  Name := pName;
  ShowMessage('GetStorage Worked,'#10'Int1 = '+IntToStr(Int1)+' Int2 = '+
               IntToStr(Int2)+' '+Name);
  end else
  ShowMessage('ERROR - GetStorage   FAILED');

FreeLibrary(hLibS);
end;

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

but I was just guessing,
0
 

Author Comment

by:geoffdb
ID: 12082295
Slick812

That's great thanks, let me give it a whirl !!

Geoff
0
 

Author Comment

by:geoffdb
ID: 12099999
Slick812

I gave this a whirl today -it works a treat !!   Thanks.

I'm going to up the points for your good response, but have a couple of questions :

a) AttatchProc : Can you explain this to me please, and how it works, and where the cReason argument comes from - is this an automatic DLL argument ?      The function reference appears to be called only when the DLL is created, is it an implicit thing that it is called again on destroy with the DLL_Process_Detach argument ?

Alternatively, can one use create and destroy methods for the same thing ?

and secondly
b) Debugging DLLs : How do I interactively debug a DLL ?  
I was going to debug this to see how/where the AttatchProc func was called - then instantly realised that as it's a DLL can't do that with the IDE .. My experience is really only with executables, so using the IDE with them is fine ... my experience with DLLs is fairly new, have just used debug ShowMessage and/or wrteln type statements so far, but understand it is possible to debug interactively.

I'm using Delphi 6 BTW, though have 7 & 8 also.

Many thanks
Geoff
0
 
LVL 34

Expert Comment

by:Slick812
ID: 12106634
you should look in the Delphi help for "DLLProc" and it says -

   DLLProc is used to specify a procedure that is invoked every time a DLL's entry point is called, so on thread and process detatch it is called, , , Although in delphi this is not entirely accurate, you will need to ecplictly call your DLLProc with the  "DLL_PROCESS_ATTACH"  parameter to get that functioning, so that DLL_PROCESS_ATTACH is almost a usless kind of thing, you can just do any initialization code between the begin and end or call the DLLProc if you would rather - -



procedure AttatchProc(cReason: Cardinal);
var
i: Integer;
begin
if (cReason = DLL_PROCESS_ATTACH) then
  Storage := TList.Create;

if (cReason = Dll_Process_Detach) then
 begin
 for i := 0 to Storage.Count -1 do
   Dispose(Storage.Items[i]);
 FreeAndNil(Storage);
 end;
end;


begin
DLLProc := @AttatchProc;
AttatchProc(DLL_PROCESS_ATTACH);

end.


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

I do not usually Debug a DLL, except with a messageBox or some file write, however, as I understand it you can assign a program to run when you press the green "Run" arrow, and the program can run in the Debugger, allowing you to catch code misconduct, , but I have forgotten the steps needed to set a program to run, I guess it's in the delphi help
0

Featured Post

[Webinar] Learn How Hackers Steal Your Credentials

Do You Know How Hackers Steal Your Credentials? Join us and Skyport Systems to learn how hackers steal your credentials and why Active Directory must be secure to stop them. Thursday, July 13, 2017 10:00 A.M. PDT

Question has a verified solution.

If you are experiencing a similar issue, please ask a related question

A lot of questions regard threads in Delphi.   One of the more specific questions is how to show progress of the thread.   Updating a progressbar from inside a thread is a mistake. A solution to this would be to send a synchronized message to the…
Introduction I have seen many questions in this Delphi topic area where queries in threads are needed or suggested. I know bumped into a similar need. This article will address some of the concepts when dealing with a multithreaded delphi database…
In this video, viewers will be given step by step instructions on adjusting mouse, pointer and cursor visibility in Microsoft Windows 10. The video seeks to educate those who are struggling with the new Windows 10 Graphical User Interface. Change Cu…
In this brief tutorial Pawel from AdRem Software explains how you can quickly find out which services are running on your network, or what are the IP addresses of servers responsible for each service. Software used is freeware NetCrunch Tools (https…

724 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question