views:

70

answers:

2

Hi, im trying to send a Windows message to my Delphi application, but im having problems with the FindWindow method: im getting error id of 0 from the GetLastError method. Im running Vista and from what ive read this error is common in XP or earlier versions, but should work fine in Vista or Win 7 (maybe i misunderstood ?).

This is the code im using and its in a Delphi DLL file, written in Delphi 5 :

procedure SendData(const copyDataStruct: TCopyDataStruct) ;
var
   receiverHandle : THandle;
   res : integer;
begin
   receiverHandle := FindWindow(PChar('TMainForm'),PChar('MainForm')) ;
   if receiverHandle = 0 then
   begin
   ShowMessage(format('Error %x finding MainForm',
    [GetLastError()]));
     Exit;
   end;

   res := SendMessage(receiverHandle, WM_COPYDATA, Integer(receiverHandle), Integer(@copyDataStruct)) ;
end;
+1  A: 

According to the system error codes list, error 0 means "ERROR_SUCCESS".

Could it be that your Window is of class TMainWindow, but has an empty Caption?

See the remarks for GetWindowText that is internally used by FindWindow when the lpWindowName parameter is non-null (which is the case: you pass MainWindow there).

--jeroen

Jeroen Pluimers
My window is a TForm, and its got a caption. So dont think that is the fault.
Roise
Found the error, i changed the caption of the form after startup så the second parameter in findWindow should not be MainForm :) Thanks for the help.
Roise
@Roise, that's one of the reasons I don't like `FindWindow`. It's sensitive to cosmetic UI changes.
Rob Kennedy
A better option would be to use SendMessage(HWND_BROADCAST, ...) to broadcast a custom message to all windows. Oly your window will know how to reply to it, and can reply with its current HWND value so the broadcaster does not have to hunt for it.
Remy Lebeau - TeamB
@Remy: I think that is a very good tip, worth posting as an answer.
Jeroen Pluimers
Im having some problems registering the message in my app, thought first it was the handle, but when i use HWND_BROADCAST i get a return value of 1 and my app should return 2006. Så not to shure about the HWND_BROADCAST.
Roise
@Roise - As there can be more than one application that can process the message, SendMessage cannot return what you have returned in your other application. Dammit.. I think I fail to explain, see [this](http://support.microsoft.com/kb/102588). BTW, do not use 'SendMessage' with 'HWND_BROADCAST', if there's any single one top-level window not processing messages, your application will *wait* for it, see [answer](http://stackoverflow.com/questions/1951658/sendmessagehwnd-broadcast-hangs/1956702#1956702) to *SendMessage(HWND_BROADCAST hangs*.
Sertac Akyuz
Use RegisterWindowMessage() to register a unique message ID. Also, like MSDN says, instead of having the target window return its HWND in reply to the SendMessage() broadcast directly (which the OS will discard), you will have to make your broadcasting app specify its own HWND as a parameter of the broadcasted message, and then the target window can send its HWND to the broadcasting HWND in a separate message.
Remy Lebeau - TeamB
A: 

Broadcast a custom message to all windows. Only your window will know how to react to it. It can then reply with its current HWND in another message so the broadcaster does not have to hunt for it manually. Use RegisterWindowMessage() to register unique message IDs that other apps will ignore. For example:

App 1:

var
  WM_WHERE_ARE_YOU: UINT = 0;
  WM_HERE_I_AM: UINT = 0;
  App2Wnd: HWND = 0;

procedure TApp1Form.FromCreate(Sender: TObject);
begin
  // use whatever string names you want, as long as they match App 2...
  WM_WHERE_ARE_YOU := RegisterWindowMessage("WhereAreYou");
  WM_HERE_I_AM := RegisterWindowMessage("HereIAm");
end;

procedure TApp1Form.WndProc(var Message: TMessage);
begin
  if (Message.Msg = WM_HERE_I_AM) and (WM_HERE_I_AM <> 0) then
    App2Wnd := HWND(Message.LParam)
  else
    inherited;
end;

procedure TApp1Form.SendData(const copyDataStruct: TCopyDataStruct);
var 
  res : integer; 

  procedure FindApp2Window;
  var
    Ignore: DWORD;
  begin
    App2Wnd := 0;
    if WM_WHERE_ARE_YOU = 0 then Exit;
    SendMessageTimeout(HWND_BROADCAST, WM_WHERE_ARE_YOU, 0, Longint(Self.Handle), SMTO_NORMAL, 500, Ignore);
    if App2Wnd = 0 then Application.ProcessMessages;
  end;

begin 
   FindApp2Window; 
   if App2Wnd = 0 then 
   begin 
     ShowMessage(Format('Unable to find MainForm');
     Exit; 
   end; 
   res := SendMessage(App2Wnd, WM_COPYDATA, Longint(Self.Handle), Longint(@copyDataStruct));
   ...
end;

App 2:

var
  WM_WHERE_ARE_YOU: UINT = 0;
  WM_HERE_I_AM: UINT = 0;

procedure TApp2Form.FromCreate(Sender: TObject);
begin
  // use whatever string names you want, as long as they match App 1...
  WM_WHERE_ARE_YOU := RegisterWindowMessage("WhereAreYou");
  WM_HERE_I_AM := RegisterWindowMessage("HereIAm");
end;

procedure TApp2Form.WndProc(var Message: TMessage);
begin
  case Message.Msg of
    WM_COPYDATA:
    begin
      if PCopyDataStruct(Message.LParam)^.dwData = ... then
      begin
        ...
        Message.Result := 1;
        Exit;
      end;
    end;
    ...
  else
    if (Message.Msg = WM_WHERE_ARE_YOU) and (WM_WHERE_ARE_YOU <> 0) then
    begin
      if WM_HERE_I_AM <> 0 then
        PostMessage(HWND(Message.LParam), WM_HERE_I_AM, 0, Longint(Self.Handle));
      Exit;
    end;
  end;

  inherited;
end;
Remy Lebeau - TeamB