"Fossies" - the Fresh Open Source Software Archive

Member "AutoHotkey_L-1.1.33.09/source/window.h" (8 May 2021, 17195 Bytes) of package /windows/misc/AutoHotkey_L-1.1.33.09.zip:


As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) C and C++ source code syntax highlighting (style: standard) with prefixed line numbers and code folding option. Alternatively you can here view or download the uninterpreted source code file. For more information about "window.h" see the Fossies "Dox" file reference documentation.

    1 /*
    2 AutoHotkey
    3 
    4 Copyright 2003-2009 Chris Mallett (support@autohotkey.com)
    5 
    6 This program is free software; you can redistribute it and/or
    7 modify it under the terms of the GNU General Public License
    8 as published by the Free Software Foundation; either version 2
    9 of the License, or (at your option) any later version.
   10 
   11 This program is distributed in the hope that it will be useful,
   12 but WITHOUT ANY WARRANTY; without even the implied warranty of
   13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   14 GNU General Public License for more details.
   15 */
   16 
   17 #ifndef window_h
   18 #define window_h
   19 
   20 #include "defines.h"
   21 #include "globaldata.h"
   22 #include "util.h" // for strlcpy()
   23 
   24 
   25 // Note: it is apparently possible for a hidden window to be the foreground
   26 // window (it just looks strange).  If DetectHiddenWindows is off, set
   27 // target_window to NULL if it's hidden.  Doing this prevents, for example,
   28 // WinClose() from closing the hidden foreground if it's some important hidden
   29 // window like the shell or the desktop:
   30 #define USE_FOREGROUND_WINDOW(title, text, exclude_title, exclude_text)\
   31     ((*title == 'A' || *title == 'a') && !*(title + 1) && !*text && !*exclude_title && !*exclude_text)
   32 #define SET_TARGET_TO_ALLOWABLE_FOREGROUND(detect_hidden_windows) \
   33 {\
   34     if (target_window = GetForegroundWindow())\
   35         if (!(detect_hidden_windows) && (!IsWindowVisible(target_window) || IsWindowCloaked(target_window)))\
   36             target_window = NULL;\
   37 }
   38 #define IF_USE_FOREGROUND_WINDOW(detect_hidden_windows, title, text, exclude_title, exclude_text)\
   39 if (USE_FOREGROUND_WINDOW(title, text, exclude_title, exclude_text))\
   40 {\
   41     SET_TARGET_TO_ALLOWABLE_FOREGROUND(detect_hidden_windows)\
   42 }
   43 
   44 
   45 
   46 inline bool IsTextMatch(LPTSTR aHaystack, LPTSTR aNeedle)
   47 // Generic helper function used by WindowSearch and other things.
   48 // To help performance, it's the caller's responsibility to ensure that all params are not NULL.
   49 {
   50     if (!*aNeedle) // The empty string is always found, regardless of mode.
   51         return true;
   52     switch(g->TitleMatchMode)
   53     {
   54     case FIND_ANYWHERE:        return _tcsstr(aHaystack, aNeedle);
   55     case FIND_REGEX:           return RegExMatch(aHaystack, aNeedle);
   56     case FIND_IN_LEADING_PART: return !_tcsncmp(aHaystack, aNeedle, _tcslen(aNeedle));
   57     default: // Otherwise: Exact match.
   58         return !_tcscmp(aHaystack, aNeedle); 
   59     }
   60 }
   61 
   62 
   63 
   64 #define SEARCH_PHRASE_SIZE 1024
   65 // Info from AutoIt3 source: GetWindowText fails under 95 if >65535, WM_GETTEXT randomly fails if > 32767.
   66 // My: And since 32767 is what AutoIt3 passes to the API functions as the size (not the length, i.e.
   67 // it can only store 32766 if room is left for the zero terminator) we'll use that for the size too.
   68 // Note: MSDN says (for functions like GetWindowText): "Specifies the maximum number of characters to
   69 // copy to the buffer, including the NULL character. If the text exceeds this limit, it is truncated."
   70 #define WINDOW_TEXT_SIZE 32767
   71 #define WINDOW_CLASS_SIZE 257  // MSDN implies length can't be greater than 256: "The maximum length for [WNDCLASS] lpszClassName is 256. If lpszClassName is greater than the maximum length, the RegisterClass function will fail."
   72 
   73 // Bitwise fields to support multiple criteria in v1.0.36.02
   74 #define CRITERION_TITLE 0x01
   75 #define CRITERION_ID    0x02
   76 #define CRITERION_PID   0x04
   77 #define CRITERION_CLASS 0x08
   78 #define CRITERION_GROUP 0x10
   79 #define CRITERION_PATH  0x20
   80 
   81 class WindowSearch
   82 {
   83     // One of the reasons for having this class is to avoid fetching PID, Class, and Window Text
   84     // when only the criteria have changed but not the candidate window.  This happens when called
   85     // from the WinGroup class.  Another reason is that it's probably more understandable than
   86     // the old way, while eliminating some redundant code as well.
   87 
   88 public:
   89     DWORD mCriteria; // Which criteria are currently in effect (ID, PID, Class, Title, etc.)
   90 
   91     // Controlled and initialized by SetCriteria():
   92     global_struct *mSettings;                 // Settings such as TitleMatchMode and DetectHiddenWindows.
   93     TCHAR mCriterionTitle[SEARCH_PHRASE_SIZE]; // For storing the title.
   94     TCHAR mCriterionClass[SEARCH_PHRASE_SIZE]; // For storing the "ahk_class" class name.
   95     size_t mCriterionTitleLength;             // Length of mCriterionTitle.
   96     LPTSTR mCriterionExcludeTitle;             // ExcludeTitle.
   97     size_t mCriterionExcludeTitleLength;      // Length of the above.
   98     LPTSTR mCriterionText;                     // WinText.
   99     LPTSTR mCriterionExcludeText;              // ExcludeText.
  100     HWND mCriterionHwnd;                      // For "ahk_id".
  101     DWORD mCriterionPID;                      // For "ahk_pid".
  102     WinGroup *mCriterionGroup;                // For "ahk_group".
  103     TCHAR mCriterionPath[SEARCH_PHRASE_SIZE]; // For "ahk_exe".
  104 
  105     bool mCriterionPathIsNameOnly;
  106     bool mFindLastMatch; // Whether to keep searching even after a match is found, so that last one is found.
  107     int mFoundCount;     // Accumulates how many matches have been found (either 0 or 1 unless mFindLastMatch==true).
  108     HWND mFoundParent;   // Must be separate from mCandidateParent because some callers don't have access to IsMatch()'s return value.
  109     HWND mFoundChild;    // Needed by EnumChildFind() to store its result, and other things.
  110 
  111     HWND *mAlreadyVisited;      // Array of HWNDs to exclude from consideration.
  112     int mAlreadyVisitedCount;   // Count of items in the above.
  113     WindowSpec *mFirstWinSpec;  // Linked list used by the WinGroup commands.
  114     ActionTypeType mActionType; // Used only by WinGroup::PerformShowWindow().
  115     int mTimeToWaitForClose;    // Same.
  116     Var *mArrayStart;           // Used by WinGetList() to fetch an array of matching HWNDs.
  117 
  118     // Controlled by the SetCandidate() method:
  119     HWND mCandidateParent;
  120     DWORD mCandidatePID;
  121     TCHAR mCandidateTitle[WINDOW_TEXT_SIZE];  // For storing title or class name of the given mCandidateParent.
  122     TCHAR mCandidateClass[WINDOW_CLASS_SIZE]; // Must not share mem with mCandidateTitle because even if ahk_class is in effect, ExcludeTitle can also be in effect.
  123     TCHAR mCandidatePath[MAX_PATH]; // MAX_PATH vs. T_MAX_PATH because it currently seems to be impossible to run an executable with a longer path (in Windows 10.0.16299).
  124 
  125 
  126     void SetCandidate(HWND aWnd) // Must be kept thread-safe since it may be called indirectly by the hook thread.
  127     {
  128         // For performance reasons, update the attributes only if the candidate window changed:
  129         if (mCandidateParent != aWnd)
  130         {
  131             mCandidateParent = aWnd;
  132             UpdateCandidateAttributes(); // In case mCandidateParent isn't NULL, update the PID/Class/etc. based on what was set above.
  133         }
  134     }
  135 
  136     ResultType SetCriteria(global_struct &aSettings, LPTSTR aTitle, LPTSTR aText, LPTSTR aExcludeTitle, LPTSTR aExcludeText);
  137     void UpdateCandidateAttributes();
  138     HWND IsMatch(bool aInvert = false);
  139 
  140     WindowSearch() // Constructor.
  141         // For performance and code size, only the most essential members are initialized.
  142         // The others do not require it or are initialized by SetCriteria() or SetCandidate().
  143         : mCriteria(0), mCriterionExcludeTitle(_T("")) // ExcludeTitle is referenced often, so should be initialized.
  144         , mFoundCount(0), mFoundParent(NULL) // Must be initialized here since none of the member functions is allowed to do it.
  145         , mFoundChild(NULL) // ControlExist() relies upon this.
  146         , mCandidateParent(NULL)
  147         // The following must be initialized because it's the object user's responsibility to override
  148         // them in those relatively rare cases when they need to be.  WinGroup::ActUponAll() and
  149         // WinGroup::Deactivate() (and probably other callers) rely on these attributes being retained
  150         // after they were overridden even upon multiple subsequent calls to SetCriteria():
  151         , mFindLastMatch(false), mAlreadyVisited(NULL), mAlreadyVisitedCount(0), mFirstWinSpec(NULL), mArrayStart(NULL)
  152     {
  153     }
  154 };
  155 
  156 
  157 
  158 struct control_list_type
  159 {
  160     // For something this simple, a macro is probably a lot less overhead that making this struct
  161     // non-POD and giving it a constructor:
  162     #define CL_INIT_CONTROL_LIST(cl) \
  163         cl.is_first_iteration = true;\
  164         cl.total_classes = 0;\
  165         cl.total_length = 0;\
  166         cl.buf_free_spot = cl.class_buf; // Points to the next available/writable place in the buf.
  167     bool fetch_hwnds;         // True if fetching HWND of each control rather than its ClassNN.
  168     bool is_first_iteration;  // Must be initialized to true by Enum's caller.
  169     int total_classes;        // Must be initialized to 0.
  170     VarSizeType total_length; // Must be initialized to 0.
  171     VarSizeType capacity;     // Must be initialized to size of the below buffer.
  172     LPTSTR target_buf;         // Caller sets it to NULL if only the total_length is to be retrieved.
  173     #define CL_CLASS_BUF_SIZE (32 * 1024) // Even if class names average 50 chars long, this supports 655 of them.
  174     TCHAR class_buf[CL_CLASS_BUF_SIZE];
  175     LPTSTR buf_free_spot;      // Must be initialized to point to the beginning of class_buf.
  176     #define CL_MAX_CLASSES 500  // The number of distinct class names that can be supported in a single window.
  177     LPTSTR class_name[CL_MAX_CLASSES]; // Array of distinct class names, stored consecutively in class_buf.
  178     int class_count[CL_MAX_CLASSES];  // The quantity found for each of the above classes.
  179 };
  180 
  181 struct MonitorInfoPackage // A simple struct to help with EnumDisplayMonitors().
  182 {
  183     int count;
  184     #define COUNT_ALL_MONITORS INT_MIN  // A special value that can be assigned to the below.
  185     int monitor_number_to_find;  // If this is left as zero, it will find the primary monitor by default.
  186     MONITORINFOEX monitor_info_ex;
  187 };
  188 
  189 struct pid_and_hwnd_type
  190 {
  191     DWORD pid;
  192     HWND hwnd;
  193 };
  194 
  195 struct length_and_buf_type
  196 {
  197     size_t total_length;
  198     size_t capacity;
  199     LPTSTR buf;
  200 };
  201 
  202 struct class_and_hwnd_type
  203 {
  204     LPTSTR class_name;
  205     bool is_found;
  206     int class_count;
  207     HWND hwnd;
  208 };
  209 
  210 struct point_and_hwnd_type
  211 {
  212     POINT pt;
  213     RECT rect_found;
  214     HWND hwnd_found;
  215     double distance;
  216     bool ignore_disabled_controls; // Used in EnumChildFindPoint for ControlClick; should normally be initialized to false.
  217 };
  218 
  219 
  220 HWND WinActivate(global_struct &aSettings, LPTSTR aTitle, LPTSTR aText, LPTSTR aExcludeTitle, LPTSTR aExcludeText
  221     , bool aFindLastMatch = false
  222     , HWND aAlreadyVisited[] = NULL, int aAlreadyVisitedCount = 0);
  223 HWND SetForegroundWindowEx(HWND aTargetWindow);
  224 
  225 // Defaulting to a non-zero wait-time solves a lot of script problems that would otherwise
  226 // require the user to specify the last param (or use WinWaitClose):
  227 #define DEFAULT_WINCLOSE_WAIT 20
  228 HWND WinClose(global_struct &aSettings, LPTSTR aTitle, LPTSTR aText, int aTimeToWaitForClose = DEFAULT_WINCLOSE_WAIT
  229     , LPTSTR aExcludeTitle = _T(""), LPTSTR aExcludeText = _T(""), bool aKillIfHung = false);
  230 HWND WinClose(HWND aWnd, int aTimeToWaitForClose = DEFAULT_WINCLOSE_WAIT, bool aKillIfHung = false);
  231 
  232 HWND WinActive(global_struct &aSettings, LPTSTR aTitle, LPTSTR aText, LPTSTR aExcludeTitle, LPTSTR aExcludeText
  233     , bool aUpdateLastUsed = false);
  234 
  235 HWND WinExist(global_struct &aSettings, LPTSTR aTitle, LPTSTR aText, LPTSTR aExcludeTitle, LPTSTR aExcludeText
  236     , bool aFindLastMatch = false, bool aUpdateLastUsed = false
  237     , HWND aAlreadyVisited[] = NULL, int aAlreadyVisitedCount = 0);
  238 
  239 HWND GetValidLastUsedWindow(global_struct &aSettings);
  240 
  241 BOOL CALLBACK EnumParentFind(HWND hwnd, LPARAM lParam);
  242 BOOL CALLBACK EnumChildFind(HWND hwnd, LPARAM lParam);
  243 
  244 
  245 // Use a fairly long default for aCheckInterval since the contents of this function's loops
  246 // might be somewhat high in overhead (especially SendMessageTimeout):
  247 #define SB_DEFAULT_CHECK_INTERVAL 50
  248 ResultType StatusBarUtil(Var *aOutputVar, HWND aBarHwnd, int aPartNumber = 1, LPTSTR aTextToWaitFor = _T("")
  249     , int aWaitTime = -1, int aCheckInterval = SB_DEFAULT_CHECK_INTERVAL);
  250 HWND ControlExist(HWND aParentWindow, LPTSTR aClassNameAndNum = NULL);
  251 BOOL CALLBACK EnumControlFind(HWND aWnd, LPARAM lParam);
  252 
  253 #define MSGBOX_NORMAL (MB_OK | MB_SETFOREGROUND)
  254 #define MSGBOX_TEXT_SIZE (1024 * 8)
  255 #define DIALOG_TITLE_SIZE 1024
  256 int MsgBox(int aValue);
  257 int MsgBox(LPCTSTR aText = _T(""), UINT uType = MSGBOX_NORMAL, LPTSTR aTitle = NULL, double aTimeout = 0, HWND aOwner = NULL);
  258 HWND FindOurTopDialog();
  259 BOOL CALLBACK EnumDialog(HWND hwnd, LPARAM lParam);
  260 
  261 HWND WindowOwnsOthers(HWND aWnd);
  262 BOOL CALLBACK EnumParentFindOwned(HWND aWnd, LPARAM lParam);
  263 HWND GetNonChildParent(HWND aWnd);
  264 HWND GetTopChild(HWND aParent);
  265 bool IsWindowHung(HWND aWnd);
  266 bool IsWindowCloaked(HWND aWnd);
  267 
  268 // Defaults to a low timeout because a window may have hundreds of controls, and if the window
  269 // is hung, each control might result in a delay of size aTimeout during an EnumWindows.
  270 // It shouldn't need much time anyway since the moment the call to SendMessageTimeout()
  271 // is made, our thread is suspended and the target thread's WindowProc called directly.
  272 // In addition:
  273 // Whenever using SendMessageTimeout(), our app will be unresponsive until
  274 // the call returns, since our message loop isn't running.  In addition,
  275 // if the keyboard or mouse hook is installed, the events will lag during
  276 // this call.  So keep the timeout value fairly short.  UPDATE: Need a longer
  277 // timeout because otherwise searching will be inconsistent / unreliable for the
  278 // slow Title Match method, since some apps are lazy about keeping their
  279 // message pumps running, such as during long disk I/O operations, and thus
  280 // may sometimes (randomly) take a long time to respond to the WM_GETTEXT message.
  281 // 5000 seems about the largest value that should ever be needed since this is what
  282 // Windows uses as the cutoff for determining if a window has become "unresponsive":
  283 int GetWindowTextTimeout(HWND aWnd, LPTSTR aBuf = NULL, INT_PTR aBufSize = 0, UINT aTimeout = 5000);
  284 void SetForegroundLockTimeout();
  285 
  286 
  287 // Notes about the below macro:
  288 // Update for v1.0.40.01:
  289 // In earlier versions, a critical thread that displayed a dialog would discard any pending events
  290 // that were waiting to start new threads (since in most cases, the dialog message pump would
  291 // route those events directly to a window proc, which would then repost them with a NULL hwnd
  292 // to prevent bouncing, which in turn would cause the dialog pump to discard them).  To avoid
  293 // this and make the behavior more useful and intuitive, this has been changed so that any
  294 // pending threads will launch right before the dialog is displayed.  But later, when the user
  295 // dismisses the dialog, the thread becomes critical again.
  296 // 
  297 // Update for v1.0.38.04: Rather than setting AllowInterruption unconditionally to
  298 // true, make it reflect the state of g->ThreadIsCritical.  This increases flexibility by allowing
  299 // threads to stay interrruptible even when they're displaying a dialog.  In such cases, an
  300 // incoming thread-event such as a hotkey will get routed to our MainWindowProc by the dialog's
  301 // message pump; and from there it will get reposted to our queue, and then get pumped again.
  302 // This bouncing effect may impact performance slightly but seems warranted to maintain
  303 // flexibility of the "Critical" command as well as its ability to buffer incoming events.
  304 //
  305 // If our thread's message queue has any message pending whose HWND member is NULL -- or even
  306 // normal messages which would be routed back to the thread by the WindowProc() -- clean them
  307 // out of the message queue before launching the dialog's message pump below.  That message pump
  308 // doesn't know how to properly handle such messages (it would either lose them or dispatch them
  309 // at times we don't want them dispatched).  But first ensure the current quasi-thread is
  310 // interruptible, since it's about to display a dialog so there little benefit (and a high cost)
  311 // to leaving it uninterruptible.  The "high cost" is that MsgSleep (our main message pump) would
  312 // filter out (leave queued) certain messages if the script were uninterruptible.  Then when it
  313 // returned, the dialog message pump below would start, and it would discard or misroute the
  314 // messages.
  315 // If this is not done, the following scenario would also be a problem:
  316 // A newly launched thread (in its period of uninterruptibility) displays a dialog.  As a consequence,
  317 // the dialog's message pump starts dispatching all messages.  If during this brief time (before the
  318 // thread becomes interruptible) a hotkey/hotstring/custom menu item/gui thread is dispatched to one
  319 // of our WindowProc's, and then posted to our thread via PostMessage(NULL,...), the item would be lost
  320 // because the dialog message pump discards messages that lack an HWND (since it doesn't know how to
  321 // dispatch them to a Window Proc).
  322 // GetQueueStatus() is used because unlike PeekMessage() or GetMessage(), it might not yield
  323 // our timeslice if the CPU is under heavy load, which would be good to improve performance here.
  324 #define DIALOG_PREP bool thread_was_critical = DialogPrep();
  325 // v1.0.40.01: Turning off critical during the dialog is relied upon by ResumeUnderlyingThread(),
  326 // UninterruptibleTimeout(), and KILL_AUTOEXEC_TIMER.  Doing it this way also seems more maintainable
  327 // than some other approach such as storing a new flag in the "g" struct that says whether it is currently
  328 // displaying a dialog and waiting for it to finish.
  329 #define DIALOG_END \
  330 {\
  331     g->ThreadIsCritical = thread_was_critical;\
  332     g->AllowThreadToBeInterrupted = !thread_was_critical;\
  333 }
  334 bool DialogPrep();
  335 
  336 #endif