Delphi-PRAXiS

Delphi-PRAXiS (https://www.delphipraxis.net/forum.php)
-   Win32/Win64 API (native code) (https://www.delphipraxis.net/17-win32-win64-api-native-code/)
-   -   Text (Pfadangabe) per Windows Message verschicken (https://www.delphipraxis.net/133736-text-pfadangabe-per-windows-message-verschicken.html)

lbccaleb 7. Mai 2009 19:35


Text (Pfadangabe) per Windows Message verschicken
 
Hallo,

ist es möglich Text per eigene Message zu verschicken und dabei nicht WM_COPYDATA zu nutzen??

Habe schon das hier gefunden:

Send Message


aber das ist nicht das wahre, da er ab und zu nur Kaudawelsch bekommt! Oder liegts an mir??

oki 7. Mai 2009 20:02

Re: Text (Pfadangabe) per Windows Message verschicken
 
Reservier den notwendigen Speicher und übergib den Zeiger in LParam oder WParam. Dein Beispiel ist aber auch nichts anderes. Das gilt natürlich auch für Zeiger auf Records oder Instancen von Klassen (also Objekte).

Gruß oki

lbccaleb 7. Mai 2009 20:17

Re: Text (Pfadangabe) per Windows Message verschicken
 
Wie soll ich den speicher reservieren? In der anderen Anwendung weiß ich ja nicht wie groß der Text ist, der dort ankommt? Oder hab ich gerade nur ne Denkblockade?

himitsu 7. Mai 2009 20:25

Re: Text (Pfadangabe) per Windows Message verschicken
 
nja, direkt Speicher reservieren mußt du nicht ... du mußt nur einen Zeiger auf die geünschten Daten verschicken und beim Empfänger ab dieser Adresse die Daten auslesen (wenn es ein anderer Prozeß ist, dann z.B. per MSDN-Library durchsuchenReadProcessMemory)

oki 7. Mai 2009 20:30

Re: Text (Pfadangabe) per Windows Message verschicken
 
Joop, so wie himitsu es beschreibt. Eigentlich ist jede Variable auch ein Zeiger auf eine Speicherstelle. Der Witz ist nur, ob dieser Zeigen auch noch gültig ist wenn die Message ankommt. Bei einer lokalen Variable sehe ich das sehr kritisch.
Die Verwendung von SendMessage kommt nicht von Ohne. SendMessage wartet eigentlich auf die Ausführung und kehrt nach der Ausführung wieder zurück. Damit sollte eigentlich nichts schief gehen. Vertrauen würd ich darauf jetzt aber nicht.

Gruß oki

lbccaleb 7. Mai 2009 20:45

Re: Text (Pfadangabe) per Windows Message verschicken
 
Ich hab jetzt noch eine Möglichkeit gefunden das mit der GlobalAtom Function von Windows zu machen! Ist das eine gute lösung oder sollte ich davon lieber die Finger lassen? Hab nicht wirklich nen Schimmer wozu genau diese GlobalAtom Function ist oO

oki 7. Mai 2009 20:55

Re: Text (Pfadangabe) per Windows Message verschicken
 
Damit kannst du sozusagen einen systemweiten Wert registrieren (oder so). Das ist aber eher nicht dein Weg. Mehr mit Kanonen auf Spatzen geschossen.

Mußt du denn unbedingt SendMessage verwenden? Trotzdem sollte das mit dem PChar im Param klappen. Wenn dabei Mist raus kommt, dann ist dein Zeiger ungültig geworden oder an einer anderen Stelle schmiert was über den Speicher.

Gruß oki

lbccaleb 7. Mai 2009 21:09

Re: Text (Pfadangabe) per Windows Message verschicken
 
Zitat:

Zitat von oki
Mußt du denn unbedingt SendMessage verwenden? Trotzdem sollte das mit dem PChar im Param klappen. Wenn dabei Mist raus kommt, dann ist dein Zeiger ungültig geworden oder an einer anderen Stelle schmiert was über den Speicher.

Gruß oki

Wieso? Was sollte ich sonnst verwenden? Ich schicke eine Pfadangabe als PChar in eine andere instanz der selben Anwendung (in dem Fall die Hauptinstanz) in welcher bei ankunft der Message was der Pfad (in dem Fall ne Medien Datei) abgespielt werden soll!

Messages währen eigentlich genau das richtige denke ich :gruebel:

Muetze1 7. Mai 2009 22:11

Re: Text (Pfadangabe) per Windows Message verschicken
 
Nutze dazu u.a. die GlobalLock() Funktion. Du versendest das Handle und jede Anwendung holt sich den Zeiger für den Zugriff mit GlobalLock.

lbccaleb 8. Mai 2009 05:21

Re: Text (Pfadangabe) per Windows Message verschicken
 
Habs jetzt so gelöst, aber irgendwie bekomme ich immer nur die ersten 3 Zeichen von der Pfandangabe! Was ist da noch falsch?


Delphi-Quellcode:
procedure GlobalAllocFileName(aWnd: HWND; aText: String);
var
  Data: THandle;
  DataPtr: Pointer;
  Size: Integer;
  oldWND: HWND;
begin
  Size := Length(aText) + 1;

    Data := GlobalAlloc(GMEM_MOVEABLE or GMEM_DDESHARE, Size);
    try
      DataPtr := GlobalLock(Data);
      try
        Move(PChar(aText)^, DataPtr^, Size);
            PostMessage(aWnd, WM_TSOPLAYFILE, INTEGER(dataptr^), 0)

      finally
        GlobalUnlock(Data);
      end;
    except
      GlobalFree(Data);
      raise;
    end;
end;
Den Code hab ich mehr oder weniger hier aus dem Forum!

himitsu 8. Mai 2009 09:17

Re: Text (Pfadangabe) per Windows Message verschicken
 
ich würd es am Einfachsten so machen ... auf jedenfall mußt du data verschicken, der andere Prozess holt sich dann über diesen globalen Wert in data selber per GlobalLock die Daten in seinen Arbeitsspeicher und kann dann daraus lesen.
Delphi-Quellcode:
Data := GlobalAlloc(GMEM_MOVEABLE or GMEM_DDESHARE, Size);
try
  DataPtr := GlobalLock(Data);
  try
    CopyMemory(DataPtr, PChar(aText), Size);
  finally
    GlobalUnlock(Data);
  end;
  SendMessage(aWnd, WM_TSOPLAYFILE, data, 0);
finally
  GlobalFree(Data);
end;
PS: hiermit INTEGER(dataptr^) versendest du nur die ersten 4 Byte direkt im Parameter.

lbccaleb 8. Mai 2009 13:22

Re: Text (Pfadangabe) per Windows Message verschicken
 
Ich dachte ich kann die Daten dann in der Message des Empfängers einfach per Pointer auslesen! Muss ich dort auch mit GlobalAlloc arbeiten?

Im Empänger sieht es so aus:

Delphi-Quellcode:
var
  MSGFile: PChar;


    WM_TSOPLAYFILE:
      begin;
        MSGFile := PChar(@wParam);
            MessageBox(0, MSGFile, 'param', MB_OK or MB_ICONWARNING);
//mit deinem Code bekomme ich jetzt hier eine endlos lange Message...
        if FileExists(MSGFile) then
          begin;
            PostMessage(HWND_TOPMOST, WM_COMMAND, MAKELONG(IDC_BMPBUTTON2, BN_CLICKED), 0);
            if Succeeded(CheckFile(MSGFile)) then
              PostMessage(HWND_TOPMOST, WM_COMMAND, MAKELONG(IDC_BMPBUTTON1, BN_CLICKED), 0)
          end;
      end;

Wie muss das hier aussehen? Also wie lese ich den Speicher mit GlobalAlloc?


Edit:
Achja, ist PostMessage in dem Fall nicht besser als SendMessage in deinem Code?
@himitsu

himitsu 8. Mai 2009 13:31

Re: Text (Pfadangabe) per Windows Message verschicken
 
Einfach so mit einem Pointer geht das nicht ... wie auch, da beide Programme ihren eigenen virtuellen Arbeitsspeicher haben.


Delphi-Quellcode:
DataPtr := GlobalLock(wParam);
try
  s := PChar(DataPtr); // oder sonstwas
finally
  GlobalUnlock(wParam);
end;
mit GloablAlloc wird Speicher außerhalb deiner Anwendung reserviert
und mit GlobalLock wird dieser Speicher in den Adreßraum deiner Anwendung verschoben
danach mit GlobalUnlock wieder aus dem Adreßraum deiner anwendung entfernt
und nun kann sich die andere Anwendung diesen Speicher auch mal in ihren Adreßraum legen und diesen so auslesen.

lbccaleb 8. Mai 2009 13:44

Re: Text (Pfadangabe) per Windows Message verschicken
 
Erstmal danke für deine Erklärung :thumb:

Hab das ganze nun erstmal wieder in eine Funktion gepackt, die es dann auslesen soll (sonnst seh ich bald gar nicht mehr durch^^)

Delphi-Quellcode:
function GetAllocFileName(wParam: WPARAM): PChar;
var
  DataPtr: Pointer;
  begin;
    Result := '';
    DataPtr := GlobalLock(wParam);
    try
      Result := PChar(DataPtr); // oder sonstwas
    finally
      GlobalUnlock(wParam);
    end;
  end;


Delphi-Quellcode:
    WM_TSOPLAYFILE:
      begin;
        MSGFile := GetAllocFileName(wParam);//PChar(@wParam);
            MessageBox(0, MSGFile, 'param', MB_OK or MB_ICONWARNING);
        if FileExists(MSGFile) then
          begin;
            PostMessage(HWND_TOPMOST, WM_COMMAND, MAKELONG(IDC_BMPBUTTON2, BN_CLICKED), 0);
            if Succeeded(CheckFile(MSGFile)) then
              PostMessage(HWND_TOPMOST, WM_COMMAND, MAKELONG(IDC_BMPBUTTON1, BN_CLICKED), 0)
          end;
      end;
Aber ich bekomme schon wieder nur 3x Cryptisches Zeug angezeigt??

Das aber ne schwere Geburt mit mir und GlobalAlloc :lol:

himitsu 8. Mai 2009 13:49

Re: Text (Pfadangabe) per Windows Message verschicken
 
Zitat:

Zitat von lbccaleb
Achja, ist PostMessage in dem Fall nicht besser als SendMessage in deinem Code?

nee, SendMessage wertet, bis das andere Programm fertig ist
und das hab ich hier mal ausgenutzt, damit die Speicher reservierung und Freigabe in einer Hand (Programm) bleibt.

Delphi-Quellcode:
Data := GlobalAlloc(GMEM_MOVEABLE or GMEM_DDESHARE, Size);
If Data <> 0 Then Begin
  Try
    DataPtr := GlobalLock(Data);
    If DataPtr <> nil Then Begin
      Try
        CopyMemory(DataPtr, PChar(aText), Size);
        If SendMessage(aWnd, WM_TSOPLAYFILE, Data, 0) = 0 Then {Fehler};
      Finally
        GlobalUnlock(Data);
      End;
    End Else {Fehler};
  Finally
    GlobalFree(Data);
  End;
End Else {Fehler};
da die Speicherverwaltung des Strings aber Delphi übernimmt und PChar intern für einen vorhandenen Speicher sorgt, kann eigentlich keine Exception entstehen (es sei den du hast irgendwo anders ein großes Problem)
Delphi-Quellcode:
Data := GlobalAlloc(GMEM_MOVEABLE or GMEM_DDESHARE, Length(aText) + 1);
If Data <> 0 Then Begin
  DataPtr := GlobalLock(Data);
  If DataPtr <> nil Then Begin
    CopyMemory(DataPtr, PChar(aText), Length(aText) + 1);
    If SendMessage(aWnd, WM_TSOPLAYFILE, Data, 0) = 0 Then {Fehler};
    GlobalUnlock(Data);
  End Else {Fehler};
  GlobalFree(Data);
End Else {Fehler};
und die andere Seite hatte ich ja schon geschrieben
Delphi-Quellcode:
DataPtr := GlobalLock(wParam);
If DataPtr = nil Then Begin
  Try
    s := PChar(DataPtr); // oder sonstwas
  Finally
    GlobalUnlock(wParam);
  End;
End Else {Fehler};

Tyrael Y. 8. Mai 2009 14:07

Re: Text (Pfadangabe) per Windows Message verschicken
 
Zitat:

Zitat von himitsu
nee, SendMessage wertet, bis das andere Programm fertig ist
und das hab ich hier mal ausgenutzt, damit die Speicher reservierung und Freigabe in einer Hand (Programm) bleibt.

SendMessage wartet auf den Empfang der WindowMessage.
Eine WindowMessage gilt als empfangen, wenn die WndProc des Empgängers verlassen wurde.

Eine Verarbeitung im WndProc ist daher sehr bedenklich, da das andere Programm solange blockiert wird.

Besser wäre die Variable im anderen Programm solange gültig zu halten bis eine "Verarbeitung-Beendet" Message zurück kommt.

Zitat:

Programm_A -> Daten -> Programm B
Programm_A hält Variable im Speicher
ProgrammB Verarbeitung();
ProgrammB -> Nachricht über Ende -> Programm A gibt Variable frei

lbccaleb 16. Mai 2009 18:18

Re: Text (Pfadangabe) per Windows Message verschicken
 
Sorry, ist schon ne Weile her, hatte aber nicht viel Zeit :(

Aufjedenfall habe ich immer noch das Problem, das nichts ankommt, sieht vllt irgendjemand noch nen Fehler??
Ich bin schon tierisch am Verzweifeln :(

und das verstehe ich auch nicht so:

Delphi-Quellcode:
If DataPtr = nil Then Begin
  Try
    s := PChar(DataPtr); // oder sonstwas
  Finally
    GlobalUnlock(wParam);
  End;
Wieso soll der Ptr nil sein?? muss der nicht auf ne Addresse zeigen?

himitsu 16. Mai 2009 18:24

Re: Text (Pfadangabe) per Windows Message verschicken
 
ups ... <> nil natürlich :oops:

im Fehlerfall liefert GlobalLock ein NIL zurück.

lbccaleb 16. Mai 2009 18:31

Re: Text (Pfadangabe) per Windows Message verschicken
 
OK, aber wenn ich auf ungleichheit Prüfe kommt bei mir der Fehler, also ist GlobalLock fehlgeschlagen, aber wieso??


Meine Funktionen:

Senden:
Delphi-Quellcode:
procedure GlobalAllocFileName(aWnd: HWND; aText: String);
var
  Data: THandle;
  DataPtr: Pointer;
  Size: Integer;
  oldWND: HWND;
begin
{  Size := Length(aText) + 1;
  Data := GlobalAlloc(GMEM_MOVEABLE or GMEM_DDESHARE, Size);
  try
    DataPtr := GlobalLock(Data);
    try
      CopyMemory(DataPtr, PChar(aText), Size);
    finally
      GlobalUnlock(Data);
    end;
    SendMessage(aWnd, WM_TSOPLAYFILE, data, 0);
  finally
    GlobalFree(Data);
  end; }
  Data := GlobalAlloc({GMEM_MOVEABLE or GMEM_DDESHARE}GHND, Length(aText) + 1);
  If Data <> 0 Then Begin
    DataPtr := GlobalLock(Data);
    If DataPtr <> nil Then Begin
      CopyMemory(DataPtr, PChar(aText), Length(aText) + 1);
      If SendMessage(aWnd, WM_TSOPLAYFILE, Data, 0) = 0 Then {Fehler}
        begin
          MessageBox(0, 'senden fehlgeschlagen', 'fehler', MB_OK or MB_ICONWARNING);
          GlobalUnlock(Data);
        end;
    End Else {Fehler}
      MessageBox(0, 'dataptr leer', 'fehler', MB_OK or MB_ICONWARNING);
    GlobalFree(Data);
  End Else {Fehler}
    MessageBox(0, 'data leer', 'fehler', MB_OK or MB_ICONWARNING);
  end;
Empfangen:
Delphi-Quellcode:
function GetAllocFileName(wParam: WPARAM): PChar; //wparam ist nicht 0
var
  DataPtr: Pointer;
  begin;
    Result := '';
    DataPtr := GlobalLock(wParam); //aber hier gibts nen "nil" ich vermute das hier irgendwo mein Fehler steckt
    If DataPtr <> nil Then Begin
      Try
        Result := PChar(DataPtr); // oder sonstwas
        MessageBox(0, 'get - pointer nil', 'fehler', MB_OK or MB_ICONWARNING);
      Finally
        GlobalUnlock(wParam);
      End;
    End Else {Fehler}
      MessageBox(0, 'get - dataptr leer', 'fehler', MB_OK or MB_ICONWARNING);
  end;

Nachrichtenschleife vom Hauptprogramm:
Delphi-Quellcode:
    WM_TSOPLAYFILE:
      begin;
        MSGFile := GetAllocFileName(wParam);//PChar(@wParam);
        MessageBox(0, MSGFile, 'param', MB_OK or MB_ICONWARNING);

        if FileExists(MSGFile) then
          begin;
            PostMessage(HWND_TOPMOST, WM_COMMAND, MAKELONG(IDC_BMPBUTTON2, BN_CLICKED), 0);
            if Succeeded(CheckFile(MSGFile)) then
              PostMessage(HWND_TOPMOST, WM_COMMAND, MAKELONG(IDC_BMPBUTTON1, BN_CLICKED), 0)
          end;
        Result := 1;
      end;
initialization abschnitt von der Anwendung:
Delphi-Quellcode:
initialization
  begin;
    if paramcount > 0 then
      Param := paramstr(1);
    tMutex := CreateMutex(nil, True, ClassName);
    if GetLastError = ERROR_ALREADY_EXISTS then
      begin;
        if fileexists(Param) then
          begin;
            if (FindWindow(ClassName, AppName) > 0) then
              GlobalAllocFileName(FindWindow(ClassName, AppName), Param)
//            PostMessage(FindWindow(ClassName, AppName), WM_TSOPLAYFILE, INTEGER(@Param), 0)
          end
        else
          MessageBox(0, 'The Program is already running.', ClassName, MB_OK or MB_ICONWARNING);
        Halt;
      end;
  end;

Sorry für nen bissel viel Code :)

Muetze1 17. Mai 2009 00:03

Re: Text (Pfadangabe) per Windows Message verschicken
 
Dein Problem derzeit ist, dass der Sender den Speicher noch immer gelockt hat. Du hast derzeit beim Sender folgenden Ablauf:

1. Speicher alloziieren
2. Speicher locken, Pointer holen
3. Speicher befüllen (Pointer beschreiben)
4. Nachricht versenden mit dem Handle von 1.
5. Speicher unlocken
6. Speicher freigeben.

Wenn du an Stelle 4. bist, dann empfängt dieser das Handle von 1. und versucht nun ebenfalls mit GlocalLock ein exklusiven Lock zu bekommen, was ihm aber von Windows verwehrt wird, da das Handle derzeit von deinem Sender noch gelockt ist.

Also, der korrekte Ablauf sollte anhand der Nummerierung von zuvor wie folgt sein: 1., 2., 3., 5., 4., 6.

Also vorher unlocken, nur im ungelockten Zustand kann Windows den speicher virtuell zwischen den Prozessen verschieben. So lange einer den glockt hat, hat er den Finger drauf und Windows ist machtlos.

lbccaleb 17. Mai 2009 13:42

Re: Text (Pfadangabe) per Windows Message verschicken
 
Ich bin echt mit meinem Latein am ende :(

Habs so gemacht wie du gesagt hast aber geht nicht :(

Delphi-Quellcode:
function GetAllocFileName(wParam: WPARAM): PChar; //wparam ist nicht 0
var
  DataPtr: Pointer;
  begin;
    Result := '';
    DataPtr := GlobalLock(wParam); //aber hier gibts nen "nil" ich vermute das hier irgendwo mein Fehler steckt
// hier gibts laut getlasterror ein ungültiges handle :(
    If DataPtr <> nil Then Begin
      Try
        Result := PChar(DataPtr); // oder sonstwas
        MessageBox(0, 'get - pointer nil', 'fehler', MB_OK or MB_ICONWARNING);
      Finally
        GlobalUnlock(wParam);
      End;
    End Else {Fehler}
      MessageBox(0, 'get - dataptr leer', 'fehler', MB_OK or MB_ICONWARNING);
  end;
Erstmal danke für deine Hilfe, fällt dir noch was ein was falsch sein könnte?? *grummel*

mfg Caleb

Luckie 17. Mai 2009 14:09

Re: Text (Pfadangabe) per Windows Message verschicken
 
Was spricht eigentlich gegen WM_COPYDATA? Warum der Umstand?

SirThornberry 17. Mai 2009 14:24

Re: Text (Pfadangabe) per Windows Message verschicken
 
@Luckie: Das habe ich mich auch gefragt. wm_copydata ist die einfachste Variante (da dabei automatisch dafür gesorgt wird das die Daten im anderen Prozess gelesen werden können). Aber weil das nicht auf Anhieb funktioniert hat, wird eine kompliziertere Lösung gesucht bei der letzendlich genau an der gleichen Stelle der Fehler zu beseitigen ist + das was wm_copydata für einen von allein macht.
Anstelle hier einen riesen Umweg zu gehen wäre es aus meiner sicht Ratsamer zu schauen was und warum wm_copydata angeblich nicht funktioniert.

lbccaleb 17. Mai 2009 14:31

Re: Text (Pfadangabe) per Windows Message verschicken
 
Hallo,

das ist richtig, es ist die einfachste Lösung, und ja sie Funktioniert auch, aber ich möchte ganz gerne den anderen Weg geklärt haben ;)
In späteren Programmen möchte ich dann auf diesen weg weiter arbeiten, und wenn ich den Fehler finde, sollte die Funktionen auch gehen!

Bloß weil es im mom ein wenig schwierig ist (insbesondere weil ich nicht so rcht weiß wo der Fehler liegt) muss es Ihn aber geben, und ich währe halt zufrieden wenn ich diese Lösung benutzen könnte! Wenn alles nichts hilft, dann muss ich wohl auf WM_COPYDATA umsteigen, was ich aber eigentlich nicht vorgehabt habe, da ich dort KEINE eigene Messages nutzen kann.

Luckie 17. Mai 2009 15:05

Re: Text (Pfadangabe) per Windows Message verschicken
 
Eigene nachrichten brauchst du doch aich nicht. Die Datenstruktur für WM_COPYDATA bietet dir ein frei verwendbares Integer-Feld. Dieses kannst du nutzen, um die enthaltenen daten zu unterscheiden:

http://msdn.microsoft.com/en-us/library/ms649010(VS.85).aspx
-> dwData
Specifies data to be passed to the receiving application.

Delphi-Quellcode:
case dwData of
0: ; // mach dies mit den Daten
1: ; // mach jenes mit den Daten
end;

lbccaleb 17. Mai 2009 16:08

Re: Text (Pfadangabe) per Windows Message verschicken
 
Hallo, ich habe iene möglichkeit gefunden wie ich es mit WM_COPYDATA machen kann, aber wie oben beschrieben war das nicht mein Hauptziel! Sondern es mit eigenen Messages hinzubekommen! Trotzdem danke :thumb:


Alle Zeitangaben in WEZ +1. Es ist jetzt 17:18 Uhr.

Powered by vBulletin® Copyright ©2000 - 2024, Jelsoft Enterprises Ltd.
LinkBacks Enabled by vBSEO © 2011, Crawlability, Inc.
Delphi-PRAXiS (c) 2002 - 2023 by Daniel R. Wolf, 2024 by Thomas Breitkreuz