Solved

Single Instance Netscape

Posted on 2002-05-12
16
225 Views
Last Modified: 2012-05-04
I have an application that I am creating that one of its functions is to keep open only 1 or 2 instances of Netscape or IE open.  Can some give me a code example to do this?  Or give me a way to count the number of open Netscape or IE browser windows, and close them, leaving only one open?  I hope this is a clear question.

Thanks!
0
Comment
Question by:aj85
  • 9
  • 7
16 Comments
 
LVL 17

Expert Comment

by:geobul
ID: 7005743
Hi,

The following code will close all IE windows except one when the button is pressed:
-----
unit Unit1;

interface

uses
  Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms,
  StdCtrls;

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

var
  Form1: TForm1;
  List: TStringList;

implementation

{$R *.DFM}

function EnumerateWindows(hWnd: HWND; lParam: LPARAM): BOOL; stdcall;
var
  buf: array [1..10] of char;
  cl: string;
begin
  Result := true;
  if GetClassName(hWnd, @buf, 10) <> 0 then begin
    cl := string(buf);
    if Trim(cl) = 'IEFrame' then List.Add(IntToStr(hWnd));
  end;
end;

procedure TForm1.Button1Click(Sender: TObject);
var
  i: integer;
begin
  List := TStringList.Create;
  try
    EnumWindows(@EnumerateWindows, 0);
    if List.Count > 1 then begin
      for i := 1 to List.Count - 1 do begin
        PostMessage(StrToInt(List[i]),WM_CLOSE,0,0);
      end;
    end;
  finally
    List.Free;
  end;
end;

end.
-----

IEFrame is the ClassName for IE windows. I don't know what is the name for Netscape. I will try to find it out and modify the code in a couple of hours.

Regards, Geo
0
 
LVL 17

Expert Comment

by:geobul
ID: 7005993
Hi,

This works (tested) with IE 5 and above and Netscape Communicator 4.51.
----
type
  TForm1 = class(TForm)
    Button1: TButton;
    procedure Button1Click(Sender: TObject);
  private
    { Private declarations }
  public
    { Public declarations }
  end;

var
  Form1: TForm1;
  List: TStringList;
  Instances: integer = 2; // number of instances to retain

implementation

{$R *.DFM}

function EnumerateWindows(hWnd: HWND; lParam: LPARAM): BOOL; stdcall;
var
 buf: array [1..10] of char;
 cl: string;
begin
 Result := true;
 if GetClassName(hWnd, @buf, 10) <> 0 then begin
   cl := string(buf);
   if (Trim(cl) = 'IEFrame') or (Copy(cl,1,4) = 'Afx:') then List.Add(IntToStr(hWnd));
 end;
end;

procedure TForm1.Button1Click(Sender: TObject);
var
 i: integer;
begin
 List := TStringList.Create;
 try
   EnumWindows(@EnumerateWindows, 0);
   if List.Count > Instances then begin
     for i := Instances to List.Count - 1 do begin
       PostMessage(StrToInt(List[i]),WM_CLOSE,0,0);
     end;
   end;
 finally
   List.Free;
 end;
end;

end.
-----
Regards, Geo
0
 

Author Comment

by:aj85
ID: 7006468
Ok, thanks, I will test this and get back to you shortly.

aj85
0
DevOps Toolchain Recommendations

Read this Gartner Research Note and discover how your IT organization can automate and optimize DevOps processes using a toolchain architecture.

 

Author Comment

by:aj85
ID: 7007475

Ok, it seems to work, however, it closes the current browser window that I have open.  I want the currently open browsers to not be effected.  Meaning when the user opens the third browser for example, I only want the new browser to be closed.  Not the ones that are already open.  How can this be done?

Thanks!
aj85
0
 
LVL 17

Expert Comment

by:geobul
ID: 7007808
This way: Getting creation times of the processes and sorting them in the StringList we receive a list of all browser windows, ordered by date/time.
---
type
  TForm1 = class(TForm)
    Button1: TButton;
    procedure Button1Click(Sender: TObject);
  private
    { Private declarations }
  public
    { Public declarations }
  end;

var
  Form1: TForm1;
  List: TStringList;
  Instances: integer = 1; // number of instances to retain

implementation

{$R *.DFM}

function EnumerateWindows(hWnd: HWND; lParam: LPARAM): BOOL; stdcall;
var
  buf: array [1..10] of char;
  cl: string;
  PID: DWORD;  // Process ID
  PH: THandle; // Process Handle
  CreationTime,ExitTime,KernelTime,UserTime: TFileTime;
  SysTimeStruct: TSystemTime;
  TheTime: TDateTime;
begin
  Result := true;
  if GetClassName(hWnd, @buf, 10) <> 0 then begin
    cl := string(buf);
    if (Copy(cl,1,7) = 'IEFrame') or (Copy(cl,1,4) = 'Afx:') then begin // IE or Netscape window
      GetWindowThreadProcessId(hWnd,@PID); // Get PID
      PH := OpenProcess(PROCESS_QUERY_INFORMATION, false, PID); // Get Process Handle
      try
        if PH <> 0 then begin
          GetProcessTimes(PH,CreationTime,ExitTime,KernelTime,UserTime); // Get Process Times
          if FileTimeToSystemTime(CreationTime, SysTimeStruct) then begin // Convert CreationTime to DateTime
            TheTime := SystemTimeToDateTime(SysTimeStruct);
            List.Add(FormatDateTime('yyyymmddhhnnss',TheTime)+' '+Format('%12d',[hWnd])); // Add to List
          end;
        end;
      finally
        CloseHandle(PH);
      end;
    end;
  end;
end;

procedure TForm1.Button1Click(Sender: TObject);
var
  i: integer;
begin
  List := TStringList.Create;
  try
    EnumWindows(@EnumerateWindows, 0); // Enumerate windows
    List.Sorted := true; // sort the list (last times at the bottom)
    if List.Count > Instances then begin
      for i := Instances to List.Count - 1 do begin
        PostMessage(StrToInt(Copy(List[i],16,12)),WM_CLOSE,0,0); // close windows
      end;
    end;
  finally
    List.Free;
  end;
end;

end.
---
Regards, Geo
0
 

Author Comment

by:aj85
ID: 7010103
This works great, except I now get an exception error "date encode".  Can you tell me how to correct this?  Other than that it appears to work fine.

Thanks again!
0
 
LVL 17

Accepted Solution

by:
geobul earned 325 total points
ID: 7010502
if PH <> 0 then begin
  try // >> new line
    GetProcessTimes(PH,CreationTime,ExitTime,KernelTime,UserTime); // Get Process Times
    if FileTimeToSystemTime(CreationTime, SysTimeStruct) then begin // Convert CreationTime to DateTime
      TheTime := SystemTimeToDateTime(SysTimeStruct);
      List.Add(FormatDateTime('yyyymmddhhnnss',TheTime)+' '+Format('%12d',[hWnd])); // Add to List
  except // >> 3 new lines
    // if an exception occurs - do nothing
  end;
end;

This should do it I think.

Regards, Geo
0
 

Author Comment

by:aj85
ID: 7010738
Thanks, I will try this and get back with you shortly.

aj85
0
 

Author Comment

by:aj85
ID: 7012607
Ok, that took care of that, I think, but now when I open a new browser serveral times in a row.  On the 4th or 5th time whether it is IE or Netscape, it closes my current browser window and lets the new open.  I hope I explained that clearly enough, but anyway, what do you think could be cause this?  It is as if the time gets lost or something and it assumes the new browser has a more current timestamp than the present one that is already opened.

Thanks again!

P.S. Because you have given me a great source code example to follow.  And have also given me clear comments to follow what is happening.  I have increase your points by 25 for your help.
0
 

Author Comment

by:aj85
ID: 7012842
Also, one other thing.  I am now getting this error: Exception class EconvertError with message "Invalid argument to time encode".  I am not sure what is causing this?  Can you assist with this as well.

Thanks again!
0
 
LVL 17

Expert Comment

by:geobul
ID: 7013138
I'm sorry that I misled you with all this processes stuff. I've found that:

1.IE: doesn't create new process when a new window is being opened using 'File-New-Window' main menu or 'Open in New Window' popup menu. It creates a new process when started using desktop icon / start-programs only.

2. Netscape always uses one process for all its windows.

So, the only real solution I could think of is:
1. Remember all browser window handles that should not be terminated (in a StringList)
2. repeatedly kill all other browser windows.

In the next example:
-pressing btnStore button will 'remember' all currently opened browsers in Instances list;
-pressing btnKill will close all the others.

And the code is:
---

type
  TForm1 = class(TForm)
    btnKill: TButton;
    btnStore: TButton;
    procedure btnKillClick(Sender: TObject);
    procedure btnStoreClick(Sender: TObject);
  private
    { Private declarations }
  public
    { Public declarations }
  end;

var
  Form1: TForm1;
  List: TStringList;
  Instances: TStringList;

implementation

{$R *.DFM}

function EnumerateWindows(hWnd: HWND; lParam: LPARAM): BOOL; stdcall;
var
  buf: array [1..10] of char;
  cl: string;
begin
  Result := true;
  if GetClassName(hWnd, @buf, 10) <> 0 then begin
    cl := string(buf);
    if (Copy(cl,1,7) = 'IEFrame') or (Copy(cl,1,4) = 'Afx:') then begin // IE or Netscape window
      TStringList(Ptr(lParam)).Add(Format('%12d',[hWnd])); // Add to List
    end;
  end;
end;

procedure TForm1.btnKillClick(Sender: TObject);
var
  i: integer;
begin
  List := TStringList.Create;
  try
    EnumWindows(@EnumerateWindows, Integer(List)); // Enumerate windows
    if List.Count > 0 then begin // if there are browsers found
      for i := 0 to List.Count - 1 do begin
        if Instances.IndexOf(List[i]) = -1 then begin // if the window hasn't been stored in Instances
          PostMessage(StrToInt(List[i]),WM_CLOSE,0,0); // close windows
        end;
      end;
    end;
  finally
    List.Free;
  end;
end;

procedure TForm1.btnStoreClick(Sender: TObject);
begin
  // Remember all currently opened browser windows in Instances list
  Instances.Clear;
  EnumWindows(@EnumerateWindows, Integer(Instances)); // using lParam as a pointer to a StringList
end;

initialization
  // create Instances list
  Instances := TStringList.Create;
  Instances.Sorted := true;

finalization
  // free Instances list
  if Instances <> nil then Instances.Free;

end.
---
Regards, Geo
0
 

Author Comment

by:aj85
ID: 7019263
Ok, I think that did it.  On another note, can you give me an example on clearing or killing the cookies for IE and Netscape?  If you can I will increase your points by 50.  I am not sure if this an easy thing to do or not.  Anyway, let me know if you are interested in the additional points.

Thanks,
aj85
0
 
LVL 17

Expert Comment

by:geobul
ID: 7020914
I'm afraid I can't help you in clearing cookies. Ask another 50 points question and someone else may have an answer how to do that.

Regards, Geo
0
 

Author Comment

by:aj85
ID: 7021215
No problem, here are your points.  And thanks for the clear answer.
0
 

Author Comment

by:aj85
ID: 7021217
Great answer!
0
 
LVL 17

Expert Comment

by:geobul
ID: 7021437
My pleasure. Thanks for the points.

Best regards, Geo
0

Featured Post

Master Your Team's Linux and Cloud Stack!

The average business loses $13.5M per year to ineffective training (per 1,000 employees). Keep ahead of the competition and combine in-person quality with online cost and flexibility by training with Linux Academy.

Question has a verified solution.

If you are experiencing a similar issue, please ask a related question

Suggested Solutions

Title # Comments Views Activity
ddeman not working in activex 3 103
Convert a string into a TDateTime 5 60
Installshield for Embarcadero EX 10.1 Berlin 4 40
MS Access from Delphi 31 28
Introduction Raise your hands if you were as upset with FireMonkey as I was when I discovered that there was no TListview.  I use TListView in almost all of my applications I've written, and I was not going to compromise by resorting to TStringGrid…
In my programming career I have only very rarely run into situations where operator overloading would be of any use in my work.  Normally those situations involved math with either overly large numbers (hundreds of thousands of digits or accuracy re…
Established in 1997, Technology Architects has become one of the most reputable technology solutions companies in the country. TA have been providing businesses with cost effective state-of-the-art solutions and unparalleled service that is designed…
With Secure Portal Encryption, the recipient is sent a link to their email address directing them to the email laundry delivery page. From there, the recipient will be required to enter a user name and password to enter the page. Once the recipient …

770 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question