Jump to content
Macro Express Forums

Help Me Understand Controls In Multiple Windows


Cory

Recommended Posts

Essentially: I want to create a macro that will file an Outlook 2003 mail message to file. I want to use the message date and subject in the file name. With a single mail message open it was simple to get the control text to do this. But with multiple windows I sometimes get blank values for the controls. How can I get this to work with multiple windows?

 

Long winded: I don’t understand something about windows controls. If you have calculator.exe open and interact with controls, even when minimized or not on top, it’s just like the demos but how do you deal with two instances of calculator open? In Outlook a user could have several editor/viewer windows open but when I run the “Get control” from two open windows I don’t see any difference.

 

<GETCONTROL2P:01:OUTLOOK.EXE:rctrl_renwnd32 Title1 - Message (HTML) 003:7 AfxWndW 1 #32770 5 RichEdit20WPT >

<GETCONTROL2P:01:OUTLOOK.EXE:rctrl_renwnd32 Title2 - Message (HTML) 003:7 AfxWndW 1 #32770 5 RichEdit20WPT >

 

Windows must know the difference, how do I?

 

Example: I opened a message and set up a control to grab the date. Works great. I open a second message and run the control and even if the new message is on top the macro returns the contents of the first window. Kind of makes sense. If I close the first message and run it again it returns a blank field. Now if I close the second message and open it again as the first window the macro will grab the control text fine. It’s almost like it IDs them one at a time as they are being opened and my get control it slaved to the first open window. But I don’t see anything different in the get control.

 

I was thinking of a workaround to ensure they only had one window open but even there I would have a problem. If the mail message wasn’t the first they opened it won’t work! <g>

 

If someone could explain what I am missing here I would greatly appreciate it. Also if you have any suggestions in general to do what I’m trying to do please bring it on.

Link to comment
Share on other sites

Window Controls can be very powerful but they have limitations.

 

Some programs define each Window Control statically. That is, every time a specific component is displayed the Window Control values are the same. This makes writing macros easier because you can use the Get Control command when you are writing your macro. However, as you have discovered, in some instances it can make the macro more difficult. If multiple instances of a program and/or window are displayed, the Window Control values are the same in multiple places.

 

The only thing I can think of is to use the Capture Control command to get the control values at runtime rather than design time. If your macro uses Capture Control to capture say, C1, for one instance and say, C2, for the second instance, the remainder of the macro should be able to keep track of each control (in C1 and/or C2). The reason for this is that once a Window Control is found and its information placed in a control variable, the handle is also saved. Each Window Control has a unique handle.

Link to comment
Share on other sites

Thanks for your prompt response but what a bummer. The main reason I use controls in cases like these is because things like mouse clicks often fail because the user has a different toolbar or whatever that changes location. Otherwise I could just triple-click the location and grab the text. In fact the date in an OL message is left justified so the location is different for each window width. Of course I could do some math but… I’ll have to come up with a different tack then. Maybe I’ll enforce one message only and check for null value. Hmmm….

 

I have an idea but I need to learn more from you o great sage. From my experiments I’ve gotten a vague idea of what might be happening but I’m not a programmer. It seems to me that the ‘address’, for lack of a better term, of the control is different in each window and that would make sense to me. But ME’s control details show the same. Is it the case that this is not actually the controls address? Maybe this is why you call the command “Get Control” as it almost seems like what is stored in the details is more like a pointer to help ME find the correct control address at runtime. And like an ant scent trail after you move the bag of sugar it now points nowhere if I closed the initial window. This is why it returns nothing. Is this what you are referring to as a ‘handle’?

 

I know this is above and beyond so if you don’t have the time I don’t expect a detailed dissertation and I know I can use other workarounds. It’s just that I really like controls for their ability to reduce run time timing errors and other problems. If I had a functional understanding of what’s happening behind the curtains I could come up with a routine to find the right window or something.

 

Last question: How come when I use the Variable Modify Control command to change the control’s window title does it still not work? I know if this was a solution you would have mentioned it but it’s another one of those things that stick out as being odd for probably the same reason.

 

I’m rereading your message about the handles. Where is this handle saved anyway? Could it be flushed? When does it get saved?

 

Many thanks as usual. Again this more of an aggravation thing where I don’t understand how something works and therefore how to fix it. Practically I should just change tack. If it were a microwave it would be in bits and pieces on my bench right now. Much cheaper to buy a new microwave but I’m stubborn that way. Hope you have a great day!

Link to comment
Share on other sites

Every window and every component, including window controls, are assigned a handle by Windows. A handle is numeric value that is assigned when the object is created. The handle will change every time it is created and this allows Windows to keep track of things. I do not know if the handle is the same thing as the object's address in memory. Perhaps some expert on Windows could answer that one. In practice, it doesn't matter.

 

A specific Window Control is assigned a different handle each time it appears. Therefore there is no way to know what the handle will be when the macro runs. What happens is Macro Express uses information that does not change such as the program, the form, and the class of the object to identify the Window Control. Once it identifies a Window Control it obtains the handle for that control and uses that internally from then on.

 

The problem is that the identifying information is the same for multiple instances of the same type of Window Control.

 

Windows assigns and manages 'handles'. An application can use handles but cannot, and should not, change, modify or destroy a handle. The application can destroy an object, such as a form, and when it is destroyed Windows will free up its handle.

 

Sometimes an application has a single object that is assigned a Window Control. But, as the application runs, it changes one of the identifying characteristics of that object. The best example is a button. The application may change the caption on the button from 'Cancel', to 'Continue', and then to 'Done'. This can be done without destroying and recreating the Window Control. And, by the way, in this example, the handle does not change.

 

You could write your macro to use three separate Control Variables. But in some cases it may be easier to use only one Control Variable and use the Variable Modify Control to change the identifying information that Control Variable is looking for. This does not change the Window Control. It changes the control variable that hopefully is pointing to the Window Control.

 

In our example application, the following macro would click on the button three times even though the caption changes.

// Get the control variable for a button that says 'Cancel'
Get Control %C1% (Capture Express: TButton)

// click on the button
Mouse Single Left Click on Control %C1%

// Change the window control to look at the button captioned 'Continue'
Variable Set Control Text %C1% to "Continue"
Mouse Single Left Click on Control %C1%

// Change the window control to look at the button captioned 'Done'
Variable Set Control Text %C1% to "Done"
Mouse Single Left Click on Control %C1%

This example assumes that the application is changing the caption on the button from 'Cancel' to 'Continue' and then to 'Done'.

Link to comment
Share on other sites

That is a very good explanation of handles and about what I thought. The example looks cool but in this case one of the controls is a date field which is always different. I’m still a little curious though about how ME handles, er, handles.

 

If I understand it the Get Control command’s title now makes sense. It doesn’t store the handle but rather points ME to where the handle can be found. Is this correct?

 

Now assuming my second paragraph is correct I don’t understand why ME can’t find the control’s handle sometimes. If I open message window A and fire the GC it sees the window and looks at the little index thingies and finds the handle for a date field. But if I open a second window B and close Window A I would expect ME would follow the yellow brink indexes and find the new control handle. But it doesn’t appear to. It’s almost if it’s remembering handle it got on the previous macro’s run. Is this possible? And if so is there a registry key or something I can flush?

 

I tried the modify control thingy to change the title window as well. The control properties look identical and now I set T1 to the top window title and use that to modify the get control but again it seems as if it’s remembering the first window. Again it seems like it’s remembering the first value and even though I’m explicitly telling it to ‘start here’ from a window title it pulling the first window.

 

I think I can figure a way around this if I could just understand why it is doing this. I’ll go experiment some more and see if I can learn more about handles in the mean time.

Link to comment
Share on other sites

Wahoo, I had a break thru! Ah it all seems so clear now. However I still have some residual issues.

 

It seemed that the controls were being got by different addresses and maybe OL was assigning new addresses for each window opened but I did a battery of test in the form of opening window A, run control macro. Open B, run control macro. Close B or A and run and eventually I saw a pattern. It’s ME that’s causing my pain! If you run a GC (Get Control) with multiple windows from the same app and a partial match (“message” in this case) which matches multiple windows it drills down and gets the control handle for that window. If you move to the second window and run it the dang thing still returns the value in the first window. What is happening is that ME is remembering the handle and isn’t doing the “Get” part of the command again. It’s cached somewhere. It could reside in there for weeks! To make along and boring story short I wrote a macro that does a GC and displays the control text to me. Then it restarts ME at the very end. Now with that macro I can move from any number of open windows to another in any order and run this macro and it always returns the value in the control of the top window!

 

I’ve been told that ME clears all it’s variables on each run but it’s apparent that this does not hold true for the control handles got by GC. It could be days later and ME will still be using the same handle. But kill ME and it flushes this cache and now GC gets the handle of the control in the top window. Why would they do this anyway?

 

Now for the practicalities. My solution of restarting ME is a pain. If the backups are enabled it prompts. Also if I wanted to loop I couldn’t. Not sure if I do yet but… I tried resetting hooks and preferences but that doesn’t hack it either. Is there some way to clear this cache w/o restarting ME every time the macro runs?

 

Maybe this is a bug?

Link to comment
Share on other sites

If two windows contain the same Window Control then there is no predicting which one Macro Express will find; it uses the one it finds first. Restarting Macro Express may seem to successfully cause the macro to find the correct Window Control but there is a 50/50 chance that it will find the incorrect one as well. There may be rules about which one Windows will list first, but we do not know what those rules are and cannot predict the outcome.

 

Further explanations would require disclosing proprietary information about the inner workings of Macro Express that do not belong in a public forum. I would be happy to have a private discussion with you about this.

Link to comment
Share on other sites

Finally solved. IMHO ME caches control handles and they are never cleared until ME is restarted. Also the “Clear Control Variables” does not work. I’ve tried a gazillion things and put about 6 hours into solving this multiple window problem and I finally found a solution. I tried setting the control window text to a variable and found that it does not work. At some point I tried using the Control Modify Window Title before but about 10% of the time it returned “Control not found” errors. Finally I was able to come up with a combination that appears to work reliably.

 

I first set a string variable T1 to the top window’s title. Then I do a “Get Control” with “ – Message” as a partial match. This could return the control for the top window but often returns the control that is cached thus the bane of my days here recently. You would think you could stuff T1 in there but you would be wrong. <g> Now I use the Variable Modify Control – Modify Top-Level Window Title and set it to T1 and Exact. Now when I Variable Get Control Text I reliably get the control text from the top window.

 

I’m still disappointed with the fact that the clear variables doesn’t do anything and that the ME caches control handles and doesn’t refresh them when one issues a GC command but I’ll save that for another day. I just wanted to post this fix for any future folks who might have the same problem.

Link to comment
Share on other sites

  • 1 year later...

thank you, Thank You, THANK YOU Cory!

 

This has been killing me! Every time I thought I had it... it failed the second time I ran the macro(s).

 

I was just grabbing the Top Level Window Name at the beginning (in to a variable), and then using that variable as the Top Level Window Caption for the GetControls. But doing the partial name and then adding in the 'Variable Modify Control: Modify Top-Level Window Title' after the GetControl and before I do anything with it works great!!!

 

I had the extra issue of the Controls actually changing depending on when you ran it and on what machine you ran it... but I figured that one out using "If NOT Enabled", so:

 

Get Control C1 (1)

If NOT Control C1 Enabled

Get Control C1 (2)

End If

 

Example using HP Service Desk:

 

<GETCONTROL2P:01:WJVIEW.EXE:WFC.Window.8- Default Work Order005:5WFC.Window.81WFC.Window.81WFC.Window.841WFC.Window.81WFC.EDIT>

<IFCONTROL:06:01>
<GETCONTROL2P:01:WJVIEW.EXE:WFC.Window.8- Default Work Order005:5WFC.Window.82WFC.Window.81WFC.Window.841WFC.Window.81WFC.EDIT>
<ENDIF>

 

Now I add in this at the end, and it works perfectly:

 

<VARMODCONT:3:5:2:%T1%>

 

This also seems to work great with various versions of applications or controls that change to multiple different control patterns. Which you can manually capture each time you run in to one, or what I like to do is capture a few to see the pattern, then you can just duplicate the IF statement and then go in to Direct Editor and change the control numbers to the pattern...

 

Variable Set String %T1% from Window Title

Get Control C1 (1)

If NOT Control C1 Enabled

Get Control C1 (2)

End If

If NOT Control C1 Enabled

Get Control C1 (3)

End If

If NOT Control C1 Enabled

Get Control C1 (etc...)

End If

Variable Modify Control (T1): Modify Top-Level Window Title

 

Thanks again Cory!! Awesome find!!!

Link to comment
Share on other sites

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.

Guest
Reply to this topic...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

Loading...
×
×
  • Create New...