Autor Beitrag
woully
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starontopic star
Beiträge: 78



BeitragVerfasst: Mo 06.07.09 11:18 
Hi,

ich hätte da mal ein problem.

Ich habe einen Service entwickelt der Daten mit einer Zweiten Software austauschen soll. Dazu verwende ich die Memory mapped files.

Meine erzeugen, lesen und schreib Funktionen von der Mappfile funktionnieren ganz gut. Der Datenaustauch zwischen 2 Software funtionniert Problemlos. Sobald aber ein Service mit einer Software Daten austauchen soll gibt es Problemen. Alle Funktionen werden Fehlerlos ausgeführt, aber die Datenwerte die mir der Service zurückgibt stimmen nicht mit den Daten die von der Zweiten Software geschrieben werden über ein....

Kann mir jemand helfen ?

Hier mal der Code von der MMF.
ausblenden volle Höhe 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:
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:
function TMemoryMappedFile.CreateMMF : Boolean;
Begin
  Result := False;
  try
    aMMFHandle := CreateFileMapping($FFFFFFFFnil,PAGE_READWRITE, 0, sizeOf(TExchangeData), Pchar('MedavisFileMapping'));
    // Sicherheitsprüfung
    if aMMFHandle = 0 then
      raise Exception.Create('CreateFileMapping-Error!');
  finally
  end;
  Result := True;
end;
{-------------------------------------------------------------------------------
 - WriteToMMF
 -------------------------------------------------------------------------------
 - Schreibt in die Memory Mapped file
 ------------------------------------------------------------------------------}

Function TMemoryMappedFile.WriteToMMF(pData : pExchangeData) : Boolean;
Begin
  Result := False;
  try
   aMMFHandle := OpenFileMapping(FILE_MAP_WRITE,False,pchar('MedavisFileMapping'));
    // Sicherheitsprüfung
    if aMMFHandle = 0 then
      exit;
    pViewData := MapViewOfFile(aMMFHandle, FILE_MAP_WRITE,000);
    CopyMemory(pViewData,pdata,SizeOf(texchangeData));
  finally
  end;
  Result := True;
end;
{-------------------------------------------------------------------------------
 - readFromMMF
 -------------------------------------------------------------------------------
 - Liest aus der Memory Mapped file
 ------------------------------------------------------------------------------}

Function TMemoryMappedFile.ReadFromMMF(var pData : pExchangeData) : boolean;
begin
  Result := False;
  try
    aMMFHandle := OpenFileMapping(FILE_MAP_READ,False,pchar('MedavisFileMapping'));
    // Sicherheitsprüfung
    if aMMFHandle = 0 then
      exit;

    pViewData := MapViewOfFile(aMMFHandle, FILE_MAP_READ, 000);
    CopyMemory(pData,pViewdata,SizeOf(texchangeData));
  finally
  end
end;


Moderiert von user profile iconNarses: Delphi-Tags hinzugefügt
Moderiert von user profile iconNarses: Überflüssige Zeilenumbrüche/Leerzeilen entfernt.
hathor
Ehemaliges Mitglied
Erhaltene Danke: 1



BeitragVerfasst: Mo 06.07.09 20:26 
Wie ist TExchangeData definiert? Die müssen bei Sender und Empfänger identisch sein.
woully Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starontopic star
Beiträge: 78



BeitragVerfasst: Di 07.07.09 09:02 
Hi,

TexchangeData habe ich in einer Unit definiert die beim Empfänger und beim Sender eingebunden ist.
Also identisch.

Wie schon erwähnt, muss das Problem irgendwie mit dem Service zusammenhängen, da der Datenaustausch mit einem Tform sender, und TForm empfänger funktionniert...
hathor
Ehemaliges Mitglied
Erhaltene Danke: 1



BeitragVerfasst: Di 07.07.09 10:47 
Sicherheitshalber mal nachgefragt:

1. die beiden Programme nutzen den gleichen physikalischen RAM ?

2. das "CreateFileMapping" wird nur von einer Seite (Sender) durchgeführt?

Wenn ja, dann teste doch mal meinen Code:
ausblenden volle Höhe 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:
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:
69:
70:
71:
72:
73:
74:
75:
76:
77:
78:
79:
80:
81:
82:
83:
84:
85:
86:
87:
88:
89:
90:
91:
92:
93:
94:
95:
96:
97:
98:
99:
100:
101:
102:
103:
104:
105:
106:
107:
108:
109:
110:
111:
112:
113:
114:
115:
116:
117:
118:
119:
120:
121:
122:
123:
124:
125:
126:
127:
128:
129:
130:
131:
132:
133:
134:
135:
136:
137:
138:
139:
140:
141:
142:
143:
144:
145:
unit Unit1;

interface

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

Type
   TExchangeData = record
   sName : array [0..99of Char;
   sTime : String[100];
   end;

   PExchangeData = ^TExchangeData;
   pViewData = ^TExchangeData;
//   pData : pExchangeData;   ???

type
  TForm1 = class(TForm)
    Label1: TLabel;
    Timer1: TTimer;
    cb_Timer: TCheckBox;
    CREATE1: TButton;
    Create2: TCheckBox;
    Write2: TCheckBox;
    Read2: TCheckBox;
    CREATE3: TLabel;
    WRITE1: TButton;
    READ1: TButton;
    WRITE3: TLabel;
    READ3: TLabel;
    READ4: TLabel;
    procedure FormCreate(Sender: TObject);
    procedure cb_TimerClick(Sender: TObject);
    procedure CREATE1Click(Sender: TObject);
    procedure WRITE1Click(Sender: TObject);
    procedure READ1Click(Sender: TObject);
    procedure Timer1Timer(Sender: TObject);

  private
    { Private-Deklarationen }
  public
    { Public-Deklarationen }
  end;

var
  Form1: TForm1;
  ExchangeData : PExchangeData;
  ViewData  : pViewData; //PExchangeData;

implementation

{$R *.dfm}


procedure TForm1.cb_TimerClick(Sender: TObject);
begin
if cb_Timer.Checked  then TIMER1.Enabled:=true else TIMER1.enabled:=false;
end;

procedure TForm1.FormCreate(Sender: TObject);
begin  //
   Label1.caption:='TEST';
end;

procedure TForm1.Timer1Timer(Sender: TObject);
begin
WRITE2.Checked:=false;
READ2.Checked:=false;
Label1.Caption:= DateTimeToStr(now);//IntToStr(Timer1.Tag);
Timer1.Tag:= Timer1.Tag +1;
if Timer1.Tag=1 then WRITE1Click(self);
if Timer1.Tag=2 then
  BEGIN
    READ1Click(self);
    Timer1.Tag:=0;
  END;
end;

function CreateMMF : Boolean;
var aMMFHandle : Integer;
Begin
  Result := False;
  try
    aMMFHandle :=
    CreateFileMapping($FFFFFFFFnil,PAGE_READWRITE, 0, sizeOf(TExchangeData),
Pchar('MedavisFileMapping'));
    if aMMFHandle = 0 then
      raise Exception.Create('CreateFileMapping-Error!');
  finally
  end;
  Result := True;
end;

function ReadInfo : Boolean;
var myHandle : Integer;
begin
  myHandle :=  OpenFileMapping(FILE_MAP_READ, False, 'MedavisFileMapping');
  if myHandle > 0 then
  begin
    ExchangeData := MapViewOfFile(myHandle, FILE_MAP_READ, 000);
    Result := True;
  end else result := false;
  CloseHandle(myHandle);
end;

procedure TForm1.CREATE1Click(Sender: TObject);
begin
CREATE2.checked:= CreateMMF; CREATE3.caption:='CREATE';
end;

procedure TForm1.WRITE1Click(Sender: TObject); //WRITE
var myHandle : Integer;
begin
WRITE2.checked:=false;
  myHandle :=  OpenFileMapping(FILE_MAP_ALL_ACCESS, False, 'MedavisFileMapping');
  if myHandle > 0 then
  BEGIN
    ExchangeData := MapViewOfFile(myHandle, FILE_MAP_ALL_ACCESS, 000);

    with ExchangeData^ do
    BEGIN
    sName:= 'OK';
    sTime:= DateTimeToStr(now);
    END;

  CloseHandle(myHandle);
  WRITE3.Caption:='OK'; WRITE2.checked:=true;
  END;
end;


procedure TForm1.READ1Click(Sender: TObject);
begin  //READ
// READ2.checked:=false;
 //if ReadInfo=True then //muss entfallen wegen Speicherleck
// BEGIN
 READ2.checked:=true;
 READ3.caption:= ExchangeData.sName;
 READ4.caption:= ExchangeData.sTime;
// END;
end;

end.
Einloggen, um Attachments anzusehen!
woully Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starontopic star
Beiträge: 78



BeitragVerfasst: Di 07.07.09 11:45 
humm,

dein code funktionniert auch.

Das mit dem RAM... Kann ich irgendwie nachvollziehen wo sich windows die Datei ablegt ?.
Vermutlich arbeitet eine TService Klasse anderst als die TForm..
hathor
Ehemaliges Mitglied
Erhaltene Danke: 1



BeitragVerfasst: Di 07.07.09 11:56 
user profile iconwoully hat folgendes geschrieben Zum zitierten Posting springen:
humm,

dein code funktionniert auch.

Das mit dem RAM... Kann ich irgendwie nachvollziehen wo sich windows die Datei ablegt ?.
Vermutlich arbeitet eine TService Klasse anderst als die TForm..


Ich wollte mit meiner Frage nach dem RAM nur sicher gehen, dass das RAM in EINEM PC genutzt wird und nicht in ZWEI VERSCHIEDENEN! Ausserdem darf "CreateFileMapping" nur 1 mal ausgeführt werden.
woully Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starontopic star
Beiträge: 78



BeitragVerfasst: Di 07.07.09 12:07 
;-)

ok, also da kannst du beruhigt sein. Beide programme laufen auf dem gleichen PC...

Ich habe mal einen Schreib und Lese Zugriff aus meinem Service getestet. Da funktioniert es.

pfff... keinen Schimer mehr wo das Problem liegen könnte... :cry:
ffgorcky
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starontopic star
Beiträge: 573

WIN XP/2000 & 7Prof (Familie:Win95,Win98)

BeitragVerfasst: Di 07.07.09 12:55 
Also entschuldigung, falls ich damit das ganze auf "unsaubere Abwege" bringe, aber ich fände es wesentlich einfacher, das ganze in einer Datei zwischenzuspeichern, so das das andere Programm (z.B. timer-gesteuert) immer nur nachguckt, ob eine neue Datei-Nachricht für ihn da ist - z.B. mit:
ausblenden Delphi-Quelltext
1:
2:
3:
4:
uses DateUtils; 
{Formvariable:}
var LetzterDateiaustausch:TDateTime;
    FilePfadUndName:String

ausblenden 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:
26:
27:
28:
procedure TFormWieAuchImmerDuSieNennst.OnCreate(Sender: TObject);
begin
FileName:='WieAuchImmerDuDieDateiNennstEvtlMitPfadVorausWennSieNichtImSelbenVerzeichnisStehenDarf.Endung'
end;


procedure TFormWieAuchImmerDuSieNennst.TimerDateiaustauschOnTimer(Sender: TObject);
var VergangeneZeit:
begin
if FileExists(FilePfadUndName) then  
  begin  
  VergangeneZeit:=now-LetzterDateiaustausch;  
  HoursRemaining:=Trunc(VergangeneZeit * 24);  
  MinutesRemaining:=Trunc((VergangeneZeit*24-HoursRemaining)*60);  
  SecondsRemaining:=Trunc(((VergangeneZeit*24-HoursRemaining)*60-MinutesRemaining)*60);  
  Edit1.Text:=Format('%d:%d:%d',[HoursRemaining,MinutesRemaining,SecondsRemaining]);  

    FileDate := FileAge(FileName);  
    DateTime := FileDateToDateTime(FileDate);
    if SecondsBetween(LetzterDateiaustausch, DateTime) > 30 then  
    begin  
      // Datei ist älter als 30 Sekunden, also Dateiaustausch und
      FileClose(filecreate(FileName)); 
      if deletefile(FileName)
      LetzterDateiaustausch:=DateTime;
    end;  
  end;  
end;

Wobei ich das jetzt ja nur von diesem und diesem Beitrag ohne Kontrolle (weil ich hier leider gerade keine Entwicklungsumgebeung habe!) abgewandelt habe und ich habe auf dem Gebiet sonst auch noch nich so wirklich viele Erfahrungen...
...und ich muss jetzt leider abrupt aufhören, da ich jetzt einen anderen Termin habe... *grmpf*


Zuletzt bearbeitet von ffgorcky am Di 07.07.09 13:21, insgesamt 3-mal bearbeitet
woully Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starontopic star
Beiträge: 78



BeitragVerfasst: Di 07.07.09 13:18 
hummm stimmt,

wäre nä möglichkeit...

Trotzdem würde ich gerne die lösung es über filemapping zu machen.
hathor
Ehemaliges Mitglied
Erhaltene Danke: 1



BeitragVerfasst: Di 07.07.09 13:23 
Dann nimm doch mal meinen Code und DEIN TExchangeData, um zu sehen, ob die Daten schon da verstümmelt werden.
z.B. durch zuwenig oder unterschiedliche Speicherreservierung, andere Reihenfolge bei der Definition...

Was noch wichtig ist:

ausblenden Delphi-Quelltext
1:
2:
   sName : array [0..99of Char; //funktioniert auch, wenn das sendende Programm nit C++ compiliert worden ist
   sTime : String[100]; //funktioniert nicht, wenn das sendende Programm nit C++ compiliert worden ist
woully Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starontopic star
Beiträge: 78



BeitragVerfasst: Di 07.07.09 13:42 
Hi,

hatte bei dem Test mit deinem Quellcode schon getestet.

Könnte es irgend etwas mit zugriffsberechtigung zu tun haben, wenn die Mapped Datei aus einem Windows dienst angesprochen wird ?
BenBE
ontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic starofftopic star
Beiträge: 8721
Erhaltene Danke: 191

Win95, Win98SE, Win2K, WinXP
D1S, D3S, D4S, D5E, D6E, D7E, D9PE, D10E, D12P, DXEP, L0.9\FPC2.0
BeitragVerfasst: Di 07.07.09 13:42 
user profile iconhathor hat folgendes geschrieben Zum zitierten Posting springen:
ausblenden Delphi-Quelltext
1:
2:
   sName : array [0..99of Char; //funktioniert auch, wenn das sendende Programm nit C++ compiliert worden ist
   sTime : String[100]; //funktioniert nicht, wenn das sendende Programm nit C++ compiliert worden ist


Doch, würde schon mit C++ funzen; muss dann aber so hier ausschauen (in C++):
ausblenden C#-Quelltext
1:
2:
3:
4:
struct {
    unsigned char len;
    char string[100];
} deinString;


Wobei Du jedes Mal dich selber um die Länge kümmern darfst ...

@Berechtigungen: Jap. Da auf Local System-Objekte nahezu niemand zugriff hat, außer Local System. ggf. mal mit DupHandle probieren, dass Handle an den Client-Prozess zu verschicken ...

_________________
Anyone who is capable of being elected president should on no account be allowed to do the job.
Ich code EdgeMonkey - In dubio pro Setting.
woully Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starontopic star
Beiträge: 78



BeitragVerfasst: Di 07.07.09 15:38 
DupHandle ?

muss ich zugeben das ich jetzt überfordert bin.. ich habe zwar eineiges auf internet gefunde, aber nichts was mit Mapping files zu tun hat..

Haäätest du ein kleines Beispiel ?

danke
BenBE
ontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic starofftopic star
Beiträge: 8721
Erhaltene Danke: 191

Win95, Win98SE, Win2K, WinXP
D1S, D3S, D4S, D5E, D6E, D7E, D9PE, D10E, D12P, DXEP, L0.9\FPC2.0
BeitragVerfasst: Di 07.07.09 15:43 
Du duplizierst mit DuplicateHandle einfach das Access Token für die MMF und schenkst eine Kopie davon dem Zielprozess.

Alternativ könntest Du das MMF auch auf eine reale Datei abbilden, statt das ganze rein im RAM zu halten.

Schau auch einmal, ob du dein MMF sauber flushst (zum Speichern der Änderungen), da das AFAIR nicht automatisch zwischen den Prozessen transparent gemappt wird.

_________________
Anyone who is capable of being elected president should on no account be allowed to do the job.
Ich code EdgeMonkey - In dubio pro Setting.
Xentar
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starofftopic star
Beiträge: 2077
Erhaltene Danke: 2

Win XP
Delphi 5 Ent., Delphi 2007 Prof
BeitragVerfasst: Di 07.07.09 16:14 
Wäre es nicht auch möglich, dass du einen Fehler in deiner Lese-Prozedur, und nicht im MMF selber hast?

_________________
PROGRAMMER: A device for converting coffee into software.
hathor
Ehemaliges Mitglied
Erhaltene Danke: 1



BeitragVerfasst: Di 07.07.09 16:26 
Vielleicht verwendest Du in beiden Programmen verschiedene Variablen (globale, lokale, nicht initialisierte usw.)
woully Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starontopic star
Beiträge: 78



BeitragVerfasst: Di 07.07.09 16:27 
Hallo Xentar,

nein. Ich habe die Schreib und Lese funktionen getestet, indem ich mit Zwei Programme auf die MMF zugegriffen habe.
Sobald ich aber mit einem Dienst auf die MMF zugreife funktionniert es nicht.

Ich glaube schon das BenBE mich auf den richtigen Weg gebracht hat.
Ich teste mal das DuplicateHandle und gebe euch dann das Ergebnis.
hathor
Ehemaliges Mitglied
Erhaltene Danke: 1



BeitragVerfasst: Di 07.07.09 17:06 
Return Value

If the function succeeds, the return value is the starting address of the mapped view.

If the function fails, the return value is NULL. To get extended error information, call GetLastError.

Lass Dir doch mal return value anzeigen.
MSCH
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic star
Beiträge: 1448
Erhaltene Danke: 3

W7 64
XE2, SQL, DevExpress, DevArt, Oracle, SQLServer
BeitragVerfasst: Di 07.07.09 19:31 
Lass doch mal dein Service unter einen User-Account (dengleichen den die anwendung verwendet) laufen.
Was passiert da?
:-msch

_________________
ist das politisch, wenn ich linksdrehenden Joghurt haben möchte?
woully Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starontopic star
Beiträge: 78



BeitragVerfasst: Mi 08.07.09 09:38 
Hi,

so jetzt bin ich kurz vor dem kündigen..
Ich habe soweit alles getestet, versucht, quellcode nachgeprüft...
Rückgabewerte sind i.O., Pointer adressen stimmen.
Dieser sche*** funktioniert nicht. :evil:

Ich habe mal meine Memory Mapping funktionen in eine DLL eingefügt, und einen pointer als Shared ausgegeben.
Das funktionniert auch nicht...

Jemand noch nä idee ???
:?: