Home | Contact Us | FAQ | Search & Site Map | Link to Us
Sign In | Join | Other 45 Sites in Network
Home
Discussion GroupsVB SyntaxEnterprise DevelopmentDatabase AccessControlsCOMWin APICrystal ReportDeploymentGeneralGeneral 2
Related Topics
VB.NET / ASP.NETMS SQL ServerMS AccessOther Database ProductsMore Topics ...

VB Forum / Win API / April 2007



Tip: Looking for answers? Try searching our database.

Detect if dialog page is active and button enabled

Thread view: 
Enable EMail Alerts  Start New Thread
Thread rating: 
Greg Wilson - 27 Apr 2007 05:46 GMT
Background:

I have an elaborate Excel program I developed for work used for geotechnical
analysis and mass entry of test info. This was developed because of
limitations of our network-based program (*.exe) that does much the same. I
need to use the excel version for the field work and at regular intervals
dump the data into the *.exe version. I have successfully implemented a macro
that exports to the *.exe program using the VBA SendKeys method.

General Problem:

We have a big project coming up and others will need to use the program and
dump into the *.exe. Several preconditions must be set before exporting can
take place that cannot be established via SendKeys. And I don't trust the
people who will be using it. It needs to be bullet proof.

Required Preconditions:

1.  The *.exe program must already be open.
2.  A certain dialog created by the program must be open.
3.  As a minimum, a job number must be entered plus another selection.
4.  A certain page (tab) in the dialog must be selected (where you input the
data).
5.  A button on this page must not be grayed (must be enabled).
6.  The *.exe program must be the foreground window during the export.

Progress to Date:

-  I can successfully detect if the *.exe program is open using FindWindow.
-  If not, I enable a button that opens it using VBA's Shell function.
-  I can successfully detect if the dialog is open using EnumChildWindows.
-  I mandate that the user confirm preconditions 3, 4 and 5 using a series
of checkboxes. If they select all the checkboxes and the program and dialog
are open I allow the export.
-  I set the foreground window using SetForegroundWindow to ensure that
output (SendKeys) goes to the *.exe program's message queue.
-  During the export, I can detect if an error state occurs by regularly
comparing the foreground window caption with the program caption. I use
GetForeGroundWindow and GetWindowText. (If an error message pops up it
becomes the foreground window).

Request:

I don't like the checkbox scheme for confirming the other preconditions. I
would like to detect if the page is selected and preferably also if the
button is enabled. EnumChildWindows returns ALL child windows in the dialog
as far as I can tell. Even those that are made invisible by being on inactive
pages. So there's apparently no way I can detect if the page is selected.

Also, for some reason the key sequence that would select the particular page
(Ctrl + TAB multiple times) doesn't work when executed with SendKeys but
works manually. So I can't just activate it programmatically.

Hoping someone can provide some advice on resolving the above problem.
Improvements also much appreciated.

Greg
mr_unreliable - 27 Apr 2007 17:14 GMT
hi Greg,

Excuse my prejudice, but using appactivate and sendkeys is a
very risky way to control another program.  Unless you are
extremely careful, your keystrokes will go off into the ether,
or else land on some other app -- occasionally with bad
consequences.

Would it be possible to get the application vendor to provide
a normal input interface for you, such as just a simple input
file?  That would be the best solution by far.

If that is impossible, then rather than sendkeys I would suggest
sending messages to the specific windows.  For example, if you
wish to enter characters in a textbox (a.k.a. an edit control)
then you can do that by sending wm_char messages to the textbox
directly.  That way, you know where your characters are going.
When you use sendkeys, you characters could go anywhere.  Well,
not exactly -- they go to the window with the focus, but that
could change in an instant, depending on whatever else is going
on in your system.

All of your "requirements" can be met, by just sending system
messages -- provided that app you are talking about uses standard
"microsoft" windows.  I suggest getting a copy of Dan Appleman's
book "Visual Basic Programmer's Guide to the Win32 API".  Your
local public or college library may have a copy.  Appleman explains
all the messages for the "standard" controls.

However, Appleman doesn't talk about the tab control.  But it also
responds to system messages.  Your best bet for the tab control
is to read up on it in msdn.  Switching tabs does get tricky.
As I understand it, you can tell the tab control to change tabs
by sending a TCM_SETCURSEL message.  The "tricky part" is that
the tab control will change its tabs, but the other controls for
that page may not be shown.  You also have to notify the parent
window, by sending a WM_NOTIFY message (with appropriate parameters)
to the parent window.

cheers, jw

> Background:
>
[quoted text clipped - 53 lines]
>
> Greg
Greg Wilson - 28 Apr 2007 04:52 GMT
Thanks for responding.

I concur with your assessment of SendKeys. I only go this way when I have no
other option.

> Would it be possible to get the application vendor to provide
> a normal input interface for you, such as just a simple input
> file?  That would be the best solution by far.

The applicatioin vendor is an individual programmer who is too expensive,
takes too long to respond, and currently is tied up with another project. His
program is very specialized and there is almost no competition. My program
would also be seen as an insult since it resolves deficiencies with his. His
is part of a suite of products used by our firm that integrate with a client
data base that is core to our operation. Dispencing with it isn't really an
option.

I like your idea of sending messages to specific windows. I could send the
job number to the appropriate window. The button I mentioned that cannot be
grayed would then be enabled. This will solve this problem.

Questions:

1.  I assume I would get the handles for the various child windows and then
use SendMessage or PostMessage?
2.  If so, which function would you suggest I use to get the child window
handles?
3.  I imagine I would pass the window captions to this function to get the
handles?

I spent a lot of time just finding out how to determine if the dialog was
open. I ended up using EnumChildWindows. Dealing with child windows can be
surprisingly difficult. That's why I'm asking.

Greg

> hi Greg,
>
[quoted text clipped - 94 lines]
> >
> > Greg
mr_unreliable - 28 Apr 2007 15:11 GMT
> 1.  I assume I would get the handles for the various child windows and then
> use SendMessage or PostMessage?

Right.  You must first get the handles of the windows you wish
to manipulate.

> 2.  If so, which function would you suggest I use to get the child window
> handles?
> 3.  I imagine I would pass the window captions to this function to get the
> handles?

You seem to like enumChildWindows.  I prefer either:
  - FindWindowEx, where you give the handle of the parent, plus
      the class and caption of the child you want.
  - GetDlgItem, where you pass the handle of the parent, and the
      "ID" of the child to get the child handle.  The "ID" is an
      identifier of each child window, and is "usually" a unique
      way of identifying the child window -- although there are
      a few cases of "poorly programmed" apps with duplicate
      child window id's.

> I spent a lot of time just finding out how to determine if the dialog was
> open. I ended up using EnumChildWindows. Dealing with child windows can be
> surprisingly difficult. That's why I'm asking.

If you are going to "get serious" about sending messages to
windows and/or child windows, you can save yourself a lot of
trouble, if you find and use some sort of spy utility.  If you
have one of microsoft's compilers, you may have one installed
already.  If not, then there are a number of utilities out there
both for sale and for free that will do "spying".

Some utilities will make a listing of all windows, and provide
their handles, class and caption, and other information such as
location and size (rectangle), and window "ID".  Other utilities
have a "pointer" (some use a "gunsight" icon pointer), where you
move the pointer to the window and a "tool-tip-type" window pops
up, giving the info on that window.  Actually, if you have plenty
of time to spare, you could write your own (I did), but I am
assuming you want to get on with your project.

The Microsoft spy program is called spy++.  You can find other
spy programs at the various vb source code sites.  For starters,
try planet source code:

  http://www.planet-source-code.com/vb/default.asp

and enter "spy" in the search window.  You are looking for
"windows spy" apps, rather than the "api spy" apps which tend
to show the messages flowing into a window.

Also, I should mention that I prefer the "laundry list" type
which lists EVERY window (visible or not), as opposed to the
"pointer type" spy app, which isn't much good for windows which
happen to be hidden (such as those windows which are switched
on and off when you go from tab-to-tab).

cheers, jw
mr_unreliable - 28 Apr 2007 17:10 GMT
Winspector - Ultimate Programmers Window Spy Utility:

  http://www.windows-spy.com/

WinID is controls & windows identification utility:

  http://winid.wwwdennisbabkincom.alienpicks.com/

Window Handle Picker application is a "Spy"-like tool that
will display the window handle, id, caption, class, etc:

  http://www.codeguru.com/cpp/misc/samples/article.php/c1489/

and-so-on...

cheers, jw
Greg Wilson - 29 Apr 2007 06:30 GMT
Thanks again for your assistance.

> You seem to like enumChildWindows.  I prefer either:
>    - FindWindowEx, where you give the handle of the parent, plus
>        the class and caption of the child you want.

I ended up using EnumChildWindows by default because I couldn't get
FindWindowEx to work. I just managed to do so today. I had to use the ByVal
declaration for the 3rd and 4th args. Not sure yet why but I won't argue with
success.

I downloaded the WinSpector program and am just now trying it out. Looks
very interesting.

I plan to do as you suggest: Send the info directly to the target windows
instead of tabing to them. I think it should speed up execution as well as
reliability. My eventual target is to:
1.  Open the program (can do already).
2.  Open the dialog.
3.  Input the job number and make the other required selection.
4.  Select the correct page (tab).
5.  Then transfer all the data directly to the appropriate windows (edit
boxes).

The above will probably take awhile. I'm slow at this API stuff <sigh>.

Thanks again.

Greg
mr_unreliable - 30 Apr 2007 18:00 GMT
> I'm slow at this API stuff <sigh>.

Programming with api's can be tricky business,
and even the experts will "stub-their-toe"
occasionally.

As far as the "ByVal" parameters, if you get your
declarations from a reliable source, the "ByVal"
ought to be in the api definition, allowing the
compiler to take care of the calling arguments
for you.

You might start with the win32api.txt file from
Karl E. Peterson (albeit originally from microsoft),
look here:

  http://vb.mvps.org/tools/

(Very) generally speaking, api-call parameters tend
to need ByVal, whereas the default for vb is ByRef.

cheers, jw
 
Sign In
Join
My Latest Posts
My Monitored Threads
My Blog
My Photo Gallery
My Profile
My Homepage

Start New Thread
Enable EMail Alerts
Rate this Thread



©2009 Advenet LLC   Privacy Policy - Terms of Use
This website includes both content owned or controlled by Advenet as well as content owned or controlled by third parties.