Improve company productivity with a Business Account.Sign Up

x
  • Status: Solved
  • Priority: Medium
  • Security: Public
  • Views: 388
  • Last Modified:

Stop popup

How do you prevent a window coming up (ie. a popup in an external application). I'd use WM_CLOSE but this doesn't prevent a window from popping up but closes one when it does. I need a function that prevents the window even being loaded in the first place. ANY IDEAS?
0
frangers99
Asked:
frangers99
1 Solution
 
SuperSyCommented:
Are you saying that you have to override an external application's WM_CREATE?  
0
 
ahalyaCommented:
Well,  you cannot do much better than sending a "WM_Close", Unless if you are willing to write code to "trap" the CreateWindow calls and replace it with your own.

As far as I have seen trapping a Windows API and replacing it our own seems pretty formidable, (i consider it more like re-writing the OS :-), and at times appear impossible.  Madshi, and a few others have posted some comments/codes here in EE.  But that stuff appears too difficult to be practical.

So, the next best option is to set a SHELL_Hook, and monitor the creation of windows. As soon as a window is created, you can decide whether to allow it or close it using WM_CLOSE.


0
 
frangers99Author Commented:
ahalya,
your idea sounds excellent, but how do i create a hook to do this, and i need the program to work on WIndows NT. So any ideas?
Andrew.
0
Get your problem seen by more experts

Be seen. Boost your question’s priority for more expert views and faster solutions

 
KhachabCommented:
To make a hook to system calls you shall prepare a dll with functions to hook the system event you want Shell, Keyboard, Mouse  etc..
I think that this is not an easy thing to do, but you may use some free components that you may find on internet (TWatch component by Florian Bomers even if it is not a freeware but rather a postcard ware :)

You shall take a look at the SetWindowsHookEx API function.

I hope this will help.

Ibrahim Khachab
0
 
ahalyaCommented:
Andrew,

You have to create your EXE and a DLL (The HOOK function has to reside in a DLL).  The DLL shd be as follows

library YourDLL;

uses Windows, Messages;

const FormClass = 'TForm1';    //** Change these two
         FormTitle   = 'Title of Your Form'; // entries to point to your names.


function ShellProc(nCode: integer; wp: WPARAM; lp: LPARAM): LRESULT;stdcall;

begin
if (nCode = HSHELL_WindowCreated) then
   begin
   h := FindWindow(FormClass, FormTitle);
   if h <> 0 then PostMessage(h , wm_User+1, wp, nCode)
             else Messagebeep(0); {well, this shd never happen !}
   end;
Result := CallNextHookEx(0, nCode, wp, lp);
end;

exports ShellProc   index 1;
end.


//and in your main (EXE) project do the following:

//(1). Declare the following variables and message handler in your form's private section.

     LibHandle,
     ShellHookProc : THandle;
     HookProc  : function(nCode: integer; wp: WPARAM; lp: LPARAM): LRESULT; stdcall;

     procedure ShellMsg(var M:TMessage); message wm_User+1;

//(2)  Load the library and set the Hook in the FormCreate event

DLLName := ExtractFilePath(Application.ExeName) + YourDLL.DLL';
LibHandle := LoadLibrary(PChar(DLLName));
if LibHandle <> 0 then
  begin;
  @HookProc := GetProcAddress(LibHandle, 'ShellProc');
  if @HookProc <> nil then
     begin;
     ShellHookProc := SetWindowsHookEx(WH_SHELL, HookProc, LibHandle, 0);
     Result := true;
     end
     else MessageBox(0, 'Failed to install Hook Proc', 'Error', MB_OK+MB_IconWarning);

//(3) write the Message Handler procedure.

procedure TForm1.ShellMsg(var M:TMessage);

begin;  //close the window !!
 repeat
    SendMessage(M.wparam, wm_Close, 0,0);
    application.processmessages;
 until not IsWindow(M.wparam) or application.terminated;
end;


//(4) finally unload the DLL when you are done, from your FormDestroy event

if (LibHandle <> 0) and (ShellHookProc <> 0) then
    begin;
    Result := UnhookWindowsHookEx(ShellHookProc);
    ShellHookProc := 0;
    end
FreeLibrary(LibHandle);
0
 
frangers99Author Commented:
Thanks for the help i am actually looking for source so i will try alhayla solution ASAP.
0
 
frangers99Author Commented:
where to i specify the window name that i want to bar?
0
 
ahalyaCommented:
You'll have to do that in the message handler.   Check for the Window Title and close only if it matched. (You can check for Classname as well, if you know it)

//In Step (3) of my above code:
procedure TForm1.ShellMsg(var M:TMessage);

const WinCaption = 'caption of window to close';

var c : array[0..255] of char;

begin;  //close the window !!
GetWindowText(M.wparam, @c, 255);
if lowercase(string(c)) = WinCaption then
   begin;
   repeat
       SendMessage(M.wparam, wm_Close, 0,0);
       application.processmessages;
   until not IsWindow(M.wparam) or application.terminated;
end;

btw, frangers99 this ain't an easy question :-)
0
 
frangers99Author Commented:
Adjusted points from 50 to 80
0
 
frangers99Author Commented:
I've upped the points a little and you got them.
0
 
frangers99Author Commented:
wait, i tried the source but i got a few problems, i'' try and work it out.
0
 
frangers99Author Commented:
the program seems to close itself straight away, is this right?
0
 
ahalyaCommented:
frangers99,

i'm not sure which "program" you're referring to. If it's the program window you're closing using the SendMessage then it is ok.

Our HookProc will get the "message" whenever the operating system creates a Window.  Once we get the message from the DLL we "Close" the newly created window.

Whether the new window gets displayed, or gets closed before getting a chance to be displayed will probably depend on the system resources, i'd think (speed & usage).  So it is possible for the window to be closed immediately.


BUT:
if your program that monitors the Window creations (the one that you wrote)  is closing then it is not right.  It doesn't have to.  make sure that you are using "SendMessage(M.wparam, wm_Close, 0,0)" in the message handler. if by accident you use "Handle" instead of M.wparam then you're closing your own window.

You can setup breakpoints in the code, and see where your program is getting the "Close" call.
 
0
 
ahalyaCommented:
you sure will have this right, but just in case:

make sure that your WinCaption variable points to the correct caption of the window to be closed, and NOT to the caption of your own window.
0
 
ptmcompCommented:
Windows dialogs (not delphi forms!) normally have all the classname. (#32767 or something like that - don't remember)
0
 
frangers99Author Commented:
it's still not working, and i've checked all that. Ummm...i'll keep trying.
0
 
ahalyaCommented:
these are few things to note in creating GlobalHooks.

(1):  Use FindWindow in the DLL to find your window.  (DLLs get different data segments in each instance, and therefore the variables are local to each instance. so you cannot pass a var easily)


(2): Set the caption of your EXE's mainform within the form create event. Do not set it in the object inspector. (in that case FindWindow may return the wrong handle)

(3): Make sure your program is getting the message. Put a BP in your EXE's messagehandler and check.

finally:
why don't  you  post your code. i'll take a look.
0
 
frangers99Author Commented:
The program source below, it's basically what you have put in past writings.
-------------------------------------
unit meshook;

interface

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

type
  TForm1 = class(TForm)
    Label1: TLabel;
    procedure ShellMsg(var M:TMessage); message wm_user+1;
    procedure FormCreate(Sender: TObject);
    procedure FormDestroy(Sender: TObject);
  private
    LibHandle,ShellHookProc : THandle;
    DLLName: string;
    HookProc : function(nCode:integer; wp: WPARAM; lp: LPARAM): LRESULT; stdcall;
  public
    result: boolean;
  end;

var
  Form1: TForm1;

implementation

{$R *.DFM}

procedure TForm1.FormCreate(Sender: TObject);
begin
  DLLName:= ExtractFilePath(Application.ExeName) + 'ss_hook.dll';
  LibHandle:= LoadLibrary(PChar(DLLName));
  if LibHandle <> 0 then
    begin
      @HookProc := GetProcAddress(LibHandle,'ShellProc');
      if @HookProc <> nil then
        begin
          ShellHookProc := SetWindowsHookEx(WH_SHELL,HookProc,LibHandle,0);
          Result:= true;
          end
          else MessageBox(0,'Failed to install ss_hook.dll','Error',MB_OK+MB_IconWarning);
      end;
end;

procedure TForm1.ShellMsg(var M:TMessage);
const Wincaption = 'Notepad';
var c :array [0..255] of char;
begin
  GetWindowText(M.wparam, @c, 255);
  if lowercase(string(c)) = WinCaption then
  begin
  repeat
    sendmessage(M.wparam,wm_close,0,0);
    application.ProcessMessages;
  until not IsWindow(M.wparam) or application.terminated;
  end;
end;

procedure TForm1.FormDestroy(Sender: TObject);
begin
  if (LibHandle <> 0) and (ShellHookProc <> 0) then
    begin
      Result:= UnhookWindowsHookEx(ShellHookProc);
      ShellHookProc:= 0;
    end;
  FreeLibrary(LibHandle);
end;

end.
0
 
frangers99Author Commented:
and the dll
---------------------------
library ss_hook;

uses
  Windows, Messages;

const
  Formclass = 'TForm1';
  FormTitle = 'Messenger Hook';

var
  h: integer;

function ShellProc(nCode:integer; wp: WPARAM; lp: LPARAM): LRESULT;stdcall;

begin
  if (nCode = HSHELL_WindowCreated) then
    begin
      h:= FindWindow(Formclass,Formtitle);
      if h <> 0 then Postmessage (h, wm_user+1, wp, nCode)
        else Messagebeep(0);
      end;
    Result:= CallNextHookEx(0,nCode,wp,lp);
end;

exports
ShellProc index 1;
end.
0
 
ahalyaCommented:
Frangers99:

There are a few "issues":

(1): i will make your message handler a private declaration. i.e., move this line into the private section of the class declaration:
procedure ShellMsg(var M:TMessage); message wm_user+1;


(2): The variable WinCaption is defined with a capital 'N' ('Notepad') and gets compared to the lowercase(windowtitle).  So change the definition of WinCaption as 'notepad'

(3): The main problem is that the Title of notepad is NOT 'notepad'. It is 'Untitled - Notepad' (when started).  So you should either do a partial check, or properly define the WinCaption variable.  The following will work:

//in your message handler
if pos(wincaption, lowercase(string(c))) <> 0 then
   repeat
    sendmessage(M.wparam,wm_close,0,0);
    application.ProcessMessages;
  until not IsWindow(M.wparam) or application.terminated;

(4): and finally set your programs window title within its formcreate event, just before loading the Hook DLL. (as in)

begin;
Caption := 'Messenger Hook';
DLLName:= ExtractFilePath(Application.ExeName) + 'ss_hook.dll';
//This will make sure that your run time form gets the message (instead of the design time form of delphi)

Your code should work when the above corrections are incorporated.

0
 
frangers99Author Commented:
ok, cool, it works, thanks a heap
0
Question has a verified solution.

Are you are experiencing a similar issue? Get a personalized answer when you ask a related question.

Have a better answer? Share it in a comment.

Join & Write a Comment

Featured Post

Free Tool: Path Explorer

An intuitive utility to help find the CSS path to UI elements on a webpage. These paths are used frequently in a variety of front-end development and QA automation tasks.

One of a set of tools we're offering as a way of saying thank you for being a part of the community.

Tackle projects and never again get stuck behind a technical roadblock.
Join Now