Go Premium for a chance to win a PS4. Enter to Win

x
?
Solved

Stop popup

Posted on 2000-03-27
21
Medium Priority
?
384 Views
Last Modified: 2010-04-04
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
Comment
Question by:frangers99
21 Comments
 

Expert Comment

by:SuperSy
ID: 2662185
Are you saying that you have to override an external application's WM_CREATE?  
0
 
LVL 7

Expert Comment

by:ahalya
ID: 2662470
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
 

Author Comment

by:frangers99
ID: 2663016
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
Technology Partners: We Want Your Opinion!

We value your feedback.

Take our survey and automatically be enter to win anyone of the following:
Yeti Cooler, Amazon eGift Card, and Movie eGift Card!

 

Expert Comment

by:Khachab
ID: 2663305
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
 
LVL 7

Expert Comment

by:ahalya
ID: 2664659
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
 

Author Comment

by:frangers99
ID: 2667562
Thanks for the help i am actually looking for source so i will try alhayla solution ASAP.
0
 

Author Comment

by:frangers99
ID: 2667574
where to i specify the window name that i want to bar?
0
 
LVL 7

Expert Comment

by:ahalya
ID: 2668143
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
 

Author Comment

by:frangers99
ID: 2670992
Adjusted points from 50 to 80
0
 

Author Comment

by:frangers99
ID: 2670993
I've upped the points a little and you got them.
0
 

Author Comment

by:frangers99
ID: 2675521
wait, i tried the source but i got a few problems, i'' try and work it out.
0
 

Author Comment

by:frangers99
ID: 2679019
the program seems to close itself straight away, is this right?
0
 
LVL 7

Expert Comment

by:ahalya
ID: 2680698
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
 
LVL 7

Expert Comment

by:ahalya
ID: 2680708
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
 
LVL 10

Expert Comment

by:ptmcomp
ID: 2685551
Windows dialogs (not delphi forms!) normally have all the classname. (#32767 or something like that - don't remember)
0
 

Author Comment

by:frangers99
ID: 2695602
it's still not working, and i've checked all that. Ummm...i'll keep trying.
0
 
LVL 7

Expert Comment

by:ahalya
ID: 2695627
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
 

Author Comment

by:frangers99
ID: 2699047
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
 

Author Comment

by:frangers99
ID: 2699049
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
 
LVL 7

Accepted Solution

by:
ahalya earned 320 total points
ID: 2699116
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
 

Author Comment

by:frangers99
ID: 2699169
ok, cool, it works, thanks a heap
0

Featured Post

VIDEO: THE CONCERTO CLOUD FOR HEALTHCARE

Modern healthcare requires a modern cloud. View this brief video to understand how the Concerto Cloud for Healthcare can help your organization.

Question has a verified solution.

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

Hello everybody This Article will show you how to validate number with TEdit control, What's the TEdit control? TEdit is a standard Windows edit control on a form, it allows to user to write, read and copy/paste single line of text. Usua…
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…
This video shows how to quickly and easily deploy an email signature for all users in Office 365 and prevent it from being added to replies and forwards. (the resulting signature is applied on the server level in Exchange Online) The email signat…
Screencast - Getting to Know the Pipeline
Suggested Courses

916 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