@Luckie: Hut ab, das ist gut.
Aber hier ein kleiner Hinweis zum Thema IPC (Inter Process Communication):
Luckie hat folgendes geschrieben: |
Auf der anderen Seite gibt es aber auch Ressourcen, die von den Prozessen geteilt werden
können. Da wären zum Beispiel dynamische Bibliotheken, die DLL's, zu nennen. Eine DLL
kann von mehreren Prozessen gleichzeitig genutzt werden. Dabei wird sie nur einmal geladen,
ihr Code aber in den Adressraum des Prozesses eingeblendet, welcher die DLL nutzt. Dies
kann man unter anderem zur Inter Process Communication nutzen. Dies hat aber des Weiteren
noch den Vorteil, dass gleicher Code nur einmal geschrieben werden muss und gleichzeitig
von mehreren Prozessen genutzt werden kann.
|
Das war mal so. Aber heute stimmt das nicht mehr!
In der Delphihilfe (D5) steht dazu:
(a) In einer DLL deklarierte globale Variablen können von Object-Pascal-Anwendungen nicht importiert werden.
(b) Eine DLL kann von mehreren Anwendungen gleichzeitig verwendet werden. Jede Anwendung verfügt aber in ihrem Verarbeitungsbereich über eine Kopie der DLL mit einem eigenen Satz globaler Variablen.
(c) Damit mehrere DLLs (oder mehrere Instanzen einer DLL) den Speicher gemeinsam nutzen können, müssen die DLLs Speicherzuordnungstabellen verwenden. Weitere Informationen zu diesem Thema finden Sie in der Dokumentation der Windows-API.
Zu (a): Das ist etwas ungeschickt formuliert, denn es ist ja durchaus möglich auf in einer DLL deklarierte globale Variablen zuzugreifen, wenn man selbst passende Funktionen dafür vorsieht.
(Siehe auch das Beispiel unten)
Zu (b): Das mit der eigenen Kopie ist das neue, denn früher existierte nur eine Instanz. Darum kann man eine DLL normalerweise nicht mehr für IPC verwenden.
Zu (c): Das weiß wohl kaum jemand, und deshalb werden die meisten, die IPC per DLL implementieren auf die Nase fallen!
Deshalb der Vorschlag, nimm das einfach raus, denn das gehört dort nicht unbedingt zum Thema.
Für alle, die das nachprüfen wollen, ist unten ein Beispiel. Die DLL hat eine globale Variable,
die beim Laden initialisiert wird. Wenn ein Programm die Get-Funktion aufruft, erhält sie den aktuellen Wert. Mit der Set-Funktion lässt sich der Wert in der DLL ändern.
Wenn nun zwei Instanzen des Test-Programms gleichzeitig laufen, und jeweils eigene Namen per Set eintragen, sieht jeder, wenn er in allen Instanzen noch die Getfunktion benutzt, dass die Werte nicht übereinstimmen. Jede Instanz hat ihre eigene Kopie der DLL. Deshalb ist es also Essig mit IPC.
1. DLL-Projektdatei
Delphi-Quelltext
1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13: 14: 15:
| library DLL;
uses SysUtils, Classes, UnitDLL in 'UnitDLL.pas';
exports GetMyGlobalName, SetMyGlobalName;
{$R *.RES}
begin end. |
2. DLL-Implementation
Delphi-Quelltext
1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13: 14: 15: 16: 17: 18: 19: 20: 21: 22: 23: 24: 25:
| unit UnitDLL;
interface
function GetMyGlobalName: ShortString; stdcall; procedure SetMyGlobalName(Value: ShortString); stdcall;
implementation
var dllMyGlobalName: ShortString;
function GetMyGlobalName: ShortString; begin Result := dllMyGlobalName; end;
procedure SetMyGlobalName(Value: ShortString); begin dllMyGlobalName := Value; end;
initialization dllMyGlobalName := 'Jungfrau'; end. |
3. Testprogramm:
1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13: 14: 15: 16: 17: 18: 19: 20: 21: 22: 23: 24: 25: 26: 27: 28: 29: 30: 31: 32: 33: 34: 35: 36: 37: 38: 39: 40: 41: 42: 43: 44: 45: 46: 47: 48: 49: 50: 51: 52: 53: 54: 55: 56: 57: 58: 59: 60: 61: 62: 63: 64:
| unit UnitFormMain;
interface
uses Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs, StdCtrls;
type TFormMain = class(TForm) EditShowName: TEdit; LabelName: TLabel; LabelNewName: TLabel; EditNewName: TEdit; ButtonSetName: TButton; ButtonGetName: TButton; procedure ButtonGetNameClick(Sender: TObject); procedure ButtonSetNameClick(Sender: TObject); procedure FormCreate(Sender: TObject); private public end;
var FormMain: TFormMain;
implementation
var cMyDLL: THandle; cGetNameProc: function: ShortSTring; stdcall; cSetNameProc: procedure (Name: ShortSTring); stdcall;
{$R *.DFM}
procedure TFormMain.ButtonGetNameClick(Sender: TObject); begin EditShowName.Text := cGetNameProc; end;
procedure TFormMain.ButtonSetNameClick(Sender: TObject); begin cSetNameProc(EditNewName.Text); EditShowName.Text := cGetNameProc; end;
procedure TFormMain.FormCreate(Sender: TObject); begin ButtonGetNameClick(nil); end;
initialization cMyDLL := LoadLibrary('DLL.dll'); @cGetNameProc := GetProcAddress(cMyDLL,'GetMyGlobalName'); @cSetNameProc := GetProcAddress(cMyDLL,'SetMyGlobalName');
finalization cGetNameProc := nil; cSetNameProc := nil; if cMyDLL <> 0 then FreeLibrary(cMyDLL); end. |
4. Formular
1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13: 14: 15: 16: 17: 18: 19: 20: 21: 22: 23: 24: 25: 26: 27: 28: 29: 30: 31: 32: 33: 34: 35: 36: 37: 38: 39: 40: 41: 42: 43: 44: 45: 46: 47: 48: 49: 50: 51: 52: 53: 54: 55: 56: 57: 58: 59: 60: 61: 62: 63: 64: 65: 66: 67: 68:
| object FormMain: TFormMain Left = 498 Top = 332 Width = 182 Height = 171 ActiveControl = EditNewName Caption = 'Test Global DLL-Name' Color = clBtnFace Font.Charset = DEFAULT_CHARSET Font.Color = clWindowText Font.Height = -11 Font.Name = 'MS Sans Serif' Font.Style = [] OldCreateOrder = False Position = poDefaultPosOnly OnCreate = FormCreate PixelsPerInch = 96 TextHeight = 13 object LabelName: TLabel Left = 8 Top = 8 Width = 87 Height = 13 Caption = 'Global DLL-Name:' end object LabelNewName: TLabel Left = 8 Top = 56 Width = 63 Height = 13 Caption = '&Neuer Name:' FocusControl = EditNewName end object EditShowName: TEdit Left = 8 Top = 24 Width = 153 Height = 21 Color = clBtnFace ReadOnly = True TabOrder = 0 end object EditNewName: TEdit Left = 8 Top = 72 Width = 153 Height = 21 TabOrder = 1 end object ButtonSetName: TButton Left = 88 Top = 104 Width = 75 Height = 25 Caption = '&Set Name' TabOrder = 2 OnClick = ButtonSetNameClick end object ButtonGetName: TButton Left = 8 Top = 104 Width = 75 Height = 25 Caption = '&Get Name' TabOrder = 3 OnClick = ButtonGetNameClick end end |
5. Test-Projekt
Delphi-Quelltext
1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13:
| program Test;
uses Forms, UnitFormMain in 'UnitFormMain.pas' ;
{$R *.RES}
begin Application.Initialize; Application.CreateForm(TFormMain, FormMain); Application.Run; end. |