Tek-Tips is the largest IT community on the Internet today!

Members share and learn making Tek-Tips Forums the best source of peer-reviewed technical information on the Internet!

  • Congratulations strongm on being selected by the Tek-Tips community for having the most helpful posts in the forums last week. Way to Go!

Restore form given handle 1

Status
Not open for further replies.

bobbie100

Programmer
Aug 29, 2003
64
GB
I have the handle of another application's main form of a known type. I want to display that form in the foreground in the Default (Normal) condition. The current state of the form is either Minimized or Normal.

The best I have achieved is by using:
Code:
ShowWindow(FormHandle, SW_SHOWDEFAULT);
SetForegroundWindow(FormHandle);
The problem with this is that if the form starts in a minimised state it is displayed correctly, but the Minimize button does not seem to work.

I am not very good with the Win API. Can anybody help?

Bob

 
Unfortunately SW_RESTORE has the same effect!

Although the window is being displayed correctly, if you right click on the symbol in the task bar the Restore item is bold and Minimize is greyed out. It's as though windows hasn't realised the window is no longer minimized.

I am running Win XP if that matters. Any other ideas?
 
The reason could be that new foreground application doesn't receive a proper message from Windows thus it doesn't know that it's the active application.

You can try to send a WM_ACTIVATEAPP or WM_ACTIVATE message (which _should_ come from Windows).

Also you can try SetActiveWindow function instead of SetForeGroundWindow. Check the Win32API help for moree information about these. If you don't have the API reference yet the you can download it here:
 
SetActiveWindow doesn't do it and I'm not sure how to use WM_ACTIVATEAPP and WM_ACTIVATE (even after reading the Win32API help!).

Maybe it would be best if I showed a very simplified example of the problem. Open a new project and replace Project1 with the following and compile.
Code:
program Project1;

uses
  Windows, Forms,
  Unit1 in 'Unit1.pas' {Form1};

{$R *.res}

var
  PrevHandle: THandle;
begin
  PrevHandle := FindWindow('TForm1', nil);
  if PrevHandle = 0 then
  begin
    Application.Initialize;
    Application.CreateForm(TForm1, Form1);
    Application.Run;
  end
  else
  begin
    ShowWindow(PrevHandle, SW_RESTORE);
    SetForegroundWindow(PrevHandle);
  end;
end.
Run the executable and minimize Form1. Then run a second time. Form1 is displayed, but the minimize button does not work!

Bob
 
Ahh. So you want to check if a program is already running. If it's not then execute the program else just show it?

I have such code in my project all ready for you. Though it's a MDI application so it might function differently.

I'm currently at home but i'll post the code tomorrow morning when back at the office.
 
Searching more through other threads and looking more into the API seem to suggest IsIconic(PrevHandle) should return True when the window is minimized.

However, inserting
PrevIconic := IsIconic(PrevHandle);
before
ShowWindow(PrevHandle, SW_RESTORE);
in my earlier example returns False regardless of whether the first instance is minimized.

Bob
 
Ok. Here's the code that i'm using in my project. This works at least with an MDI application. This code goes to the project file like the code in your earlier post.

Code:
var
  Mutex: THandle;
  hwind:HWND;

{$R *.RES}
                       
begin
  Mutex := CreateMutex(nil, TRUE, 'APPNAME');

  if Mutex <> 0 then
  begin
    if GetLastError = ERROR_ALREADY_EXISTS then
    begin
      MessageBox(0, 'Instance of this application is already running. Activating first instance.',
                    'Application already running', mb_IconHand);
      CloseHandle(Mutex);
      hwind:=0;
      repeat
        hwind:=Windows.FindWindowEx(0,hwind,'TApplication','APPNAME');          
      until (hwind<>Application.Handle);

      if (hwind<>0) then
      begin
        { Found it, & show it }
        Windows.ShowWindow(hwind,SW_SHOWNORMAL);
        Windows.SetForegroundWindow(hwind);
      end;
      Halt;
    end
  end;
 
Many thanks Pikkunero for your help (I have given you a star for your efforts!). Obviously I should have been looking for the handle to TApplication rather than the main window.

I have now implemented the multiple instance checking with the Mutex check and using a single FindWindow of the form
FindWindow(TApplication, 'MyApplicationName');
rather than a FindWindowEx in a loop. I am assuming the FindWindow won't find the current instance because the
Application.Title := 'MyApplicationName';
statement is not executed before this point. Is this assumption correct?

I have tried running the first instance in one WinXP user and then switching to another user to run the second instance. The current checks DO NOT catch the presence of the first instance running in the first user. Is this the expected behaviour?

I have to admit that at this stage in the program development the registry settings are not yet initialised. Is this the reason?

If I need to achieve multiple instance blocking across multiple users on the same machine, how is this achieved? (I'm not sure I need it for my current program development, but I might need it in the future and it might be of interest to other people reading this thread).

-Bob
 
Forgot to mention a problem I encountered while implementing Pikkunero's code. At first the ShowWindow and SetForegroundWindow lines weren't doing anything. After much investigation found that the problem was because the program name and Application.Title were the same.

For example the ShowWindow DOES NOT work with:
Code:
program MyProgram
  ...
  hwind := FindWindow('TApplication', 'MyProgram');
  ShowWindow(hwind, SW_SHOWNORMAL); 
  ...
  Application.Title := 'MyProgram';
  ...
whereas the ShowWindow DOES work with:
Code:
program MyProgram
  ...
  hwind := FindWindow('TApplication', 'MyProgram is great');
  ShowWindow(hwind, SW_SHOWNORMAL); 
  ...
  Application.Title := 'MyProgram is great';
  ...
From now on I will be making sure my application titles are different from the program name!

Does anybody know why this was a problem?

-Bob
 
To the "different user" question. In windows there are user specific prosesses and system wide processes. Normal applications are usually user specific and i don't know if it is possible to prevent another user starting a new instance of an application. It propably isn't possible. It's just the way Windows works.

You can go around this problem with a different approach. Create a service with a user interface.

When you start your application, it checks if the service is running, if it's not, it starts the service. And when you close it, you don't close the service. Of course this would mean that all the functionality is in the service itself and the interface just controls the service. That way switching user will not result to multiple instances of your program... in a way. Of course there might be multiple instances of the user interface.

Note that there still may be a way to prevent another user starting a new instance of an application. I just don't know how. The service approach is propably not the nicest way to go around this problem so i would very much like to hear different solutions.

And now it occured to me that it should be quite easy... *sigh* Just create a registry value which will be checked every time your app starts. If there is a value indicating your program is already running then just terminate the new instance. Another way is to use a small text file which is saved to the Windows\system32 directory. There are of course user specific files but not in that directory. At least that i know of :)
 
Status
Not open for further replies.

Part and Inventory Search

Sponsor

Back
Top