Jump to content
Macro Express Forums

acantor

Members
  • Posts

    1,521
  • Joined

  • Last visited

  • Days Won

    18

acantor last won the day on December 30 2023

acantor had the most liked content!

1 Follower

Contact Methods

  • Website URL
    www.cantoraccess.com
  • ICQ
    0

Profile Information

  • Location
    Toronto

Recent Profile Visitors

1,144 profile views

acantor's Achievements

  1. I tried running a global macro in MMC, and I tried creating a window-specific macro for MMC, as well. Neither script did anything! Perhaps try running Macro Express in Administrative mode?
  2. There's another option to improve the legibility of screen fonts: reduce the screen resolution. The Windows default resolution might work perfectly for a 20-year-old with 20:20 vision using a very large monitor. But I can almost guarantee it's not a good set-up for a middle-aged person working on a laptop.
  3. Here's another possibility: When running a macro, if there's an unrecoverable error, Macro Express displays a dialog box that looks something like this: The last line shows the line number. Press Ctrl + C when this dialog box has focus. This hotkey will copy the text to the clipboard. Create a new macro. Choose "Clipboard" as its activation. Choose to activate when the clipboard "contains" unique text from the error message. A good choice is "Line Number:" but another option is "The following error was encountered:" This script should extract the line number, place the value in a variable, and display it. Variable Set String %Clip% from the clipboard contents Variable Set Integer %ClipLength% to the length of variable %Clip% Variable Set Integer %TargetPosition% to the position of "Line Number:" in %Clip% Variable Modify Integer: %TargetPosition% = %TargetPosition% + 13 Variable Modify Integer: %CharactersToCopy% = %ClipLength% - %TargetPosition% Variable Modify String: Copy part of text in %Clip% starting at %TargetPosition% and %CharactersToCopy% characters long to %LineNumber% Variable Modify String %LineNumber%: Trim Text Box Display: Line Number = %LineNumber% <VARIABLE SET STRING Option="\x02" Destination="%Clip%" NoEmbeddedVars="FALSE"/> <COMMENT/> <VARIABLE SET INTEGER Option="\x0D" Destination="%ClipLength%" Text_Variable="%Clip%"/> <VARIABLE SET INTEGER Option="\x0E" Destination="%TargetPosition%" Text_Variable="%Clip%" Text="Line Number:" Ignore_Case="FALSE"/> <VARIABLE MODIFY INTEGER Option="\x00" Destination="%TargetPosition%" Value1="%TargetPosition%" Value2="13"/> <VARIABLE MODIFY INTEGER Option="\x01" Destination="%CharactersToCopy%" Value1="%ClipLength%" Value2="%TargetPosition%"/> <VARIABLE MODIFY STRING Option="\x09" Destination="%LineNumber%" Variable="%Clip%" Start="%TargetPosition%" Count="%CharactersToCopy%" NoEmbeddedVars="FALSE"/> <VARIABLE MODIFY STRING Option="\x00" Destination="%LineNumber%"/> <COMMENT/> <TEXT BOX DISPLAY Title="Line Number = %LineNumber%" Content="{\\rtf1\\ansi\\ansicpg1252\\deff0\\deflang1033{\\fonttbl{\\f0\\fnil Tahoma;}}\r\n\\viewkind4\\uc1\\pard\\f0\\fs14 \r\n\\par }\r\n" Left="Center" Top="Center" Width="278" Height="200" Monitor="0" OnTop="TRUE" Keep_Focus="TRUE" Mode="\x00" Delay="0"/>
  4. I don't think it's possible to capture the line number in a variable. But perhaps dividing the script into sections might accomplish something similar: Variable Set From Misc: "Name of Current Macro" into %CurrentMacro% Variable Set Integer %Section% to 1 If Window "Macro Express Pro" is focused Text Box Display: Check %CurrentMacro% at Section %Section% End If // Do something Variable Modify Integer %Section%: Increment If Window "Macro Express Pro" is focused Text Box Display: Check %CurrentMacro% at Section %Section% End If // Do something Variable Modify Integer %Section%: Increment If Window "Macro Express Pro" is focused Text Box Display: Check %CurrentMacro% at Section %Section% End If // Do something Variable Modify Integer %Section%: Increment If Window "Macro Express Pro" is focused Text Box Display: Check %CurrentMacro% at Section %Section% End If
  5. Or this: Variable Set String %FourLeftArrows% to "<ARROW LEFT><ARROW LEFT><ARROW LEFT><ARROW LEFT>" Text Type (Simulate Keystrokes): %FourLeftArrows%
  6. Here's my version. // A simulation to calculate differences between a sum of exact and rounded values. // The script generates random integers 100 times higher than the actual range. // For example, if the range is 10 to 200, the script uses values 1,000 to 20,000. // By dividing the result by 100, we obtain a value with two decimal places. E.g., 12345 --> 123.45 Variable Restore: Restore All Variables // Run the simulation how many times? Variable Set String %NumberOfSimulations%: Prompt Variable Modify String %NumberOfSimulations%: Convert to Integer (%NumberOfSimulationsInt%) // How many random values do you want to generate? Variable Set String %NumberOfRandomPicks%: Prompt Variable Modify String %NumberOfRandomPicks%: Convert to Integer (%NumberOfRandomPicksInt%) // Get the range of values Variable Set String %InitialLowValueStr%: Prompt Variable Set String %InitialHighValueStr%: Prompt Variable Modify String %InitialLowValueStr%: Convert to Integer (%InitialLowValue%) Variable Modify String %InitialHighValueStr%: Convert to Integer (%InitialHighValue%) // Multiply by 100 so we can later divide by 100 to obtain a value with two digits after the decimal point. Variable Modify Integer: %LowValue% = %InitialLowValue% * 100 Variable Modify Integer: %HighValue% = %InitialHighValue% * 100 // Loop for each simulation Repeat Start (Repeat %NumberOfSimulationsInt% times) Variable Set Decimal %SumExactD% to 0 Variable Set Decimal %SumRoundD% to 0 // Loop the number of random values that will be summed. Repeat Start (Repeat %NumberOfRandomPicksInt% times) Variable Set Integer %x% to a random value between %LowValue% and %HighValue% Variable Modify Integer %x%: Convert to Decimal (%xD%) Variable Modify Decimal: %DollarsCentsExactD% = %xD% / 100 Variable Modify Decimal %DollarsCentsRoundD%: Copy Value (%DollarsCentsExactD%) Variable Modify Decimal: Round %DollarsCentsRoundD% to 0 decimal places Variable Modify Decimal: %SumExactD% = %SumExactD% + %DollarsCentsExactD% Variable Modify Decimal: %SumRoundD% = %SumRoundD% + %DollarsCentsRoundD% End Repeat Variable Modify Decimal: %DifferenceD% = %SumExactD% - %SumRoundD% Variable Modify Decimal: Round %DifferenceD% to 4 decimal places Variable Modify Decimal: %DifferencePercentD% = %DifferenceD% / %SumExactD% Variable Modify Decimal: %DifferencePercentD% = %DifferencePercentD% * 100 Variable Modify Decimal: Round %DifferencePercentD% to 4 decimal places Text Box Display: Results End Repeat Variable Save: Save All Variables <COMMENT Value="A simulation to calculate differences between a sum of exact and rounded values."/> <COMMENT Value="The script generates random integers 100 times higher than the actual range. "/> <COMMENT Value="For example, if the range is 10 to 200, the script uses values 1,000 to 20,000. "/> <COMMENT Value="By dividing the result by 100, we obtain a value with two decimal places. E.g., 12345 --> 123.45"/> <VARIABLE RESTORE Option="\x00"/> <COMMENT/> <COMMENT Value="Run the simulation how many times?"/> <VARIABLE SET STRING Option="\x01" Destination="%NumberOfSimulations%" Prompt="Run the simulation how many times?" Mask="FALSE" OnTop="TRUE" Left="Center" Top="Center" Monitor="0" Lines="\x00"/> <VARIABLE MODIFY STRING Option="\x04" Destination="%NumberOfSimulations%" Variable="%NumberOfSimulationsInt%"/> <COMMENT/> <COMMENT Value="How many random values do you want to generate?"/> <VARIABLE SET STRING Option="\x01" Destination="%NumberOfRandomPicks%" Prompt="How many random picks per simulation?" Mask="FALSE" OnTop="TRUE" Left="Center" Top="Center" Monitor="0" Lines="\x00"/> <VARIABLE MODIFY STRING Option="\x04" Destination="%NumberOfRandomPicks%" Variable="%NumberOfRandomPicksInt%"/> <COMMENT/> <COMMENT Value="Get the range of values"/> <VARIABLE SET STRING Option="\x01" Destination="%InitialLowValueStr%" Prompt="Lowest value to include: (Must be an integer!)" Mask="FALSE" OnTop="TRUE" Left="Center" Top="Center" Monitor="0" Lines="\x00"/> <VARIABLE SET STRING Option="\x01" Destination="%InitialHighValueStr%" Prompt="Highest value to include: (Must be an integer!)" Mask="FALSE" OnTop="TRUE" Left="Center" Top="Center" Monitor="0" Lines="\x00"/> <VARIABLE MODIFY STRING Option="\x04" Destination="%InitialLowValueStr%" Variable="%InitialLowValue%"/> <VARIABLE MODIFY STRING Option="\x04" Destination="%InitialHighValueStr%" Variable="%InitialHighValue%"/> <COMMENT/> <COMMENT Value="Multiply by 100 so we can later divide by 100 to obtain a value with two digits after the decimal point."/> <VARIABLE MODIFY INTEGER Option="\x02" Destination="%LowValue%" Value1="%InitialLowValue%" Value2="100"/> <VARIABLE MODIFY INTEGER Option="\x02" Destination="%HighValue%" Value1="%InitialHighValue%" Value2="100"/> <COMMENT/> <COMMENT Value="Loop for each simulation"/> <REPEAT START Start="1" Step="1" Count="%NumberOfSimulationsInt%" Save="TRUE" Variable="%Counter%"/> <VARIABLE SET DECIMAL Option="\x00" Destination="%SumExactD%" Value="0"/> <VARIABLE SET DECIMAL Option="\x00" Destination="%SumRoundD%" Value="0"/> <COMMENT/> <COMMENT Value="Loop the number of random values that will be summed."/> <REPEAT START Start="1" Step="1" Count="%NumberOfRandomPicksInt%" Save="FALSE"/> <VARIABLE SET INTEGER Option="\x05" Destination="%x%" Minimum="%LowValue%" Maximum="%HighValue%"/> <VARIABLE MODIFY INTEGER Option="\x05" Destination="%x%" Variable="%xD%"/> <COMMENT/> <VARIABLE MODIFY DECIMAL Option="\x03" Destination="%DollarsCentsExactD%" Value1="%xD%" Value2="100"/> <VARIABLE MODIFY DECIMAL Option="\x08" Destination="%DollarsCentsRoundD%" Variable="%DollarsCentsExactD%"/> <VARIABLE MODIFY DECIMAL Option="\x04" Destination="%DollarsCentsRoundD%" Places="0"/> <COMMENT/> <VARIABLE MODIFY DECIMAL Option="\x00" Destination="%SumExactD%" Value1="%SumExactD%" Value2="%DollarsCentsExactD%"/> <VARIABLE MODIFY DECIMAL Option="\x00" Destination="%SumRoundD%" Value1="%SumRoundD%" Value2="%DollarsCentsRoundD%"/> <COMMENT/> <END REPEAT/> <COMMENT/> <VARIABLE MODIFY DECIMAL Option="\x01" Destination="%DifferenceD%" Value1="%SumExactD%" Value2="%SumRoundD%"/> <VARIABLE MODIFY DECIMAL Option="\x04" Destination="%DifferenceD%" Places="4"/> <COMMENT/> <VARIABLE MODIFY DECIMAL Option="\x03" Destination="%DifferencePercentD%" Value1="%DifferenceD%" Value2="%SumExactD%"/> <VARIABLE MODIFY DECIMAL Option="\x02" Destination="%DifferencePercentD%" Value1="%DifferencePercentD%" Value2="100"/> <VARIABLE MODIFY DECIMAL Option="\x04" Destination="%DifferencePercentD%" Places="4"/> <COMMENT/> <TEXT BOX DISPLAY Title="Results" Content="{\\rtf1\\ansi\\ansicpg1252\\deff0\\deflang1033{\\fonttbl{\\f0\\fnil\\fcharset0 Courier;}}\r\n\\viewkind4\\uc1\\pard\\lang4105\\b\\f0\\fs48 Simulation: %Counter% of %NumberOfSimulationsInt% \r\n\\par Range: %InitialLowValue%.00 to %InitialHighValue%.00\r\n\\par Numbers to add: %NumberOfRandomPicksInt%\r\n\\par \r\n\\par Exact Sum = %SumExactD%\r\n\\par Rounded Sum = %SumRoundD%\r\n\\par \r\n\\par Difference = %DifferenceD%\r\n\\par Percentage = %DifferencePercentD%%\\lang1033 \r\n\\par }\r\n" Left="521" Top="64" Width="1391" Height="674" Monitor="0" OnTop="TRUE" Keep_Focus="TRUE" Mode="\x00" Delay="0"/> <END REPEAT/> <COMMENT/> <VARIABLE SAVE Option="\x00"/>
  7. Rberq, That's the same approach I settled on. But I took a circuitous route before I got there: 1. Choose a random integer for the dollars value, from the lower to the upper limit, e.g., 10 to 2000. 2. Choose a random integer for the cents value, 0 to 99. 3. Convert both values to string variables. 4. If Cents < 10, append a zero to the start, e.g., 8 --> 08. 5. Construct the result by putting together three strings: the Dollar value, a decimal point, and the cents value. 6. Convert the result to a decimal variable so it can be easily rounded, added, etc. It worked, but was a bit contrived! Your approach is better.
  8. Before I post a solution, here's the challenge within the challenge... which might be the most challenging part! In coding this simulation, we generate random values within a fixed range. For example, the low end of the range might be $10, and the upper end might be $199.99. So here is a list of all possible values: 10.00 10.01 ... 10.99 11.00 ... 199.98 199.99 The challenge within the challenge is that Macro Express generates random integers: Variable Set Integer %x% to a random value between 1 and 100 Given this limitation, how would you use Macro Express to generate random non-integers between 10.00 and 199.99, and with decimal values between 00 and 99? I came up with two solutions, one of which was messier than I was comfortable with. I'm curious how others might tackle this.
  9. Even if all 600 items were priced at x dollars and 99 cents, the rounding difference would be $6, or 1%. I've been experimenting to try to make the simulation more realistic. For example, my expenses that are less than $10 and more than $200 are outliers. So I changed the upper and lower range. I messed with the total number values. When I repeated the experiment with ten values instead of 100 or 1000, there was a difference, but not by much. Rberq, did you do the sums via a macro, or did you "cheat" by using a spreadsheet? 😏
  10. I’m preparing my tax return. What a slog. I needed a diversion. Thus, this challenge. During tax season, there’s one task I especially dislike: Gather receipts for expenses I’ve incurred during the past year, and add up the amounts I can claim as deductions. I’ve got hundreds of receipts. Sorting them and adding expenses takes me a couple of days. It’s pure tedium! Fortunately, an accountant I know suggested a way to ease this task. His idea cuts the time and effort in half: Round every number to the nearest dollar. For example, $44.44 becomes $44, and $500.50 becomes $501. This strategy reduces the number of keystrokes for each number by three: no decimal point and no cent values. Two keystrokes for “44” vs. five keystrokes for “44.44”. He assured me the difference is insignificant. The tax collectors won’t care if my sums are off by a couple of dollars. They’re more interested in identifying tax evaders and fraudsters than taxpayers who take little shortcuts! But I got curious. Is the difference REALLY only a couple of dollars? What is the true difference between a sum that consists of exact values, and a sum that consists of rounded values? The challenge: Write a simulation to help develop your intuition about the differences. Your script randomly chooses, say, 1000 values between, say, $1.00 and $2000.00, and sums them. Also, round and sum the values. Calculate the difference between the two sums expressed in dollars (or euros, pounds, rupees, shekels, or whatever!) and as a percentage. Run the macro many times to get a feel for the range of values. Not sure a challenge of creating a financial simulation will appeal to everybody. I found it instructive. By running the macro repeatedly, I discovered the difference between the sums of exact and rounded values is often less than a dollar -- and rarely more than five dollars. The percentage difference between the two values has never been more than 0.02%!
  11. There are many ways to accomplish this. Some methods are probably "smarter" than others, and it can be satisfying to write a clever macro. But if you can find a way to get the job done, any way at all, that's a good thing! If you can figure out sequences of keys to do what you want to do, you may discover you are most of the way to a macro solution. For example... 1. Select a column in Excel. [Ctrl+space] 2. Copy it. [Ctrl+c] 3. Switch to the form. [Alt+Tab... but the Macro Express "Window Activate" will be better] 4. Output cell values one at a time, and press Tab after outputting a value in a field. [Not sure how to do this... but maybe when you get to this stage, ask for help!]
  12. I've noticed quirks with the size and position of windows, but this isn't something new. I've seen it for years. I've wondered whether the behaviour might be related to the use of Macro Express to resize and reposition windows. Perhaps the methods Macro Express uses to resize and reposition are different from the methods Windows uses. But I don't really know. Information about the size and position of each window must be stored somewhere. (In the Registry, perhaps?) But under certain circumstances, I think the values for "Restore" and "Maximize" get confused. When this happens, I click on "Maximize" and "Restore" a few times. This seems to fix the problem, at least temporarily.
  13. rberq's two methods are the main techniques I use. Here's a script for a banking application that searches for a fly-out menu, opens the menu, and searches for an item that appears in the fly-out menu: // Automate the two steps to Transfer Funds Text Type (Simulate Keystrokes): <ESC> // Try to cancel a process that is already started Text Type (Simulate Keystrokes): <CONTROL>f // First, search for unique text in "the Pay and Transfer" link... Delay: 20 milliseconds Text Type (Simulate Keystrokes): Trans // Pay and Transfer Text Type (Simulate Keystrokes): <ESC> Delay: 20 milliseconds Text Type (Simulate Keystrokes): <ENTER> Delay: 1000 milliseconds // Need at least half a second for the fly-out menu to unfurl Text Type (Simulate Keystrokes): <CONTROL>f // Second, search for unique text in the "Transfer Funds" link... Delay: 20 milliseconds Text Type (Simulate Keystrokes): er fu // Transf_ER FU_nds Text Type (Simulate Keystrokes): <ESC> Delay: 20 milliseconds Text Type (Simulate Keystrokes): <ENTER> <COMMENT Value="Automate the two steps to Transfer Funds"/> <TEXT TYPE Action="0" Text="<ESC>" _COMMENT="Try to cancel a process that is already started"/> <COMMENT/> <TEXT TYPE Action="0" Text="<CONTROL>f" _COMMENT="First, search for unique text in \"the Pay and Transfer\" link..."/> <DELAY Flags="\x02" Time="20"/> <TEXT TYPE Action="0" Text="Trans" _COMMENT="Pay and Transfer"/> <TEXT TYPE Action="0" Text="<ESC>"/> <DELAY Flags="\x02" Time="20"/> <TEXT TYPE Action="0" Text="<ENTER>"/> <DELAY Flags="\x02" Time="1000" _COMMENT="Need at least half a second for the fly-out menu to unfurl"/> <COMMENT/> <TEXT TYPE Action="0" Text="<CONTROL>f" _COMMENT="Second, search for unique text in the \"Transfer Funds\" link..."/> <DELAY Flags="\x02" Time="20"/> <TEXT TYPE Action="0" Text="er fu" _COMMENT="Transf_ER FU_nds"/> <TEXT TYPE Action="0" Text="<ESC>"/> <DELAY Flags="\x02" Time="20"/> <TEXT TYPE Action="0" Text="<ENTER>"/> Another technique, much more complicated, is to search for a pixel colour under the mouse cursor, along a path, or both. This demonstration script, when run in the Macro Express Script Editor window, locates the "Activations" tab by its colour by searching diagonally, south-east, from position (10,10) relative to the window. Because the script is moving in intervals of the square root of 2 (less than two pixels at a timeI, it's very slow. But in "real" scripts, I check more aggressively. Instead of moving (1,1) pixels at a time, I might move (10,10) or even (100,100) pixels. Mouse Move: 10, 10 Relative to Current Window Variable Set Integer %WinWidth%: Set to the Current Window's Width Variable Set Integer %WinHeight%: Set to the Current Window's Height Extended Math %WinWidthSquared%=%WinWidth%^2 Extended Math %WinHeightSquared%=%WinHeight%^2 Variable Modify Integer: %WinDiagonalSquared% = %WinWidthSquared% + %WinHeightSquared% Extended Math %WinDiagonal%=%WinDiagonalSquared%^.5 Text Box Display: Values Variable Set Integer %Count% to 1 Repeat Until %Count% Is Greater Than or Equal To "%WinDiagonal%" Mouse Move: 1, 1 Relative to Last Position Delay: 10 milliseconds Get Pixel Color from Beneath the Mouse into %PixelColour% If Variable %PixelColour% Equals "16777215" Text Box Display: GOT IT! Macro Stop End If Variable Modify Integer %Count%: Increment End Repeat <MOUSE MOVE Option="\x02" X="10" Y="10" _PROMPT="0x000A"/> <COMMENT/> <VARIABLE SET INTEGER Option="\x0A" Destination="%WinWidth%"/> <VARIABLE SET INTEGER Option="\x0B" Destination="%WinHeight%"/> <COMMENT/> <EXTENDED MATH Option="\x07" Destination="%WinWidthSquared%" Value1="%WinWidth%" Value2="2"/> <EXTENDED MATH Option="\x07" Destination="%WinHeightSquared%" Value1="%WinHeight%" Value2="2"/> <COMMENT/> <VARIABLE MODIFY INTEGER Option="\x00" Destination="%WinDiagonalSquared%" Value1="%WinWidthSquared%" Value2="%WinHeightSquared%"/> <EXTENDED MATH Option="\x07" Destination="%WinDiagonal%" Value1="%WinDiagonalSquared%" Value2=".5"/> <TEXT BOX DISPLAY Title="Values" Content="{\\rtf1\\ansi\\ansicpg1252\\deff0\\deflang4105{\\fonttbl{\\f0\\fnil\\fcharset0 Tahoma;}{\\f1\\fnil Tahoma;}}\r\n\\viewkind4\\uc1\\pard\\f0\\fs16 w \\f1 %Win\\f0 Width\\f1 %\r\n\\par \\f0 h \\f1 %Win\\f0 Height\\f1 %\r\n\\par \\f0 w^2 \\f1 %Win\\f0 Width\\f1 Squared%\r\n\\par \\f0 h^2 \\f1 %Win\\f0 Height\\f1 Squared%\r\n\\par \\f0 d^2 \\f1 %WinDiagonalSquared%\r\n\\par \\f0 d \\f1 %WinDiagonal%\r\n\\par \r\n\\par }\r\n" Left="Center" Top="Center" Width="278" Height="200" Monitor="0" OnTop="FALSE" Keep_Focus="TRUE" Mode="\x00" Delay="0" _ENABLED="FALSE"/> <COMMENT/> <VARIABLE SET INTEGER Option="\x00" Destination="%Count%" Value="1"/> <REPEAT UNTIL Variable="%Count%" Condition="\x04" Value="%WinDiagonal%"/> <MOUSE MOVE Option="\x03" X="1" Y="1" _PROMPT="0x000A"/> <DELAY Flags="\x02" Time="10"/> <GET PIXEL COLOR Option="\x00" Rel_To_Screen="TRUE" Destination="%PixelColour%"/> <IF VARIABLE Variable="%PixelColour%" Condition="\x00" Value="16777215" IgnoreCase="FALSE"/> <TEXT BOX DISPLAY Title="GOT IT!" Content="{\\rtf1\\ansi\\ansicpg1252\\deff0\\deflang4105{\\fonttbl{\\f0\\fnil Tahoma;}}\r\n\\viewkind4\\uc1\\pard\\f0\\fs16 \r\n\\par }\r\n" Left="Center" Top="Center" Width="278" Height="200" Monitor="0" OnTop="FALSE" Keep_Focus="TRUE" Mode="\x00" Delay="0"/> <MACRO STOP/> <END IF/> <VARIABLE MODIFY INTEGER Option="\x07" Destination="%Count%"/> <END REPEAT/>
  14. The method to capture the Sender’s email address will be different for every email program. The method might even vary in different versions of the same program. The following script is for Outlook 2019. Note that this only works for email messages that have already been received, e.g., messages in the Inbox or other folders. The script wasn't designed for messages that you're in the process of writing. Although I found several solutions to extract the Sender’s email address from an email message in Outlook 2019, some solutions worked more reliably and/or faster than others. Here are approaches I abandoned : 1. Forward the message. Tab into the body field. Select the entire message and copy to the clipboard. Close the forwarded message. Assign the clipboard to a text variable. Parse the variable to identify the email address. Assign the email address to the clipboard. 2. Save the email message to a temporary text-only file. (In Outlook, F12 is the “Save As…” shortcut.) Read the file into a text variable. Delete the temporary file. Parse the variable to identify the email address. Assign the email address to the clipboard. 3. Open the "Properties" window for the email message. (In Outlook 2019, use this four-step key sequence: F10, h, o, p.) Navigate to the Internet Headers field. Copy the field to the clipboard. Close the Properties window. Assign the content of the field to a text variable. Parse the variable to identify the email address. Assign the email address to the clipboard. Here's the approach I ended up using: 1. Press Shift + Tab repeatedly to navigate backwards between the regions in the message. (This gives focus to every region, and then wraps around to the bottom of the message body.) 2. After each Shift + Tab, capture the control for the region and get its class. 3. Test if "ToolbarWindow32" is the control class... ...If yes, navigate to the field containing the Sender’s email address by pressing Shift + Tab once. ...If no, repeat from Step 1. 4. Select field that contains the Sender's email address. Copy, assign to a variable, and parse. Assign to clipboard. 5. If we began on the main Outlook UI, press Esc to close the message... ...Otherwise, press Shift + Tab 3 times to give focus to the message body. Press Home to go to the top of the message. The macro seems to be mostly reliable, but I’m still tinkering with the length of delays. If you try the macro and the macro fails, try making all of the delays a little longer. // Extract sender's email address from an Outlook message and assign to the clipboard. How it works: // 0. Note whether the main Outlook UI is open, or if a message is open... // ... If this is the main UI, open the focused message by pressing Enter. // 1. Press Shift + Tab repeatedly to navigate backwards between the regions in the email message. // (This method gives focus to every regionl, then wraps around to the bottom of the message body.) // 2. With each Shift + Tab, capture the control for the region, and get its class. // 3. Test if "ToolbarWindow32" is the focused control class... // ...If yes, press Shift + Tab to reach the field containing the Sender’s email address. // ...If no, repeat from Step 1. // 4. Select field with Sender's email. Copy, assign to variable, and parse. Assign to clipboard. // 5. If we began on the main Outlook UI, press Esc to close the message... // ...Otherwise, press Shift + Tab 3x to give focus to the message body, and press Home to go to the top. // Is this the main Outlook UI? If yes open the message and set a Boolean flag. If Window " - Outlook" is focused Text Type (Simulate Keystrokes): <ENTER> Delay: 100 milliseconds If Not Window "- Message (" is focused // Ensure a message is open. If not, signal an error and quit. MessageBox: Cannot capture Sender's address Macro Stop End If Variable Set Bool %IsMainOutlookUI% to "True" End If // Is this NOT a message that has already been received? If yes, Quit. If Not Window "- Message (" is focused MessageBox: Cannot capture Sender's address Macro Stop End If // Otherwise, proceed as though this is a valid message, with "- Message (" in the titlebar. Variable Set String %Class% to "Nothing" // Cycle backwards through interface regions by pressing Shift + Tab. Continue until we reach the toolbar. Repeat Until %Class% Equals "ToolbarWindow32" Text Type (Simulate Keystrokes): <SHIFT><TAB> Capture Control from Focused Control into %OutlookControl% Delay: 20 milliseconds // (May need to adjust several delays to improve reliability) Get Control Class from %OutlookControl% into %Class% Delay: 5 milliseconds End Repeat // Navigate backwards one more region. This is the field containing the Sender's email. Select and copy it. Text Type (Simulate Keystrokes): <SHIFT><TAB> Delay: 20 milliseconds Text Type (Simulate Keystrokes): <HOME><SHIFT><END> // Select the field Delay: 100 milliseconds // (50 ms occasionally fails) Clipboard Copy Variable Set String %Clip% from the clipboard contents // Parse content of field. If it contains a "<" then assume email address is between "<" and ">". If Variable %Clip% Does not Contain "<" Variable Set String %EmailAddress% to "%Clip%" Else Variable Set Integer %StartPos% to the position of "<" in %Clip% Variable Modify String: Delete part of text from %Clip% starting at 1 and %StartPos% characters long Variable Set Integer %EndPos% to the position of ">" in %Clip% Variable Modify Integer: %EndPos% = %EndPos% - 1 Variable Modify String: Copy part of text in %Clip% starting at 1 and %EndPos% characters long to %EmailAddress% End If Variable Modify String: Save %EmailAddress% to the clipboard // If we began in main Outlook UI, press Esc to return. Else, give focus to the body, and go to the top. If Variable %IsMainOutlookUI% Equals "True" Text Type (Simulate Keystrokes): <ESC> Else Repeat Start (Repeat 3 times) Text Type (Simulate Keystrokes): <SHIFT><TAB> Delay: 200 milliseconds End Repeat Text Type (Simulate Keystrokes): <HOME> End If // Briefly display the captured email address Text Box Display: Extracted Email Address Delay: 1000 milliseconds Text Box Close: Extracted Email Address <COMMENT Value="Extract sender's email address from an Outlook message and assign to the clipboard. How it works:" _BACK="0080FFFF"/> <COMMENT/> <COMMENT Value="0. Note whether the main Outlook UI is open, or if a message is open..." _BACK="0080FFFF"/> <COMMENT Value=" ... If this is the main UI, open the focused message by pressing Enter." _BACK="0080FFFF"/> <COMMENT Value="1. Press Shift + Tab repeatedly to navigate backwards between the regions in the email message." _BACK="0080FFFF"/> <COMMENT Value=" (This method gives focus to every regionl, then wraps around to the bottom of the message body.)" _BACK="0080FFFF"/> <COMMENT Value="2. With each Shift + Tab, capture the control for the region, and get its class. " _BACK="0080FFFF"/> <COMMENT Value="3. Test if \"ToolbarWindow32\" is the focused control class..." _BACK="0080FFFF"/> <COMMENT Value=" ...If yes, press Shift + Tab to reach the field containing the Sender’s email address." _BACK="0080FFFF"/> <COMMENT Value=" ...If no, repeat from Step 1." _BACK="0080FFFF"/> <COMMENT Value="4. Select field with Sender's email. Copy, assign to variable, and parse. Assign to clipboard. " _BACK="0080FFFF"/> <COMMENT Value="5. If we began on the main Outlook UI, press Esc to close the message..." _BACK="0080FFFF"/> <COMMENT Value=" ...Otherwise, press Shift + Tab 3x to give focus to the message body, and press Home to go to the top." _BACK="0080FFFF"/> <COMMENT/> <COMMENT Value="Is this the main Outlook UI? If yes open the message and set a Boolean flag." _BACK="0080FFFF"/> <IF WINDOW Option="\x00" Title=" - Outlook" Partial="TRUE" Wildcards="FALSE"/> <TEXT TYPE Action="0" Text="<ENTER>"/> <DELAY Flags="\x02" Time="100"/> <IF NOT WINDOW Option="\x00" Title="- Message (" Partial="TRUE" Wildcards="FALSE" _COMMENT="Ensure a message is open. If not, signal an error and quit."/> <MESSAGEBOX Caption="Cannot capture Sender's address" Message="This script captures the address from already received emails." Icon="4"/> <MACRO STOP/> <END IF/> <VARIABLE SET BOOL Destination="%IsMainOutlookUI%" Command="263" Value="TRUE"/> <END IF/> <COMMENT/> <COMMENT Value="Is this NOT a message that has already been received? If yes, Quit." _BACK="0080FFFF"/> <IF NOT WINDOW Option="\x00" Title="- Message (" Partial="TRUE" Wildcards="FALSE"/> <MESSAGEBOX Caption="Cannot capture Sender's address" Message="This script captures the address from already received emails." Icon="4"/> <MACRO STOP/> <END IF/> <COMMENT/> <COMMENT Value="Otherwise, proceed as though this is a valid message, with \"- Message (\" in the titlebar." _BACK="0080FFFF"/> <VARIABLE SET STRING Option="\x00" Destination="%Class%" Value="Nothing" NoEmbeddedVars="FALSE"/> <COMMENT/> <COMMENT Value="Cycle backwards through interface regions by pressing Shift + Tab. Continue until we reach the toolbar." _BACK="0080FFFF"/> <REPEAT UNTIL Variable="%Class%" Condition="\x00" Value="ToolbarWindow32"/> <TEXT TYPE Action="0" Text="<SHIFT><TAB>"/> <CAPTURE CONTROL Option="\x01" Control="%OutlookControl%" UseText="FALSE"/> <DELAY Flags="\x02" Time="20" _COMMENT="(May need to adjust several delays to improve reliability)"/> <GET CONTROL CLASS TextVar="%Class%" ControlVar="%OutlookControl%"/> <DELAY Flags="\x02" Time="5" _ENABLED="FALSE"/> <END REPEAT/> <COMMENT/> <COMMENT Value="Navigate backwards one more region. This is the field containing the Sender's email. Select and copy it." _BACK="0080FFFF"/> <TEXT TYPE Action="0" Text="<SHIFT><TAB>"/> <DELAY Flags="\x02" Time="20"/> <TEXT TYPE Action="0" Text="<HOME><SHIFT><END>" _COMMENT="Select the field"/> <DELAY Flags="\x02" Time="100" _COMMENT="(50 ms occasionally fails)"/> <CLIPBOARD COPY/> <COMMENT/> <VARIABLE SET STRING Option="\x02" Destination="%Clip%" NoEmbeddedVars="FALSE"/> <COMMENT/> <COMMENT Value="Parse content of field. If it contains a \"<\" then assume email address is between \"<\" and \">\"." _BACK="0080FFFF"/> <IF VARIABLE Variable="%Clip%" Condition="\x07" Value="<" IgnoreCase="FALSE"/> <VARIABLE SET STRING Option="\x00" Destination="%EmailAddress%" Value="%Clip%" NoEmbeddedVars="FALSE"/> <ELSE/> <VARIABLE SET INTEGER Option="\x0E" Destination="%StartPos%" Text_Variable="%Clip%" Text="<" Ignore_Case="FALSE"/> <VARIABLE MODIFY STRING Option="\x0A" Destination="%Clip%" Start="1" Count="%StartPos%"/> <VARIABLE SET INTEGER Option="\x0E" Destination="%EndPos%" Text_Variable="%Clip%" Text=">" Ignore_Case="FALSE"/> <VARIABLE MODIFY INTEGER Option="\x01" Destination="%EndPos%" Value1="%EndPos%" Value2="1"/> <VARIABLE MODIFY STRING Option="\x09" Destination="%EmailAddress%" Variable="%Clip%" Start="1" Count="%EndPos%" NoEmbeddedVars="FALSE"/> <END IF/> <COMMENT/> <VARIABLE MODIFY STRING Option="\x10" Destination="%EmailAddress%" NoEmbeddedVars="FALSE"/> <COMMENT/> <COMMENT Value="If we began in main Outlook UI, press Esc to return. Else, give focus to the body, and go to the top." _BACK="0080FFFF"/> <IF VARIABLE Variable="%IsMainOutlookUI%" Condition="\x00" Value="True" IgnoreCase="FALSE"/> <TEXT TYPE Action="0" Text="<ESC>"/> <ELSE/> <REPEAT START Start="1" Step="1" Count="3" Save="FALSE"/> <TEXT TYPE Action="0" Text="<SHIFT><TAB>"/> <DELAY Flags="\x02" Time="200"/> <END REPEAT/> <TEXT TYPE Action="0" Text="<HOME>"/> <END IF/> <COMMENT/> <COMMENT Value="Briefly display the captured email address" _BACK="0080FFFF"/> <TEXT BOX DISPLAY Title="Extracted Email Address" Content="{\\rtf1\\ansi\\ansicpg1252\\deff0\\deflang1033{\\fonttbl{\\f0\\fnil\\fcharset0 Tahoma;}{\\f1\\fnil Tahoma;}}\r\n\\viewkind4\\uc1\\pard\\lang4105\\f0\\fs40 [%EmailAddress%]\\lang1033\\f1\\fs14 \r\n\\par }\r\n" Left="239" Top="116" Width="1577" Height="233" Monitor="0" OnTop="TRUE" Keep_Focus="TRUE" Mode="\x02" Delay="3"/> <DELAY Flags="\x02" Time="1000"/> <TEXT BOX CLOSE Header="Extracted Email Address"/>
  15. Hi Cory, Avoiding keyboard and mouse interactions with the Outlook user interface would be an advantage. I tried to implement your idea, but couldn't figure out how to create a rule to output a message to a text file. Please elaborate! Your idea did give me an idea for a second method to extract the sender's email address, but the method involves sending keystrokes to the user interface! (I was able to use Window Controls for parts of the script, but in the end, I got more consistent results when I sent keystrokes.)
×
×
  • Create New...