title: Passing a string to an already running instance of an application
body: <p>I have an application that detects if there is another instance of the app running and exits if one is found. This part seems to work reliably. My app takes a command-line argument that I would like to pass to the already running instance. I have the following code so far:</p>
  
  <h2>Project1.dpr</h2>
  
  <pre><code>program Project1;
  
  uses
    ...
    AppInstanceControl in 'AppInstanceControl.pas';
  
    if not AppInstanceControl.RestoreIfRunning(Application.Handle) then
    begin
      Application.Initialize;
      Application.MainFormOnTaskbar := True;
      Application.CreateForm(TFormMain, FormMain);
      Application.Run;
    end;
  
  end.
  </code></pre>
  
  <h2>AppInstanceControl.pas</h2>
  
  <p>{ Based on code by Zarko Gajic found at <a href="http://delphi.about.com/library/code/ncaa100703a.htm" rel="noreferrer">http://delphi.about.com/library/code/ncaa100703a.htm</a>}</p>
  
  <pre><code>unit AppInstanceControl;
  
  interface
  
  uses
    Windows,
    SysUtils;
  
  function RestoreIfRunning(const AAppHandle: THandle; const AMaxInstances: integer = 1): boolean;
  
  implementation
  
  uses
    Messages;
  
  type
    PInstanceInfo = ^TInstanceInfo;
    TInstanceInfo = packed record
      PreviousHandle: THandle;
      RunCounter: integer;
    end;
  
  var
    UMappingHandle: THandle;
    UInstanceInfo: PInstanceInfo;
    UMappingName: string;
  
    URemoveMe: boolean = True;
  
  function RestoreIfRunning(const AAppHandle: THandle; const AMaxInstances: integer = 1): boolean;
  var
    LCopyDataStruct : TCopyDataStruct;
  begin
    Result := True;
  
    UMappingName := StringReplace(
                     ParamStr(0),
                     '\',
                     '',
                     [rfReplaceAll, rfIgnoreCase]);
  
    UMappingHandle := CreateFileMapping($FFFFFFFF,
                                       nil,
                                       PAGE_READWRITE,
                                       0,
                                       SizeOf(TInstanceInfo),
                                       PChar(UMappingName));
  
    if UMappingHandle = 0 then
      RaiseLastOSError
    else
    begin
      if GetLastError &lt;&gt; ERROR_ALREADY_EXISTS then
      begin
        UInstanceInfo := MapViewOfFile(UMappingHandle,
                                      FILE_MAP_ALL_ACCESS,
                                      0,
                                      0,
                                      SizeOf(TInstanceInfo));
  
        UInstanceInfo^.PreviousHandle := AAppHandle;
        UInstanceInfo^.RunCounter := 1;
  
        Result := False;
      end
      else //already runing
      begin
        UMappingHandle := OpenFileMapping(
                                  FILE_MAP_ALL_ACCESS, 
                                  False, 
                                  PChar(UMappingName));
        if UMappingHandle &lt;&gt; 0 then
        begin
          UInstanceInfo := MapViewOfFile(UMappingHandle,
                                        FILE_MAP_ALL_ACCESS,
                                        0,
                                        0,
                                        SizeOf(TInstanceInfo));
  
          if UInstanceInfo^.RunCounter &gt;= AMaxInstances then
          begin
            URemoveMe := False;
  
            if IsIconic(UInstanceInfo^.PreviousHandle) then
              ShowWindow(UInstanceInfo^.PreviousHandle, SW_RESTORE);
            SetForegroundWindow(UInstanceInfo^.PreviousHandle);
          end
          else
          begin
            UInstanceInfo^.PreviousHandle := AAppHandle;
            UInstanceInfo^.RunCounter := 1 + UInstanceInfo^.RunCounter;
  
            Result := False;
          end
        end;
      end;
    end;
    if (Result) and (CommandLineParam &lt;&gt; '') then
    begin
      LCopyDataStruct.dwData := 0; //string
      LCopyDataStruct.cbData := 1 + Length(CommandLineParam);
      LCopyDataStruct.lpData := PChar(CommandLineParam);
  
      SendMessage(UInstanceInfo^.PreviousHandle, WM_COPYDATA, Integer(AAppHandle), Integer(@LCopyDataStruct));
    end;
  end; (*RestoreIfRunning*)
  
  initialization
  
  finalization
    //remove this instance
    if URemoveMe then
    begin
      UMappingHandle := OpenFileMapping(
                          FILE_MAP_ALL_ACCESS, 
                          False, 
                          PChar(UMappingName));
      if UMappingHandle &lt;&gt; 0 then
      begin
        UInstanceInfo := MapViewOfFile(UMappingHandle,
                                    FILE_MAP_ALL_ACCESS,
                                    0,
                                    0,
                                    SizeOf(TInstanceInfo));
  
        UInstanceInfo^.RunCounter := -1 + UInstanceInfo^.RunCounter;
      end
      else
        RaiseLastOSError;
    end;
  
    if Assigned(UInstanceInfo) then UnmapViewOfFile(UInstanceInfo);
    if UMappingHandle &lt;&gt; 0 then CloseHandle(UMappingHandle);
  
  end.
  </code></pre>
  
  <h2>and in the main form unit:</h2>
  
  <pre><code>procedure TFormMain.WMCopyData(var Msg: TWMCopyData);
  var
    LMsgString: string;
  begin
    Assert(Msg.CopyDataStruct.dwData = 0);
    LMsgString := PChar(Msg.CopyDataStruct.lpData);
  
    //do stuff with the received string
  
  end;
  </code></pre>
  
  <p>I'm pretty sure the problem is that I'm trying to send the message to the handle of the running app instance but trying to process the message on the main form. I'm thinking I have two options here:</p>
  
  <p>A) From the application's handle somehow get the handle of its main form and send the message there.</p>
  
  <p>B) Handle receiving the message at the application rather than the main form level.</p>
  
  <p>I'm not really sure how to go about either. Is there a better approach?</p>
  
  <p>Thanks.</p>