We help IT Professionals succeed at work.

ShellExecute SW_HIDE

skynergy
skynergy asked
on
When using ShellExecute SW_HIDE, how do you get the handle to un-hide the application using ShowWindow?
Comment
Watch Question

Commented:
Hello skynergy,
Try this bro:

ShowWindow(Application.Handle, SW_HIDE);

Open in new window

Geert GOracle dba
Top Expert 2009

Commented:
that looks like a typo
Top Expert 2010

Commented:
You can un-hide it only if you know its main window class or/and its main window caption. Like this:

procedure Unhide;
var
  Handle: THandle;
begin
  Handle:= FindWindow( 'Its main window class name', 'Its main window caption');
  if Handle <> 0 then
    ShowWindow(Handle, SW_SHOW)
  else
    ShowMessage('Window is not found');
end;

Author

Commented:
Hi Aflarin, thanks for the reply. That is basically my main question: how do I find the Main Window Class Name to get it's handle so that I can unhide it?

I know how do use ShellExecute and ShowWindow. But getting the handle to for the ShowWindow is what I don't know how to do.

When you use ShellExecute it doesn't return the handle to the window it just executed, if so it would have been easy to unhide it with ShowWindow.

Does anybody know how this can be done?

Thanks for all the feedback guys!
Eddie ShipmanAll-around developer

Commented:
It is better to use CreateProcess, CreateProcess() returns both the ID and THandle of the new process.
Eddie ShipmanAll-around developer

Commented:
This code is from Andrew Jamison:
function LaunchApplication(AppName : string; aXPos, aYPos, aWidth, aHeight :
integer; aClassName, aTitle : string) : THandle;
var
  StartupInfo : TStartupInfo;
  ProcessInfo : TProcessInformation;
begin
  FillChar(StartupInfo, SizeOf(TStartupInfo), #0); // Get
ready to create a process thread
  StartupInfo.cb := SizeOf(TStartupInfo); // that
will execute this application.
  StartupInfo.dwFlags := STARTF_USESHOWWINDOW;
  StartupInfo.wShowWindow := SW_SHOW;

  if CreateProcess(nil,
                   PChar(AppName),
                   nil,
                   nil,
                   false,
                   NORMAL_PRIORITY_CLASS,
                   nil,
                   nil,
                   StartupInfo,
                   ProcessInfo) then begin

    WaitForInputIdle(ProcessInfo.hProcess, INFINITE); // Wait
around for the application to start.
    CloseHandle(ProcessInfo.hThread); // Close
handles.
    CloseHandle(ProcessInfo.hProcess);
    Result := FindWindow(aClassName, aTitle);
    if (Result <> 0) then
      SetWindowPos(fAppHandle, 0, aXPos, aYPos, aWidth, aHeight,
SWP_NOACTIVATE);
  end; {if}
end; {LaunchApplication}

It returns the handle of the window launched so you can change it's Show later....
hint: add another parameter and replace SWP_NOACTIVATE to send it the SW_HIDE when it starts.

Author

Commented:
Thanks for the reply Eddie.

When I try to compile I get the following error:
Incompatible types: 'String' and 'PAnsiChar'
on this line of code:
Result := FindWindow(aClassName, aTitle);  

How do I fix this?

Author

Commented:
I fixed the error with:
Result := FindWindow(pChar(aClassName), pChar(aTitle));

Now that it is working, I call this function with the following parameters:
hwnd := LaunchApplication('c:\WINDOWS\notepad.exe', 0, 0, 100, 100, 'notepad.exe', 'Notepad');

But the function returns a 0 as the handle. Are my parameters correct?

I know the Title should be Notepad but what should the ClassName be?
All-around developer
Commented:
The classname for notepad is not notepad.exe...
However, here's something you might be interested in. Peter below to the rescue again...



unit Unit1;

interface

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

type
  TForm1 = class(TForm)
    Button1: TButton;
    procedure Button1Click(Sender: TObject);
  private
    { Private declarations }
  public
    { Public declarations }
  end;

var
  Form1: TForm1;

implementation

{$R *.dfm}

type
  TEnumData = record
    hW: HWND;
    pID: DWORD;
  end;

function EnumProc( hw: HWND; var data: TEnumData ): Bool; stdcall;
var
  pID: DWORD;
begin
  Result := True;
  if (GetWindowLong(hw, GWL_HWNDPARENT) = 0) and
     (IsWindowVisible( hw ) or IsIconic(hw)) then
  begin
    GetWindowThreadProcessID( hw, @pID );
    If pID = data.pID then
    begin
      data.hW := hW;
      Result := False;
    end; { If }
  end; { If }
end; { EnumProc }

function WindowFromProcessID( pID: DWORD ): HWND;
var
  data: TEnumData;
begin
  data.pID := pID;
  data.hW := 0;
  EnumWindows( @EnumProc, longint(@data) );
  Result := data.hW;
end; { WindowFromProcessID }

function WindowFromAppname32( appname: String ): HWND;
  { Take only the application filename, not full path!
    Need to pass the extension as well. }
var
  snapshot: THandle;
  processEntry : TProcessEntry32;
begin
  Result := 0;
  appName := UpperCase( appname );
  snapshot := CreateToolhelp32Snapshot(
                TH32CS_SNAPPROCESS,
                0 );
  if snapshot <> 0 then
  try
    processEntry.dwSize := Sizeof( processEntry );
    if Process32First( snapshot, processEntry ) then
    repeat
      if AnsiCompareText(
           appname,
           ExtractFilename( StrPas(processEntry.szExeFile))
           ) = 0
      then
      begin
        Result:= WindowFromProcessID( processEntry.th32ProcessID);
        Break;
      end; { If }
    until not Process32Next( snapshot, processEntry );
  finally
    CloseHandle( snapshot );
  end; { try }
end; { WindowFromAppname32 }

procedure TForm1.Button1Click(Sender: TObject);
var
  x: THandle;
begin
  ShellExecute(0, 'open', 'c:\WINDOWS\notepad.exe','', '', SW_SHOW);
  x := WindowFromAppname32('NotePad.exe');
  ShowMessage(IntToStr(x));
end;

end.

Open in new window

Author

Commented:
Thanks for the help with this.

I tried the new code but the ShowMessage returns a 0. No handle found. This is when you change the ShellExecute with parameter SW_HIDE. Even SW_SHOW returns a 0.

Am I doing anything wrong?
Eddie ShipmanAll-around developer

Commented:
It worked for me. What OS do you have?

Author

Commented:
I tested that on my XP development PC in Delphi 7.
Eddie ShipmanAll-around developer

Commented:
Hmm, I'm running XP-SP3 and D7Ent and the code I posted works perfectly.
Eddie ShipmanAll-around developer

Commented:
Step through and tell me where it is going wrong. You should get the handle in line 43 (as shown above)

Oh, you might want to also comment out this stuff:
     (IsWindowVisible( hw ) or IsIconic(hw)) then

It would make you not get a handle if the window was already hidden or started with SW_HIDE.

Author

Commented:
I commented out (IsWindowVisible( hw ) or IsIconic(hw)) in line 43, also changed SW_SHOW to SW_HIDE in line 95. I took out all the breakpoints and it returned 0 again.

So I added a Sleep(1000) in the next line after the  ShellExecute command in line 95 to give Notepad a chance to load and then the ShowMessage successfully returned the handle.

Thank you so much for this Eddie. I really appreciated your help until this worked for me.