Solved

Stop popup

Posted on 2000-03-27
21
367 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
 

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
Find Ransomware Secrets With All-Source Analysis

Ransomware has become a major concern for organizations; its prevalence has grown due to past successes achieved by threat actors. While each ransomware variant is different, we’ve seen some common tactics and trends used among the authors of the malware.

 

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 80 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

How your wiki can always stay up-to-date

Quip doubles as a “living” wiki and a project management tool that evolves with your organization. As you finish projects in Quip, the work remains, easily accessible to all team members, new and old.
- Increase transparency
- Onboard new hires faster
- Access from mobile/offline

Join & Write a Comment

Introduction I have seen many questions in this Delphi topic area where queries in threads are needed or suggested. I know bumped into a similar need. This article will address some of the concepts when dealing with a multithreaded delphi database…
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…
When you create an app prototype with Adobe XD, you can insert system screens -- sharing or Control Center, for example -- with just a few clicks. This video shows you how. You can take the full course on Experts Exchange at http://bit.ly/XDcourse.
This video demonstrates how to create an example email signature rule for a department in a company using CodeTwo Exchange Rules. The signature will be inserted beneath users' latest emails in conversations and will be displayed in users' Sent Items…

744 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

Need Help in Real-Time?

Connect with top rated Experts

13 Experts available now in Live!

Get 1:1 Help Now