"Fossies" - the Fresh Open Source Software Archive

Member "AutoHotkey_L-1.1.33.09/source/util.cpp" (8 May 2021, 135224 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 "util.cpp" 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 #include "stdafx.h" // pre-compiled headers
   18 #include <olectl.h> // for OleLoadPicture()
   19 #include <gdiplus.h> // Used by LoadPicture().
   20 #include "util.h"
   21 #include "globaldata.h"
   22 
   23 
   24 int GetYDay(int aMon, int aDay, bool aIsLeapYear)
   25 // Returns a number between 1 and 366.
   26 // Caller must verify that aMon is a number between 1 and 12, and aDay is a number between 1 and 31.
   27 {
   28     --aMon;  // Convert to zero-based.
   29     if (aIsLeapYear)
   30     {
   31         int leap_offset[12] = {0, 31, 60, 91, 121, 152, 182, 213, 244, 274, 305, 335};
   32         return leap_offset[aMon] + aDay;
   33     }
   34     else
   35     {
   36         int normal_offset[12] = {0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334};
   37         return normal_offset[aMon] + aDay;
   38     }
   39 }
   40 
   41 
   42 
   43 int GetISOWeekNumber(LPTSTR aBuf, int aYear, int aYDay, int aWDay)
   44 // Caller must ensure that aBuf is of size 7 or greater, that aYear is a valid year (e.g. 2005),
   45 // that aYDay is between 1 and 366, and that aWDay is between 0 and 6 (day of the week).
   46 // Produces the week number in YYYYNN format, e.g. 200501.
   47 // Note that year is also returned because it isn't necessarily the same as aTime's calendar year.
   48 // Based on Linux glibc source code (GPL).
   49 {
   50     --aYDay;  // Convert to zero based.
   51     #define ISO_WEEK_START_WDAY 1 // Monday
   52     #define ISO_WEEK1_WDAY 4      // Thursday
   53     #define ISO_WEEK_DAYS(yday, wday) (yday - (yday - wday + ISO_WEEK1_WDAY + ((366 / 7 + 2) * 7)) % 7 \
   54         + ISO_WEEK1_WDAY - ISO_WEEK_START_WDAY);
   55 
   56     int year = aYear;
   57     int days = ISO_WEEK_DAYS(aYDay, aWDay);
   58 
   59     if (days < 0) // This ISO week belongs to the previous year.
   60     {
   61         --year;
   62         days = ISO_WEEK_DAYS(aYDay + (365 + IS_LEAP_YEAR(year)), aWDay);
   63     }
   64     else
   65     {
   66         int d = ISO_WEEK_DAYS(aYDay - (365 + IS_LEAP_YEAR(year)), aWDay);
   67         if (0 <= d) // This ISO week belongs to the next year.
   68         {
   69             ++year;
   70             days = d;
   71         }
   72     }
   73 
   74     // Use sntprintf() for safety; that is, in case year contains a value longer than 4 digits.
   75     // This also adds the leading zeros in front of year and week number, if needed.
   76     return sntprintf(aBuf, 7, _T("%04d%02d"), year, (days / 7) + 1); // Return the length of the string produced.
   77 }
   78 
   79 
   80 
   81 ResultType YYYYMMDDToFileTime(LPTSTR aYYYYMMDD, FILETIME &aFileTime)
   82 {
   83     SYSTEMTIME st;
   84     YYYYMMDDToSystemTime(aYYYYMMDD, st, false);  // "false" because it's validated below.
   85     // This will return failure if aYYYYMMDD contained any invalid elements, such as an
   86     // explicit zero for the day of the month.  It also reports failure if st.wYear is
   87     // less than 1601, which for simplicity is enforced globally throughout the program
   88     // since none of the Windows API calls seem to support earlier years.
   89     return SystemTimeToFileTime(&st, &aFileTime) ? OK : FAIL; // The st.wDayOfWeek member is ignored.
   90 }
   91 
   92 
   93 
   94 DWORD YYYYMMDDToSystemTime2(LPTSTR aYYYYMMDD, SYSTEMTIME *aSystemTime)
   95 // Calls YYYYMMDDToSystemTime() to fill up to two elements of the aSystemTime array.
   96 // Returns a GDTR bitwise combination to indicate which of the two elements, or both, are valid.
   97 // Caller must ensure that aYYYYMMDD is a modifiable string since it's temporarily altered and restored here.
   98 {
   99     DWORD gdtr = 0;
  100     if (!*aYYYYMMDD)
  101         return gdtr;
  102     if (*aYYYYMMDD != '-') // Since first char isn't a dash, there is a minimum present.
  103     {
  104         LPTSTR cp;
  105         if (cp = _tcschr(aYYYYMMDD + 1, '-'))
  106             *cp = '\0'; // Temporarily terminate in case only the leading part of the YYYYMMDD format is present.  Otherwise, the dash and other chars would be considered invalid fields.
  107         if (YYYYMMDDToSystemTime(aYYYYMMDD, aSystemTime[0], true)) // Date string is valid.
  108             gdtr |= GDTR_MIN; // Indicate that minimum is present.
  109         if (cp)
  110         {
  111             *cp = '-'; // Undo the temp. termination.
  112             aYYYYMMDD = cp + 1; // Set it to the maximum's position for use below.
  113         }
  114         else // No dash, so there is no maximum.  Indicate this by making aYYYYMMDD empty.
  115             aYYYYMMDD = _T("");
  116     }
  117     else // *aYYYYMMDD=='-', so only the maximum is present; thus there will be no minimum.
  118         ++aYYYYMMDD; // Skip over the dash to set it to the maximum's position.
  119     if (*aYYYYMMDD) // There is a maximum.
  120     {
  121         if (YYYYMMDDToSystemTime(aYYYYMMDD, aSystemTime[1], true)) // Date string is valid.
  122             gdtr |= GDTR_MAX; // Indicate that maximum is present.
  123     }
  124     return gdtr;
  125 }
  126 
  127 
  128 
  129 ResultType YYYYMMDDToSystemTime(LPTSTR aYYYYMMDD, SYSTEMTIME &aSystemTime, bool aDoValidate)
  130 // Although aYYYYMMDD need not be terminated at the end of the YYYYMMDDHH24MISS string (as long as
  131 // the string's capacity is at least 14), it should be terminated if only the leading part
  132 // of the YYYYMMDDHH24MISS format is present.
  133 // Caller must ensure that aYYYYMMDD is non-NULL.  If aDoValidate is false, OK is always
  134 // returned and aSystemTime might contain invalid elements.  Otherwise, FAIL will be returned
  135 // if the date and time contains any invalid elements, or if the year is less than 1601
  136 // (Windows generally does not support earlier years).
  137 {
  138     // sscanf() is avoided because it adds 2 KB to the compressed EXE size.
  139     TCHAR temp[16];
  140     size_t length = _tcslen(aYYYYMMDD); // Use this rather than incrementing the pointer in case there are ever partial fields such as 20051 vs. 200501.
  141 
  142     tcslcpy(temp, aYYYYMMDD, 5);
  143     aSystemTime.wYear = _ttoi(temp);
  144 
  145     if (length > 4) // It has a month component.
  146     {
  147         tcslcpy(temp, aYYYYMMDD + 4, 3);
  148         aSystemTime.wMonth = _ttoi(temp);  // Unlike "struct tm", SYSTEMTIME uses 1 for January, not 0.
  149         // v1.0.48: Changed not to provide a default when month number is out-of-range.
  150         // This allows callers like "if var is time" to properly detect badly-formatted dates.
  151     }
  152     else
  153         aSystemTime.wMonth = 1;
  154 
  155     if (length > 6) // It has a day-of-month component.
  156     {
  157         tcslcpy(temp, aYYYYMMDD + 6, 3);
  158         aSystemTime.wDay = _ttoi(temp);
  159     }
  160     else
  161         aSystemTime.wDay = 1;
  162 
  163     if (length > 8) // It has an hour component.
  164     {
  165         tcslcpy(temp, aYYYYMMDD + 8, 3);
  166         aSystemTime.wHour = _ttoi(temp);
  167     }
  168     else
  169         aSystemTime.wHour = 0;   // Midnight.
  170 
  171     if (length > 10) // It has a minutes component.
  172     {
  173         tcslcpy(temp, aYYYYMMDD + 10, 3);
  174         aSystemTime.wMinute = _ttoi(temp);
  175     }
  176     else
  177         aSystemTime.wMinute = 0;
  178 
  179     if (length > 12) // It has a seconds component.
  180     {
  181         tcslcpy(temp, aYYYYMMDD + 12, 3);
  182         aSystemTime.wSecond = _ttoi(temp);
  183     }
  184     else
  185         aSystemTime.wSecond = 0;
  186 
  187     aSystemTime.wMilliseconds = 0;  // Always set to zero in this case.
  188 
  189     // v1.0.46.07: Unlike the other date/time components, which are validated further below by the call to
  190     // SystemTimeToFileTime(), "month" must be validated in advance because it's used to access an array
  191     // in the day-of-week code further below.
  192     // v1.0.48.04: To fix FormatTime and possibly other things, don't return FAIL when month is out-of-range unless
  193     // aDoValidate==false, and not even then (for maintainability) because a section further below handles it.
  194     if (aSystemTime.wMonth < 1 || aSystemTime.wMonth > 12) // Month must be validated prior to accessing the array further below.
  195         // Set an in-range default, which caller is likely to ignore if it passed true for aDoValidate
  196         // because the validation further below will also detect the out-of-range month and return FAIL.
  197         aSystemTime.wDayOfWeek = 1;
  198     else // Month is in-range, which is necessary for the method below to work safely.
  199     {
  200         // Day-of-week code by Tomohiko Sakamoto:
  201         static int t[] = {0, 3, 2, 5, 0, 3, 5, 1, 4, 6, 2, 4};
  202         int y = aSystemTime.wYear;
  203         y -= aSystemTime.wMonth < 3;
  204         aSystemTime.wDayOfWeek = (y + y/4 - y/100 + y/400 + t[aSystemTime.wMonth-1] + aSystemTime.wDay) % 7;
  205     }
  206 
  207     if (aDoValidate)
  208     {
  209         FILETIME ft;
  210         // This will return failure if aYYYYMMDD contained any invalid elements, such as an
  211         // explicit zero for the day of the month.  It also reports failure if st.wYear is
  212         // less than 1601, which for simplicity is enforced globally throughout the program
  213         // since none of the Windows API calls seem to support earlier years.
  214         return SystemTimeToFileTime(&aSystemTime, &ft) ? OK : FAIL;
  215         // Above: The st.wDayOfWeek member is ignored by the above (but might be used by our caller), but
  216         // that's okay because it shouldn't need validation.
  217     }
  218     return OK;
  219 }
  220 
  221 
  222 
  223 LPTSTR FileTimeToYYYYMMDD(LPTSTR aBuf, FILETIME &aTime, bool aConvertToLocalTime)
  224 // Returns aBuf.
  225 {
  226     FILETIME ft;
  227     if (aConvertToLocalTime)
  228         FileTimeToLocalFileTime(&aTime, &ft); // MSDN says that target cannot be the same var as source.
  229     else
  230         memcpy(&ft, &aTime, sizeof(FILETIME));  // memcpy() might be less code size that a struct assignment, ft = aTime.
  231     SYSTEMTIME st;
  232     if (FileTimeToSystemTime(&ft, &st))
  233         return SystemTimeToYYYYMMDD(aBuf, st);
  234     *aBuf = '\0';
  235     return aBuf;
  236 }
  237 
  238 
  239 
  240 LPTSTR SystemTimeToYYYYMMDD(LPTSTR aBuf, SYSTEMTIME &aTime)
  241 {
  242     _stprintf(aBuf, _T("%04d%02d%02d") _T("%02d%02d%02d")
  243         , aTime.wYear, aTime.wMonth, aTime.wDay
  244         , aTime.wHour, aTime.wMinute, aTime.wSecond);
  245     return aBuf;
  246 }
  247 
  248 
  249 
  250 __int64 YYYYMMDDSecondsUntil(LPTSTR aYYYYMMDDStart, LPTSTR aYYYYMMDDEnd, bool &aFailed)
  251 // Returns the number of seconds from aYYYYMMDDStart until aYYYYMMDDEnd.
  252 // If aYYYYMMDDStart is blank, the current time will be used in its place.
  253 {
  254     aFailed = true;  // Set default for output parameter, in case of early return.
  255     if (!aYYYYMMDDStart || !aYYYYMMDDEnd) return 0;
  256 
  257     FILETIME ftStart, ftEnd, ftNowUTC;
  258 
  259     if (*aYYYYMMDDStart)
  260     {
  261         if (!YYYYMMDDToFileTime(aYYYYMMDDStart, ftStart))
  262             return 0;
  263     }
  264     else // Use the current time in its place.
  265     {
  266         GetSystemTimeAsFileTime(&ftNowUTC);
  267         FileTimeToLocalFileTime(&ftNowUTC, &ftStart);  // Convert UTC to local time.
  268     }
  269     if (*aYYYYMMDDEnd)
  270     {
  271         if (!YYYYMMDDToFileTime(aYYYYMMDDEnd, ftEnd))
  272             return 0;
  273     }
  274     else // Use the current time in its place.
  275     {
  276         GetSystemTimeAsFileTime(&ftNowUTC);
  277         FileTimeToLocalFileTime(&ftNowUTC, &ftEnd);  // Convert UTC to local time.
  278     }
  279     aFailed = false;  // Indicate success.
  280     return FileTimeSecondsUntil(&ftStart, &ftEnd);
  281 }
  282 
  283 
  284 
  285 __int64 FileTimeSecondsUntil(FILETIME *pftStart, FILETIME *pftEnd)
  286 // Returns the number of seconds from pftStart until pftEnd.
  287 {
  288     if (!pftStart || !pftEnd) return 0;
  289 
  290     // The calculation is done this way for compilers that don't support 64-bit math operations (not sure which):
  291     // Note: This must be LARGE vs. ULARGE because we want the calculation to be signed for cases where
  292     // pftStart is greater than pftEnd:
  293     ULARGE_INTEGER uiStart, uiEnd;
  294     uiStart.LowPart = pftStart->dwLowDateTime;
  295     uiStart.HighPart = pftStart->dwHighDateTime;
  296     uiEnd.LowPart = pftEnd->dwLowDateTime;
  297     uiEnd.HighPart = pftEnd->dwHighDateTime;
  298     // Must do at least the inner cast to avoid losing negative results:
  299     return (__int64)((__int64)(uiEnd.QuadPart - uiStart.QuadPart) / 10000000); // Convert from tenths-of-microsecond.
  300 }
  301 
  302 
  303 
  304 SymbolType IsPureNumeric(LPCTSTR aBuf, BOOL aAllowNegative, BOOL aAllowAllWhitespace
  305     , BOOL aAllowFloat, BOOL aAllowImpure)  // BOOL vs. bool might squeeze a little more performance out of this frequently-called function.
  306 // String can contain whitespace.
  307 // If aBuf doesn't contain something purely numeric, PURE_NOT_NUMERIC is returned.  The same happens if
  308 // aBuf contains a float but aAllowFloat is false.  (The aAllowFloat parameter isn't strictly necessary
  309 // because the caller could just check whether the return value is/isn't PURE_FLOAT to get the same effect.
  310 // However, supporting aAllowFloat seems to greatly improve maintainability because it saves many callers
  311 // from having to compare the return value to PURE_INTEGER [they can just interpret the return value as BOOL].
  312 // It also improves readability due to the "Is" part of the function name.  So it seems worth keeping.)
  313 // Otherwise, PURE_INTEGER or PURE_FLOAT is returned.
  314 // If aAllowAllWhitespace==true and the string is blank or all whitespace, PURE_INTEGER is returned.
  315 // Obsolete comment: Making this non-inline reduces the size of the compressed EXE by only 2K.  Since this
  316 // function is called so often, it seems preferable to keep it inline for performance.
  317 {
  318     aBuf = omit_leading_whitespace(aBuf); // i.e. caller doesn't have to have ltrimmed, only rtrimmed.
  319     if (!*aBuf) // The string is empty or consists entirely of whitespace.
  320         return aAllowAllWhitespace ? PURE_INTEGER : PURE_NOT_NUMERIC;
  321 
  322     if (*aBuf == '-')
  323     {
  324         if (aAllowNegative)
  325             ++aBuf;
  326         else
  327             return PURE_NOT_NUMERIC;
  328     }
  329     else if (*aBuf == '+')
  330         ++aBuf;
  331 
  332     // Relies on short circuit boolean order to prevent reading beyond the end of the string:
  333     BOOL is_hex = IS_HEX(aBuf); // BOOL vs. bool might squeeze a little more performance out this frequently-called function.
  334     if (is_hex)
  335         aBuf += 2;  // Skip over the 0x prefix.
  336 
  337     // Set defaults:
  338     BOOL has_decimal_point = false;
  339     BOOL has_at_least_one_digit = false; // i.e. a string consisting of only "+", "-" or "." is not considered numeric.
  340     int c; // int vs. char might squeeze a little more performance out of it (it does reduce code size by 5 bytes). Probably must stay signed vs. unsigned for some of the uses below.
  341 
  342     for (;; ++aBuf)
  343     {
  344         c = *aBuf;
  345         if (IS_SPACE_OR_TAB(c))
  346         {
  347             if (*omit_leading_whitespace(aBuf)) // But that space or tab is followed by something other than whitespace.
  348                 if (!aAllowImpure) // e.g. "123 456" is not a valid pure number.
  349                     return PURE_NOT_NUMERIC;
  350                 // else fall through to the bottom logic.
  351             // else since just whitespace at the end, the number qualifies as pure, so fall through to the bottom
  352             // logic (it would already have returned in the loop if it was impure)
  353             break;
  354         }
  355         if (!c) // End of string was encountered.
  356             break; // The number qualifies as pure, so fall through to the logic at the bottom. (It would already have returned elsewhere in the loop if the number is impure).
  357         if (c == '.')
  358         {
  359             if (!aAllowFloat || has_decimal_point || is_hex) // If aAllowFloat==false, a decimal point at the very end of the number is considered non-numeric even if aAllowImpure==true.  Some callers like "case ACT_ADD" might rely on this.
  360                 // i.e. if aBuf contains 2 decimal points, it can't be a valid number.
  361                 // Note that decimal points are allowed in hexadecimal strings, e.g. 0xFF.EE.
  362                 // But since that format doesn't seem to be supported by VC++'s atof() and probably
  363                 // related functions, and since it's extremely rare, it seems best not to support it.
  364                 return PURE_NOT_NUMERIC;
  365             else
  366                 has_decimal_point = true;
  367         }
  368         else
  369         {
  370             if (is_hex ? !_istxdigit(c) : (c < '0' || c > '9')) // And since we're here, it's not '.' either.
  371             {
  372                 if (aAllowImpure) // Since aStr starts with a number (as verified above), it is considered a number.
  373                 {
  374                     if (has_at_least_one_digit)
  375                         return has_decimal_point ? PURE_FLOAT : PURE_INTEGER;
  376                     else // i.e. the strings "." and "-" are not considered to be numeric by themselves.
  377                         return PURE_NOT_NUMERIC;
  378                 }
  379                 else
  380                 {
  381                     // As written below, this actually tolerates malformed scientific notation such as numbers
  382                     // containing two or more E's (e.g. 1.0e4e+5e-6,).  But for performance and due to rarity,
  383                     // it seems best not to check for them.
  384                     if (ctoupper(c) != 'E' // v1.0.46.11: Support scientific notation in floating point numbers.
  385                         || !(has_decimal_point && has_at_least_one_digit)) // But it must have a decimal point and at least one digit to the left of the 'E'. This avoids variable names like "1e4" from being seen as sci-notation literals (for backward compatibility). Some callers rely on this check.
  386                         return PURE_NOT_NUMERIC;
  387                     if (aBuf[1] == '-' || aBuf[1] == '+') // The optional sign is present on the exponent.
  388                         ++aBuf; // Omit it from further consideration so that the outer loop doesn't see it as an extra/illegal sign.
  389                     if (aBuf[1] < '0' || aBuf[1] > '9')
  390                         // Even if it is an 'e', ensure what follows it is a valid exponent.  Some callers rely
  391                         // on this check, such as ones that expect "0.6e" to be non-numeric (for "SetFormat Float") 
  392                         return PURE_NOT_NUMERIC;
  393                 }
  394             }
  395             else // This character is a valid digit or hex-digit.
  396                 has_at_least_one_digit = true;
  397         }
  398     } // for()
  399 
  400     if (has_at_least_one_digit)
  401         return has_decimal_point ? PURE_FLOAT : PURE_INTEGER;
  402     else
  403         return PURE_NOT_NUMERIC; // i.e. the strings "+" "-" and "." are not numeric by themselves.
  404 }
  405 
  406 
  407 
  408 void strlcpy(LPSTR aDst, LPCSTR aSrc, size_t aDstSize) // Non-inline because it benches slightly faster that way.
  409 // Caller must ensure that aDstSize is greater than 0.
  410 // Caller must ensure that the entire capacity of aDst is writable, EVEN WHEN it knows that aSrc is much shorter
  411 // than the aDstSize.  This is because the call to strncpy (which is used for its superior performance) zero-fills
  412 // any unused portion of aDst.
  413 // Description:
  414 // Same as strncpy() but guarantees null-termination of aDst upon return.
  415 // No more than aDstSize - 1 characters will be copied from aSrc into aDst
  416 // (leaving room for the zero terminator, which is always inserted).
  417 // This function is defined in some Unices but is not standard.  But unlike
  418 // other versions, this one uses void for return value for reduced code size
  419 // (since it's called in so many places).
  420 {
  421     // Disabled for performance and reduced code size:
  422     //if (!aDst || !aSrc || !aDstSize) return aDstSize;  // aDstSize must not be zero due to the below method.
  423     // It might be worthwhile to have a custom char-copying-loop here someday so that number of characters
  424     // actually copied (not including the zero terminator) can be returned to callers who want it.
  425     --aDstSize; // Convert from size to length (caller has ensured that aDstSize > 0).
  426     strncpy(aDst, aSrc, aDstSize); // NOTE: In spite of its zero-filling, strncpy() benchmarks considerably faster than a custom loop, probably because it uses 32-bit memory operations vs. 8-bit.
  427     aDst[aDstSize] = '\0';
  428 }
  429 
  430 
  431 
  432 void wcslcpy(LPWSTR aDst, LPCWSTR aSrc, size_t aDstSize)
  433 {
  434     --aDstSize;
  435     wcsncpy(aDst, aSrc, aDstSize);
  436     aDst[aDstSize] = '\0';
  437 }
  438 
  439 
  440 
  441 int sntprintf(LPTSTR aBuf, int aBufSize, LPCTSTR aFormat, ...)
  442 // aBufSize is an int so that any negative values passed in from caller are not lost.
  443 // aBuf will always be terminated here except when aBufSize is <= zero (in which case the caller should
  444 // already have terminated it).  If aBufSize is greater than zero but not large enough to hold the
  445 // entire result, as much of the result as possible is copied and the return value is aBufSize - 1.
  446 // Returns the exact number of characters written, not including the zero terminator.  A negative
  447 // number is never returned, even if aBufSize is <= zero (which means there isn't even enough space left
  448 // to write a zero terminator), under the assumption that the caller has already terminated the string
  449 // and thus prefers to have 0 rather than -1 returned in such cases.
  450 // MSDN says (about _snprintf(), and testing shows that it applies to _vsnprintf() too): "This function
  451 // does not guarantee NULL termination, so ensure it is followed by sz[size - 1] = 0".
  452 {
  453     // The following should probably never be changed without a full suite of tests to ensure the
  454     // change doesn't cause the finicky _vsnprintf() to break something.
  455     if (aBufSize < 1 || !aBuf || !aFormat) return 0; // It's called from so many places that the extra checks seem warranted.
  456     va_list ap;
  457     va_start(ap, aFormat);
  458     // Must use _vsnprintf() not _snprintf() because of the way va_list is handled:
  459     int result = _vsntprintf(aBuf, aBufSize, aFormat, ap); // "returns the number of characters written, not including the terminating null character, or a negative value if an output error occurs"
  460     aBuf[aBufSize - 1] = '\0'; // Confirmed through testing: Must terminate at this exact spot because _vsnprintf() doesn't always do it.
  461     // Fix for v1.0.34: If result==aBufSize, must reduce result by 1 to return an accurate result to the
  462     // caller.  In other words, if the line above turned the last character into a terminator, one less character
  463     // is now present in aBuf.
  464     if (result == aBufSize)
  465         --result;
  466     return result > -1 ? result : aBufSize - 1; // Never return a negative value.  See comment under function definition, above.
  467 }
  468 
  469 
  470 
  471 int sntprintfcat(LPTSTR aBuf, int aBufSize, LPCTSTR aFormat, ...)
  472 // aBufSize is an int so that any negative values passed in from caller are not lost.
  473 // aBuf will always be terminated here except when the amount of space left in the buffer is zero or less.
  474 // (in which case the caller should already have terminated it).  If aBufSize is greater than zero but not
  475 // large enough to hold the entire result, as much of the result as possible is copied and the return value
  476 // is space_remaining - 1.
  477 // The caller must have ensured that aBuf and aFormat are non-NULL and that aBuf contains a valid string
  478 // (i.e. that it is null-terminated somewhere within the limits of aBufSize).
  479 // Returns the exact number of characters written, not including the zero terminator.  A negative
  480 // number is never returned, even if aBufSize is <= zero (which means there isn't even enough space left
  481 // to write a zero terminator), under the assumption that the caller has already terminated the string
  482 // and thus prefers to have 0 rather than -1 returned in such cases.
  483 {
  484     // The following should probably never be changed without a full suite of tests to ensure the
  485     // change doesn't cause the finicky _vsnprintf() to break something.
  486     size_t length = _tcslen(aBuf);
  487     int space_remaining = (int)(aBufSize - length); // Must cast to int to avoid loss of negative values.
  488     if (space_remaining < 1) // Can't even terminate it (no room) so just indicate that no characters were copied.
  489         return 0;
  490     aBuf += length;  // aBuf is now the spot where the new text will be written.
  491     va_list ap;
  492     va_start(ap, aFormat);
  493     // Must use vsnprintf() not snprintf() because of the way va_list is handled:
  494     int result = _vsntprintf(aBuf, (size_t)space_remaining, aFormat, ap); // "returns the number of characters written, not including the terminating null character, or a negative value if an output error occurs"
  495     aBuf[space_remaining - 1] = '\0'; // Confirmed through testing: Must terminate at this exact spot because _vsnprintf() doesn't always do it.
  496     return result > -1 ? result : space_remaining - 1; // Never return a negative value.  See comment under function definition, above.
  497 }
  498 
  499 
  500 
  501 // Not currently used by anything, so commented out to possibly reduce code size:
  502 //int tcslcmp(LPTSTR aBuf1, LPTSTR aBuf2, UINT aLength1, UINT aLength2)
  503 //// Case sensitive version.  See strlicmp() comments below.
  504 //{
  505 //  if (!aBuf1 || !aBuf2) return 0;
  506 //  if (aLength1 == UINT_MAX) aLength1 = (UINT)_tcslen(aBuf1);
  507 //  if (aLength2 == UINT_MAX) aLength2 = (UINT)_tcslen(aBuf2);
  508 //  UINT least_length = aLength1 < aLength2 ? aLength1 : aLength2;
  509 //  int diff;
  510 //  for (UINT i = 0; i < least_length; ++i)
  511 //      if (   diff = (int)((UCHAR)aBuf1[i] - (UCHAR)aBuf2[i])   ) // Use unsigned chars like strcmp().
  512 //          return diff;
  513 //  return (int)(aLength1 - aLength2);
  514 //}
  515 
  516 
  517 
  518 int tcslicmp(LPTSTR aBuf1, LPTSTR aBuf2, size_t aLength1, size_t aLength2)
  519 // Similar to strnicmp but considers each aBuf to be a string of length aLength if aLength was
  520 // specified.  In other words, unlike strnicmp() which would consider strnicmp("ab", "abc", 2)
  521 // [example verified correct] to be a match, this function would consider them to be
  522 // a mismatch.  Another way of looking at it: aBuf1 and aBuf2 will be directly
  523 // compared to one another as though they were actually of length aLength1 and
  524 // aLength2, respectively and then passed to stricmp() (not strnicmp) as those
  525 // shorter strings.  This behavior is useful for cases where you don't want
  526 // to have to bother with temporarily terminating a string so you can compare
  527 // only a substring to something else.  The return value meaning is the
  528 // same as strnicmp().  If either aLength param is UINT_MAX (via the default
  529 // parameters or via explicit call), it will be assumed that the entire
  530 // length of the respective aBuf will be used.
  531 {
  532     if (!aBuf1 || !aBuf2) return 0;
  533     if (aLength1 == -1) aLength1 = _tcslen(aBuf1);
  534     if (aLength2 == -1) aLength2 = _tcslen(aBuf2);
  535     size_t least_length = aLength1 < aLength2 ? aLength1 : aLength2;
  536     int diff;
  537     for (size_t i = 0; i < least_length; ++i)
  538         if (   diff = (int)(ctoupper(aBuf1[i]) - ctoupper(aBuf2[i]))   )
  539             return diff;
  540     // Since the above didn't return, the strings are equal if they're the same length.
  541     // Otherwise, the longer one is considered greater than the shorter one since the
  542     // longer one's next character is by definition something non-zero.  I'm not completely
  543     // sure that this is the same policy followed by ANSI strcmp():
  544     return (int)(aLength1 - aLength2);
  545 }
  546 
  547 
  548 
  549 LPTSTR tcsrstr(LPTSTR aStr, size_t aStr_length, LPCTSTR aPattern, StringCaseSenseType aStringCaseSense, int aOccurrence)
  550 // Returns NULL if not found, otherwise the address of the found string.
  551 // This could probably use a faster algorithm someday.  For now it seems adequate because
  552 // scripts rarely use it and when they do, it's usually on short haystack strings (such as
  553 // to find the last period in a filename).
  554 {
  555     if (aOccurrence < 1)
  556         return NULL;
  557     if (!*aPattern)
  558         // The empty string is found in every string, and since we're searching from the right, return
  559         // the position of the zero terminator to indicate the situation:
  560         return aStr + aStr_length;
  561 
  562     size_t aPattern_length = _tcslen(aPattern);
  563     TCHAR aPattern_last_char = aPattern[aPattern_length - 1];
  564     TCHAR aPattern_last_char_lower = (aStringCaseSense == SCS_INSENSITIVE_LOCALE)
  565         ? (TCHAR)ltolower(aPattern_last_char)
  566         : ctolower(aPattern_last_char);
  567 
  568     int occurrence = 0;
  569     LPCTSTR match_starting_pos = aStr + aStr_length - 1;
  570 
  571     // Keep finding matches from the right until the Nth occurrence (specified by the caller) is found.
  572     for (;;)
  573     {
  574         if (match_starting_pos < aStr)
  575             return NULL;  // No further matches are possible.
  576         // Find (from the right) the first occurrence of aPattern's last char:
  577         LPCTSTR last_char_match;
  578         for (last_char_match = match_starting_pos; last_char_match >= aStr; --last_char_match)
  579         {
  580             if (aStringCaseSense == SCS_INSENSITIVE) // The most common mode is listed first for performance.
  581             {
  582                 if (ctolower(*last_char_match) == aPattern_last_char_lower)
  583                     break;
  584             }
  585             else if (aStringCaseSense == SCS_INSENSITIVE_LOCALE)
  586             {
  587                 if (ltolower(*last_char_match) == aPattern_last_char_lower)
  588                     break;
  589             }
  590             else // Case sensitive.
  591             {
  592                 if (*last_char_match == aPattern_last_char)
  593                     break;
  594             }
  595         }
  596 
  597         if (last_char_match < aStr) // No further matches are possible.
  598             return NULL;
  599 
  600         // Now that aPattern's last character has been found in aStr, ensure the rest of aPattern
  601         // exists in aStr to the left of last_char_match:
  602         LPCTSTR full_match, cp;
  603         bool found;
  604         for (found = false, cp = aPattern + aPattern_length - 2, full_match = last_char_match - 1;; --cp, --full_match)
  605         {
  606             if (cp < aPattern) // The complete pattern has been found at the position in full_match + 1.
  607             {
  608                 ++full_match; // Adjust for the prior iteration's decrement.
  609                 if (++occurrence == aOccurrence)
  610                     return (LPTSTR) full_match;
  611                 found = true;
  612                 break;
  613             }
  614             if (full_match < aStr) // Only after checking the above is this checked.
  615                 break;
  616 
  617             if (aStringCaseSense == SCS_INSENSITIVE) // The most common mode is listed first for performance.
  618             {
  619                 if (ctolower(*full_match) != ctolower(*cp))
  620                     break;
  621             }
  622             else if (aStringCaseSense == SCS_INSENSITIVE_LOCALE)
  623             {
  624                 if (ltolower(*full_match) != ltolower(*cp))
  625                     break;
  626             }
  627             else // Case sensitive.
  628             {
  629                 if (*full_match != *cp)
  630                     break;
  631             }
  632         } // for() innermost
  633         if (found) // Although the above found a match, it wasn't the right one, so resume searching.
  634             match_starting_pos = full_match - 1;
  635         else // the pattern broke down, so resume searching at THIS position.
  636             match_starting_pos = last_char_match - 1;  // Don't go back by more than 1.
  637     } // while() find next match
  638 }
  639 
  640 
  641 
  642 LPTSTR tcscasestr(LPCTSTR phaystack, LPCTSTR pneedle)
  643     // To make this work with MS Visual C++, this version uses tolower/toupper() in place of
  644     // _tolower/_toupper(), since apparently in GNU C, the underscore macros are identical
  645     // to the non-underscore versions; but in MS the underscore ones do an unconditional
  646     // conversion (mangling non-alphabetic characters such as the zero terminator).  MSDN:
  647     // tolower: Converts c to lowercase if appropriate
  648     // _tolower: Converts c to lowercase
  649 
  650     // Return the offset of one string within another.
  651     // Copyright (C) 1994,1996,1997,1998,1999,2000 Free Software Foundation, Inc.
  652     // This file is part of the GNU C Library.
  653 
  654     // The GNU C Library is free software; you can redistribute it and/or
  655     // modify it under the terms of the GNU Lesser General Public
  656     // License as published by the Free Software Foundation; either
  657     // version 2.1 of the License, or (at your option) any later version.
  658 
  659     // The GNU C Library is distributed in the hope that it will be useful,
  660     // but WITHOUT ANY WARRANTY; without even the implied warranty of
  661     // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
  662     // Lesser General Public License for more details.
  663 
  664     // You should have received a copy of the GNU Lesser General Public
  665     // License along with the GNU C Library; if not, write to the Free
  666     // Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
  667     // 02111-1307 USA.
  668 
  669     // My personal strstr() implementation that beats most other algorithms.
  670     // Until someone tells me otherwise, I assume that this is the
  671     // fastest implementation of strstr() in C.
  672     // I deliberately chose not to comment it.  You should have at least
  673     // as much fun trying to understand it, as I had to write it :-).
  674     // Stephen R. van den Berg, berg@pool.informatik.rwth-aachen.de
  675 
  676     // Faster looping by precalculating bl, bu, cl, cu before looping.
  677     // 2004 Apr 08  Jose Da Silva, digital@joescat@com
  678 {
  679     register const TBYTE *haystack, *needle;
  680     register unsigned bl, bu, cl, cu;
  681     
  682     haystack = (const TBYTE *) phaystack;
  683     needle = (const TBYTE *) pneedle;
  684 
  685     // Since ctolower returns TCHAR (which is signed in ANSI builds), typecast to
  686     // TBYTE first to promote characters \x80-\xFF to unsigned 32-bit correctly:
  687     bl = (TBYTE)ctolower(*needle);
  688     if (bl != '\0')
  689     {
  690         // Scan haystack until the first character of needle is found:
  691         bu = (TBYTE)ctoupper(bl);
  692         haystack--;             /* possible ANSI violation */
  693         do
  694         {
  695             cl = *++haystack;
  696             if (cl == '\0')
  697                 goto ret0;
  698         }
  699         while ((cl != bl) && (cl != bu));
  700 
  701         // See if the rest of needle is a one-for-one match with this part of haystack:
  702         cl = (TBYTE)ctolower(*++needle);
  703         if (cl == '\0')  // Since needle consists of only one character, it is already a match as found above.
  704             goto foundneedle;
  705         cu = (TBYTE)ctoupper(cl);
  706         ++needle;
  707         goto jin;
  708         
  709         for (;;)
  710         {
  711             register unsigned a;
  712             register const TBYTE *rhaystack, *rneedle;
  713             do
  714             {
  715                 a = *++haystack;
  716                 if (a == '\0')
  717                     goto ret0;
  718                 if ((a == bl) || (a == bu))
  719                     break;
  720                 a = *++haystack;
  721                 if (a == '\0')
  722                     goto ret0;
  723 shloop:
  724                 ;
  725             }
  726             while ((a != bl) && (a != bu));
  727 
  728 jin:
  729             a = *++haystack;
  730             if (a == '\0')  // Remaining part of haystack is shorter than needle.  No match.
  731                 goto ret0;
  732 
  733             if ((a != cl) && (a != cu)) // This promising candidate is not a complete match.
  734                 goto shloop;            // Start looking for another match on the first char of needle.
  735             
  736             rhaystack = haystack-- + 1;
  737             rneedle = needle;
  738             a = (TBYTE)ctolower(*rneedle);
  739             
  740             if ((TBYTE)ctolower(*rhaystack) == (int) a)
  741             do
  742             {
  743                 if (a == '\0')
  744                     goto foundneedle;
  745                 ++rhaystack;
  746                 a = (TBYTE)ctolower(*++needle);
  747                 if ((TBYTE)ctolower(*rhaystack) != (int) a)
  748                     break;
  749                 if (a == '\0')
  750                     goto foundneedle;
  751                 ++rhaystack;
  752                 a = (TBYTE)ctolower(*++needle);
  753             }
  754             while ((TBYTE)ctolower(*rhaystack) == (int) a);
  755             
  756             needle = rneedle;       /* took the register-poor approach */
  757             
  758             if (a == '\0')
  759                 break;
  760         } // for(;;)
  761     } // if (bl != '\0')
  762 foundneedle:
  763     return (LPTSTR) haystack;
  764 ret0:
  765     return 0;
  766 }
  767 
  768 
  769 
  770 LPTSTR ltcschr(LPCTSTR haystack, TCHAR ch)
  771 {
  772     LPCTSTR cp;
  773     UINT lch = ltolower(ch);
  774     for (cp = haystack;; ++cp)
  775     {
  776         if (ltolower(*cp) == lch)
  777             return (LPTSTR)cp;
  778         if (!*cp) // Implies lch != 0.
  779             return NULL;
  780     }
  781 }
  782 
  783 
  784 
  785 LPTSTR lstrcasestr(LPCTSTR phaystack, LPCTSTR pneedle)
  786 // This is the locale-obeying variant of strcasestr.  It uses CharUpper/Lower in place of toupper/lower,
  787 // which sees chars like ä as the same as Ä (depending on code page/locale).  This function is about
  788 // 1 to 8 times slower than strcasestr() depending on factors such as how many partial matches for needle
  789 // are in haystack.
  790 // License: GNU GPL
  791 // Copyright (C) 1994,1996,1997,1998,1999,2000 Free Software Foundation, Inc.
  792 // See strcasestr() for more comments.
  793 {
  794     register const TBYTE *haystack, *needle;
  795     register unsigned bl, bu, cl, cu;
  796     
  797     haystack = (const TBYTE *) phaystack;
  798     needle = (const TBYTE *) pneedle;
  799 
  800     bl = (UINT)ltolower(*needle);
  801     if (bl != 0)
  802     {
  803         // Scan haystack until the first character of needle is found:
  804         bu = (UINT)(size_t)ltoupper(bl);
  805         haystack--;             /* possible ANSI violation */
  806         do
  807         {
  808             cl = *++haystack;
  809             if (cl == '\0')
  810                 goto ret0;
  811         }
  812         while ((cl != bl) && (cl != bu));
  813 
  814         // See if the rest of needle is a one-for-one match with this part of haystack:
  815         cl = (UINT)ltolower(*++needle);
  816         if (cl == '\0')  // Since needle consists of only one character, it is already a match as found above.
  817             goto foundneedle;
  818         cu = (UINT)ltoupper(cl);
  819         ++needle;
  820         goto jin;
  821         
  822         for (;;)
  823         {
  824             register unsigned a;
  825             register const TBYTE *rhaystack, *rneedle;
  826             do
  827             {
  828                 a = *++haystack;
  829                 if (a == '\0')
  830                     goto ret0;
  831                 if ((a == bl) || (a == bu))
  832                     break;
  833                 a = *++haystack;
  834                 if (a == '\0')
  835                     goto ret0;
  836 shloop:
  837                 ;
  838             }
  839             while ((a != bl) && (a != bu));
  840 
  841 jin:
  842             a = *++haystack;
  843             if (a == '\0')  // Remaining part of haystack is shorter than needle.  No match.
  844                 goto ret0;
  845 
  846             if ((a != cl) && (a != cu)) // This promising candidate is not a complete match.
  847                 goto shloop;            // Start looking for another match on the first char of needle.
  848             
  849             rhaystack = haystack-- + 1;
  850             rneedle = needle;
  851             a = (UINT)ltolower(*rneedle);
  852             
  853             if ((UINT)ltolower(*rhaystack) == a)
  854             do
  855             {
  856                 if (a == '\0')
  857                     goto foundneedle;
  858                 ++rhaystack;
  859                 a = (UINT)ltolower(*++needle);
  860                 if ((UINT)ltolower(*rhaystack) != a)
  861                     break;
  862                 if (a == '\0')
  863                     goto foundneedle;
  864                 ++rhaystack;
  865                 a = (UINT)ltolower(*++needle);
  866             }
  867             while ((UINT)ltolower(*rhaystack) == a);
  868             
  869             needle = rneedle;       /* took the register-poor approach */
  870             
  871             if (a == '\0')
  872                 break;
  873         } // for(;;)
  874     } // if (bl != '\0')
  875 foundneedle:
  876     return (LPTSTR) haystack;
  877 ret0:
  878     return 0;
  879 }
  880 
  881 
  882 
  883 UINT StrReplace(LPTSTR aHaystack, LPTSTR aOld, LPTSTR aNew, StringCaseSenseType aStringCaseSense
  884     , UINT aLimit, size_t aSizeLimit, LPTSTR *aDest, size_t *aHaystackLength)
  885 // Replaces all (or aLimit) occurrences of aOld with aNew in aHaystack.
  886 // On success, it returns the number of replacements done (0 if none).  On failure (out of memory), it returns 0
  887 // (and if aDest isn't NULL, it also sets *aDest to NULL on failure).
  888 //
  889 // PARAMETERS:
  890 // - aLimit: Specify UINT_MAX to have no restriction on the number of replacements.  Otherwise, specify a number >=0.
  891 // - aSizeLimit: Specify -1 to assume that aHaystack has enough capacity for any mode #1 replacement. Otherwise,
  892 //   specify the size limit (in either mode 1 or 2), but it must be >= length of aHaystack (simplifies the code).
  893 // - aDest: If NULL, the function will operate in mode #1.  Otherwise, it uses mode #2 (see further below).
  894 // - aHaystackLength: If it isn't NULL, *aHaystackLength must be the length of aHaystack.  HOWEVER, *aHaystackLength
  895 //   is then changed here to be the length of the result string so that caller can use it to improve performance.
  896 //
  897 // MODE 1 (when aDest==NULL): aHaystack is used as both the source and the destination (sometimes temporary memory
  898 // is used for performance, but it's freed afterward and so transparent to the caller).
  899 // When it passes in -1 for aSizeLimit (the default), caller must ensure that aHaystack has enough capacity to hold
  900 // the new/replaced result.  When non-NULL, aSizeLimit will be enforced by limiting the number of replacements to
  901 // the available memory (i.e. any remaining replacements are simply not done and that part of haystack is unaltered).
  902 //
  903 // MODE 2 (when aDest!=NULL): If zero replacements are needed, we set *aDest to be aHaystack to indicate that no
  904 // new memory was allocated.  Otherwise, we store in *aDest the address of the new memory that holds the result.
  905 // - The caller is responsible for any new memory in *aDest (freeing it, etc.)
  906 // - The initial value of *aDest doesn't matter.
  907 // - The contents of aHaystack isn't altered, not even if aOld_length==aNew_length (some callers rely on this).
  908 //
  909 // v1.0.45: This function was heavily revised to improve performance and flexibility.  It has also made
  910 // two other/related StrReplace() functions obsolete.  Also, the code has been simplified to avoid doing
  911 // a first pass through haystack to find out exactly how many replacements there are because that step
  912 // nearly doubles the time required for the entire operation (in most cases).  Its benefit was mainly in
  913 // memory savings and avoidance of any reallocs since the initial alloc was always exactly right; however,
  914 // testing shows that one or two reallocs are generally much quicker than doing the size-calculation phase
  915 // because extra alloc'ing & memcpy'ing is much faster than an extra search through haystack for all the matches.
  916 // Furthermore, the new approach minimizes reallocs by using smart prediction.  Furthermore, the caller shrinks
  917 // the result memory via _expand() to avoid having too much extra/overhang.  These optimizations seem to make
  918 // the new approach better than the old one in every way, but especially performance.
  919 {
  920     #define REPLACEMENT_MODE2 aDest  // For readability.
  921 
  922     // THINGS TO SET NOW IN CASE OF EARLY RETURN OR GOTO:
  923     // Set up the input/output lengths:
  924     size_t haystack_length = aHaystackLength ? *aHaystackLength : _tcslen(aHaystack); // For performance, use caller's length if it was provided.
  925     size_t length_temp; // Just a placeholder/memory location used by the alias below.
  926     size_t &result_length = aHaystackLength ? *aHaystackLength : length_temp; // Make an alias for convenience and maintainability (if this is an output parameter for our caller, this step takes care that in advance).
  927     // Set up the output buffer:
  928     LPTSTR result_temp; // In mode #1, holds temporary memory that is freed before we return.
  929     LPTSTR &result = aDest ? *aDest : result_temp; // Make an alias for convenience and maintainability (if aDest is non-NULL, it's an output parameter for our caller, and this step takes care that in advance).
  930     result = NULL;     // It's allocated only upon first use to avoid a potentially massive allocation that might
  931     result_length = 0; // be wasted and cause swapping (not to mention that we'll have better ability to estimate the correct total size after the first replacement is discovered).
  932     size_t result_size = 0;
  933     // Variables used by both replacement methods.
  934     LPTSTR src, match_pos;
  935     // END OF INITIAL SETUP.
  936 
  937     // From now on, result_length and result should be kept up-to-date because they may have been set up
  938     // as output parameters above.
  939 
  940     if (!(*aHaystack && *aOld))
  941     {
  942         // Nothing to do if aHaystack is blank. If aOld is blank, that is not supported because it would be an
  943         // infinite loop. This policy is now largely due to backward compatibility because some other policy
  944         // may have been better.
  945         result = aHaystack; // Return unaltered string to caller in its output parameter (result is an alias for *aDest).
  946         result_length = haystack_length; // This is an alias for an output parameter, so update it for caller.
  947         return 0; // Report "no replacements".
  948     }
  949 
  950     size_t aOld_length = _tcslen(aOld);
  951     size_t aNew_length = _tcslen(aNew);
  952     int length_delta = (int)(aNew_length - aOld_length); // Cast to int to avoid loss of unsigned. A negative delta means the replacement substring is smaller than what it's replacing.
  953 
  954     if (aSizeLimit != -1) // Caller provided a size *restriction*, so if necessary reduce aLimit to stay within bounds.  Compare directly to -1 due to unsigned.
  955     {
  956         int extra_room = (int)(aSizeLimit-1 - haystack_length); // Cast to int to preserve negatives.
  957         if (extra_room < 0) // Caller isn't supposed to call it this way.  To avoid having to complicate the
  958             aLimit = 0;     // calculations in the else-if below, allow no replacements in this case.
  959         else if (length_delta > 0) // New-str is bigger than old-str.  This is checked to avoid going negative or dividing by 0 below. A positive delta means length of new/replacement string is greater than that of what it's replacing.
  960         {
  961             UINT upper_limit = (UINT)(extra_room / length_delta);
  962             if (aLimit > upper_limit)
  963                 aLimit = upper_limit;
  964         }
  965         //else length_delta <= 0, so there no overflow should be possible.  Leave aLimit as-is.
  966     }
  967 
  968     if (!REPLACEMENT_MODE2) // Mode #1
  969     {
  970         if (!length_delta // old_len==new_len, so use in-place method because it's just as fast in this case but it avoids the extra memory allocation.
  971             || haystack_length < 5000) // ...or the in-place method will likely be faster, and an earlier stage has ensured there's no risk of overflow.
  972             goto in_place_method; // "Goto" to avoid annoying indentation and long IF-blocks.
  973         //else continue on because the extra-memory method will usually perform better than the in-place method.
  974         // The extra-memory method is much faster than the in-place method when many replacements are needed because
  975         // it avoids a memmove() to shift the remainder of the buffer up against the area of memory that
  976         // will be replaced (which for the in-place method is done for every replacement).  The savings
  977         // can be enormous if aSource is very large, assuming the system can allocate the memory without swapping.
  978     }
  979     // Otherwise:
  980     // Since above didn't jump to the in place method, either the extra-memory method is preferred or this is mode #2.
  981     // Never use the in-place method for mode #2 because caller always wants a separate memory area used (for its
  982     // purposes, the extra-memory method is probably just as fast or faster than in-place method).
  983 
  984     // Below uses a temp var. because realloc() returns NULL on failure but leaves original block allocated.
  985     // Note that if it's given a NULL pointer, realloc() does a malloc() instead.
  986     LPTSTR realloc_temp;
  987     #define STRREPLACE_REALLOC(size) \
  988     {\
  989         result_size = size;\
  990         if (   !(realloc_temp = trealloc(result, result_size))   )\
  991             goto out_of_mem;\
  992         result = realloc_temp;\
  993     }
  994 
  995     // Other variables used by the replacement loop:
  996     size_t haystack_portion_length, new_result_length;
  997     UINT replacement_count;
  998 
  999     // Perform the replacement:
 1000     for (replacement_count = 0, src = aHaystack
 1001         ; aLimit && (match_pos = tcsstr2(src, aOld, aStringCaseSense));) // Relies on short-circuit boolean order.
 1002     {
 1003         ++replacement_count;
 1004         --aLimit;
 1005         haystack_portion_length = match_pos - src; // The length of the haystack section between the end of the previous match and the start of the current one.
 1006 
 1007         // Using the required length calculated below, expand/realloc "result" if necessary.
 1008         new_result_length = result_length + haystack_portion_length + aNew_length;
 1009         if (new_result_length >= result_size) // Uses >= to allow room for terminator.
 1010             STRREPLACE_REALLOC(PredictReplacementSize(length_delta, replacement_count, aLimit, (int)haystack_length
 1011                 , (int)new_result_length, (int)(match_pos - aHaystack))); // This will return if an alloc error occurs.
 1012 
 1013         // Now that we know "result" has enough capacity, put the new text into it.  The first step
 1014         // is to copy over the part of haystack that appears before the match.
 1015         if (haystack_portion_length)
 1016         {
 1017             tmemcpy(result + result_length, src, haystack_portion_length);
 1018             result_length += haystack_portion_length;
 1019         }
 1020         // Now append the replacement string in place of the old string.
 1021         if (aNew_length)
 1022         {
 1023             tmemcpy(result + result_length, aNew, aNew_length);
 1024             result_length += aNew_length;
 1025         }
 1026         //else omit it altogether; i.e. replace every aOld with the empty string.
 1027 
 1028         // Set up src to be the position where the next iteration will start searching.  For consistency with
 1029         // the in-place method, overlapping matches are not detected.  For example, the replacement
 1030         // of all occurrences of ".." with ". ." in "..." would produce ". ..", not ". . .":
 1031         src = match_pos + aOld_length; // This has two purposes: 1) Since match_pos is about to be altered by strstr, src serves as a placeholder for use by the next iteration; 2) it's also used further below.
 1032     }
 1033 
 1034     if (!replacement_count) // No replacements were done, so optimize by keeping the original (avoids a malloc+memcpy).
 1035     {
 1036         // The following steps are appropriate for both mode #1 and #2 (for simplicity and maintainability,
 1037         // they're all done unconditionally even though mode #1 might not require them all).
 1038         result = aHaystack; // Return unaltered string to caller in its output parameter (result is an alias for *aDest).
 1039         result_length = haystack_length; // This is an alias for an output parameter, so update it for caller.
 1040         return replacement_count;
 1041         // Since no memory was allocated, there's never anything to free.
 1042     }
 1043     // (Below relies only above having returned when no replacements because it assumes result!=NULL from now on.)
 1044 
 1045     // Otherwise, copy the remaining characters after the last replacement (if any) (fixed for v1.0.25.11).
 1046     if (haystack_portion_length = haystack_length - (src - aHaystack)) // This is the remaining part of haystack that need to be copied over as-is.
 1047     {
 1048         new_result_length = result_length + haystack_portion_length;
 1049         if (new_result_length >= result_size) // Uses >= to allow room for terminator.
 1050             STRREPLACE_REALLOC(new_result_length + 1); // This will return if an alloc error occurs.
 1051         tmemcpy(result + result_length, src, haystack_portion_length); // memcpy() usually benches a little faster than strcpy().
 1052         result_length = new_result_length; // Remember that result_length is actually an output for our caller, so even if for no other reason, it must be kept accurate for that.
 1053     }
 1054     result[result_length] = '\0'; // Must terminate it unconditionally because other sections usually don't do it.
 1055 
 1056     if (!REPLACEMENT_MODE2) // Mode #1.
 1057     {
 1058         // Since caller didn't provide destination memory, copy the result from our temporary memory (that was used
 1059         // for performance) back into the caller's original buf (which has already been confirmed to be large enough).
 1060         tmemcpy(aHaystack, result, result_length + 1); // Include the zero terminator.
 1061         free(result); // Free the temp. mem that was used for performance.
 1062     }
 1063     return replacement_count;  // The output parameters have already been populated properly above.
 1064 
 1065 out_of_mem: // This can only happen with the extra-memory method above (which due to its nature can't fall back to the in-place method).
 1066     if (result)
 1067     {
 1068         free(result); // Must be freed in mode #1.  In mode #2, it's probably a non-terminated string (not to mention being an incomplete result), so if it ever isn't freed, it should be terminated.
 1069         result = NULL; // Indicate failure by setting output param for our caller (this also indicates that the memory was freed).
 1070     }
 1071     result_length = 0; // Output parameter for caller, though upon failure it shouldn't matter (just for robustness).
 1072     return 0;
 1073 
 1074 in_place_method:
 1075     // This method is available only to mode #1.  It should help performance for short strings such as those from
 1076     // ExpandExpression().
 1077     // This in-place method is used when the extra-memory method wouldn't be faster enough to be worth its cost
 1078     // for the particular strings involved here.
 1079     //
 1080     // Older comment:
 1081     // The below doesn't quite work when doing a simple replacement such as ".." with ". .".
 1082     // In the above example, "..." would be changed to ". .." rather than ". . ." as it should be.
 1083     // Therefore, use a less efficient, but more accurate method instead.  UPDATE: But this method
 1084     // can cause an infinite loop if the new string is a superset of the old string, so don't use
 1085     // it after all.
 1086     //for ( ; ptr = StrReplace(aHaystack, aOld, aNew, aStringCaseSense); ); // Note that this very different from the below.
 1087 
 1088     for (replacement_count = 0, src = aHaystack
 1089         ; aLimit && (match_pos = tcsstr2(src, aOld, aStringCaseSense)) // Relies on short-circuit boolean order.
 1090         ; --aLimit, ++replacement_count)
 1091     {
 1092         src = match_pos + aNew_length;  // The next search should start at this position when all is adjusted below.
 1093         if (length_delta) // This check can greatly improve performance if old and new strings happen to be same length.
 1094         {
 1095             // Since new string can't fit exactly in place of old string, adjust the target area to
 1096             // accept exactly the right length so that the rest of the string stays unaltered:
 1097             tmemmove(src, match_pos + aOld_length
 1098                 , (haystack_length - (match_pos - aHaystack)) - aOld_length + 1); // +1 to include zero terminator.
 1099             // Above: Calculating length vs. using strlen() makes overall speed of the operation about
 1100             // twice as fast for some typical test cases in a 2 MB buffer such as replacing \r\n with \n.
 1101         }
 1102         tmemcpy(match_pos, aNew, aNew_length); // Perform the replacement.
 1103         // Must keep haystack_length updated as we go, for use with memmove() above:
 1104         haystack_length += length_delta; // Note that length_delta will be negative if aNew is shorter than aOld.
 1105     }
 1106 
 1107     result_length = haystack_length; // Set for caller (it's an alias for an output parameter).
 1108     result = aHaystack; // Not actually needed in this method, so this is just for maintainability.
 1109     return replacement_count;
 1110 }
 1111 
 1112 
 1113 
 1114 size_t PredictReplacementSize(ptrdiff_t aLengthDelta, int aReplacementCount, int aLimit, size_t aHaystackLength
 1115     , size_t aCurrentLength, size_t aEndOffsetOfCurrMatch)
 1116 // Predict how much size the remainder of a replacement operation will consume, including its actual replacements
 1117 // and the parts of haystack that won't need replacement.
 1118 // PARAMETERS:
 1119 // - aLengthDelta: The estimated or actual difference between the length of the replacement and what it's replacing.
 1120 //   A negative number means the replacement is smaller, which will cause a shrinking of the result.
 1121 // - aReplacementCount: The number of replacements so far, including the one the caller is about to do.
 1122 // - aLimit: The *remaining* number of replacements *allowed* (not including the one the caller is about to do).
 1123 // - aHaystackLength: The total length of the original haystack/subject string.
 1124 // - aCurrentLength: The total length of the new/result string including the one the caller is about to do.
 1125 // - aEndOffsetOfCurrMatch: The offset of the char after the last char of the current match.  For example, if
 1126 //   the empty string is the current match and it's found at the beginning of haystack, this value would be 0.
 1127 {
 1128     // Since realloc() is an expensive operation, especially for huge strings, make an extra
 1129     // effort to get a good estimate based on how things have been going so far.
 1130     // While this should definitely improve average-case memory-utilization and usually performance
 1131     // (by avoiding costly realloc's), this estimate is crude because:
 1132     // 1) The length of what is being replaced can vary due to wildcards in pattern, etc.
 1133     // 2) The length of what is replacing it can vary due to backreferences.  Thus, the delta
 1134     //    of each replacement is only a guess based on that of the current replacement.
 1135     // 3) For code simplicity, the number of upcoming replacements isn't yet known; thus a guess
 1136     //    is made based on how many there have been so far compared to percentage complete.
 1137 
 1138     INT_PTR total_delta; // The total increase/decrease in length from the number of predicted additional replacements.
 1139     int repl_multiplier = aLengthDelta < 0 ? -1 : 1; // Negative is used to keep additional_replacements_expected conservative even when delta is negative.
 1140 
 1141     if (aLengthDelta == 0) // Avoid all the calculations because it will wind up being zero anyway.
 1142         total_delta = 0;
 1143     else
 1144     {
 1145         if (!aHaystackLength // aHaystackLength can be 0 if an empty haystack being replaced by something else. If so, avoid divide-by-zero in the prediction by doing something simpler.
 1146             || !aEndOffsetOfCurrMatch)  // i.e. don't the prediction if the current match is the empty string and it was found at the very beginning of Haystack because it would be difficult to be accurate (very rare anyway).
 1147             total_delta = repl_multiplier * aLengthDelta; // Due to rarity, just allow room for one extra after the one we're about to do.
 1148         else // So the above has ensured that the following won't divide by zero anywhere.
 1149         {
 1150             // The following doesn't take into account the original value of aStartingOffset passed in
 1151             // from the caller because:
 1152             // 1) It's pretty rare for it to be greater than 0.
 1153             // 2) Even if it is, the prediction will just be too conservative at first, but that's
 1154             //    pretty harmless; and anyway each successive realloc followed by a match makes the
 1155             //    prediction more and more accurate in spite of aStartingOffset>0.
 1156             // percent_complete must be a double because we need at least 9 digits of precision for cases where
 1157             // 1 is divided by a big number like 1 GB.
 1158             double percent_complete = aEndOffsetOfCurrMatch  // Don't subtract 1 (verified correct).
 1159                 / (double)aHaystackLength; // percent_complete isn't actually a percentage, but a fraction of 1.  e.g. 0.5 rather than 50.
 1160             int additional_replacements_expected = percent_complete >= 1.0 ? 0  // It's often 100% complete, in which case there's hardly ever another replacement after this one (the only possibility is to replace the final empty-string in haystack with something).
 1161                 : (int)(
 1162                 (aReplacementCount / percent_complete) // This is basically "replacements per percentage point, so far".
 1163                 * (1 - percent_complete) // This is the percentage of haystack remaining to be scanned (e.g. 0.5 for 50%).
 1164                 + 1 * repl_multiplier // Add 1 or -1 to make it more conservative (i.e. go the opposite direction of ceil when repl_multiplier is negative).
 1165                 );
 1166             // additional_replacements_expected is defined as the replacements expected *after* the one the caller
 1167             // is about to do.
 1168 
 1169             if (aLimit >= 0 && aLimit < additional_replacements_expected)
 1170             {   // A limit is currently in effect and it's less than expected replacements, so cap the expected.
 1171                 // This helps reduce memory utilization.
 1172                 additional_replacements_expected = aLimit;
 1173             }
 1174             else // No limit or additional_replacements_expected is within the limit.
 1175             {
 1176                 // So now things are set up so that there's about a 50/50 chance than no more reallocs
 1177                 // will be needed.  Since realloc is costly (due to internal memcpy), try to reduce
 1178                 // the odds of it happening without going overboard on memory utilization.
 1179                 // Something a lot more complicated could be used in place of the below to improve things
 1180                 // a little, but it just doesn't seem worth it given the usage patterns expected and
 1181                 // the actual benefits.  Besides, there is some limiting logic further below that will
 1182                 // cap this if it's unreasonably large:
 1183                 additional_replacements_expected += (int)(0.20*additional_replacements_expected + 1) // +1 so that there's always at least one extra.
 1184                     * repl_multiplier; // This keeps the estimate conservative if delta < 0.
 1185             }
 1186             // The following is the "quality" of the estimate.  For example, if this is the very first replacement
 1187             // and 1000 more replacements are predicted, there will often be far fewer than 1000 replacements;
 1188             // in fact, there could well be zero.  So in the below, the quality will range from 1 to 3, where
 1189             // 1 is the worst quality and 3 is the best.
 1190             double quality = 1 + 2*(1-(
 1191                 (double)additional_replacements_expected / (aReplacementCount + additional_replacements_expected)
 1192                 ));
 1193             // It seems best to use whichever of the following is greater in the calculation further below:
 1194             INT_PTR haystack_or_new_length = (aCurrentLength > aHaystackLength) ? aCurrentLength : aHaystackLength;
 1195             // The following is a crude sanity limit to avoid going overboard with memory
 1196             // utilization in extreme cases such as when a big string has many replacements
 1197             // in its first half, but hardly any in its second.  It does the following:
 1198             // 1) When Haystack-or-current length is huge, this tries to keep the portion of the memory increase
 1199             //    that's speculative proportionate to that length, which should reduce the chance of swapping
 1200             //    (at the expense of some performance in cases where it causes another realloc to be required).
 1201             // 2) When Haystack-or-current length is relatively small, allow the speculative memory allocation
 1202             //    to be many times larger than that length because the risk of swapping is low.  HOWEVER, TO
 1203             //    AVOID WASTING MEMORY, the caller should probably call _expand() to shrink the result
 1204             //    when it detects that far fewer replacements were needed than predicted (this is currently
 1205             //    done by Var::AcceptNewMem()).
 1206             INT_PTR total_delta_limit = (INT_PTR)(haystack_or_new_length < 10*1024*1024 ? quality*10*1024*1024
 1207                 : quality*haystack_or_new_length); // See comment above.
 1208             total_delta = additional_replacements_expected
 1209                 * (aLengthDelta < 0 ? -aLengthDelta : aLengthDelta); // So actually, total_delta will be the absolute value.
 1210             if (total_delta > total_delta_limit)
 1211                 total_delta = total_delta_limit;
 1212             total_delta *= repl_multiplier;  // Convert back from absolute value.
 1213         } // The current match isn't an empty string at the very beginning of haystack.
 1214     } // aLengthDelta!=0
 1215 
 1216     // Above is responsible for having set total_delta properly.
 1217     INT_PTR subsequent_length = aHaystackLength - aEndOffsetOfCurrMatch // This is the length of the remaining portion of haystack that might wind up going into the result exactly as-is (adjusted by the below).
 1218         + total_delta; // This is additional_replacements_expected times the expected delta (the length of each replacement minus what it replaces) [can be negative].
 1219     if (subsequent_length < 0) // Must not go below zero because that would cause the next line to
 1220         subsequent_length = 0; // create an increase that's too small to handle the current replacement.
 1221 
 1222     // Return the sum of the following:
 1223     // 1) subsequent_length: The predicted length needed for the remainder of the operation.
 1224     // 2) aCurrentLength: The amount we need now, which includes room for the replacement the caller is about to do.
 1225     //    Note that aCurrentLength can be 0 (such as for an empty string replacement).
 1226     return subsequent_length + aCurrentLength + 1; // Caller relies on +1 for the terminator.
 1227 }
 1228 
 1229 
 1230 
 1231 LPTSTR TranslateLFtoCRLF(LPTSTR aString)
 1232 // Can't use StrReplace() for this because any CRLFs originally present in aString are not changed (i.e. they
 1233 // don't become CRCRLF) [there may be other reasons].
 1234 // Translates any naked LFs in aString to CRLF.  If there are none, the original string is returned.
 1235 // Otherwise, the translated version is copied into a malloc'd buffer, which the caller must free
 1236 // when it's done with it).  
 1237 {
 1238     UINT naked_LF_count = 0;
 1239     size_t length = 0;
 1240     LPTSTR cp;
 1241 
 1242     for (cp = aString; *cp; ++cp)
 1243     {
 1244         ++length;
 1245         if (*cp == '\n' && (cp == aString || cp[-1] != '\r')) // Relies on short-circuit boolean order.
 1246             ++naked_LF_count;
 1247     }
 1248 
 1249     if (!naked_LF_count)
 1250         return aString;  // The original string is returned, which the caller must check for (vs. new string).
 1251 
 1252     // Allocate the new memory that will become the caller's responsibility:
 1253     LPTSTR buf = (LPTSTR)tmalloc(length + naked_LF_count + 1);  // +1 for zero terminator.
 1254     if (!buf)
 1255         return NULL;
 1256 
 1257     // Now perform the translation.
 1258     LPTSTR dp = buf; // Destination.
 1259     for (cp = aString; *cp; ++cp)
 1260     {
 1261         if (*cp == '\n' && (cp == aString || cp[-1] != '\r')) // Relies on short-circuit boolean order.
 1262             *dp++ = '\r';  // Insert an extra CR here, then insert the '\n' normally below.
 1263         *dp++ = *cp;
 1264     }
 1265     *dp = '\0';  // Final terminator.
 1266 
 1267     return buf;  // Caller must free it when it's done with it.
 1268 }
 1269 
 1270 
 1271 
 1272 bool DoesFilePatternExist(LPTSTR aFilePattern, DWORD *aFileAttr)
 1273 // Returns true if the file/folder exists or false otherwise.
 1274 // If non-NULL, aFileAttr's DWORD is set to the attributes of the file/folder if a match is found.
 1275 // If there is no match, its contents are undefined.
 1276 {
 1277     if (!aFilePattern || !*aFilePattern) return false;
 1278     // Fix for v1.0.35.12: Don't consider the question mark in "\\?\Volume{GUID}\" to be a wildcard.
 1279     // Such volume names are obtained from GetVolumeNameForVolumeMountPoint() and perhaps other functions.
 1280     // However, testing shows that wildcards beyond that first one should be seen as real wildcards
 1281     // because the wildcard match-method below does work for such volume names.
 1282     LPTSTR cp = _tcsncmp(aFilePattern, _T("\\\\?\\"), 4) ? aFilePattern : aFilePattern + 4;
 1283     if (StrChrAny(cp, _T("?*")))
 1284     {
 1285         WIN32_FIND_DATA wfd;
 1286         HANDLE hFile = FindFirstFile(aFilePattern, &wfd);
 1287         if (hFile == INVALID_HANDLE_VALUE)
 1288             return false;
 1289         FindClose(hFile);
 1290         if (aFileAttr)
 1291             *aFileAttr = wfd.dwFileAttributes;
 1292         return true;
 1293     }
 1294     else
 1295     {
 1296         DWORD attr = GetFileAttributes(aFilePattern);
 1297         if (aFileAttr)
 1298             *aFileAttr = attr;
 1299         return attr != 0xFFFFFFFF;
 1300     }
 1301 }
 1302 
 1303 
 1304 
 1305 #ifdef _DEBUG
 1306 ResultType FileAppend(LPTSTR aFilespec, LPTSTR aLine, bool aAppendNewline)
 1307 {
 1308     if (!aFilespec || !aLine) return FAIL;
 1309     if (!*aFilespec) return FAIL;
 1310     FILE *fp = _tfopen(aFilespec, _T("a"));
 1311     if (fp == NULL)
 1312         return FAIL;
 1313     _fputts(aLine, fp);
 1314     if (aAppendNewline)
 1315         _puttc('\n', fp);
 1316     fclose(fp);
 1317     return OK;
 1318 }
 1319 #endif
 1320 
 1321 
 1322 
 1323 LPTSTR ConvertFilespecToCorrectCase(LPTSTR aFilespec, LPTSTR aBuf, size_t aBufSize, size_t &aBufLength)
 1324 // Convert aFilespec to proper case and put the result into aBuf.
 1325 // aFilespec and aBuf must not overlap.
 1326 // aFilespec should be modifiable, but on return always has its original value.
 1327 // aBufSize is the size of aBuf in WCHARs, including space for the null-terminator;
 1328 // it should be large enough to allow expansion of short (8.3) names to long names.
 1329 // If the final path would exceed aBufSize or if the conversion could not be completed,
 1330 // returns NULL and leaves aBufLength unchanged; otherwise returns aBuf and sets
 1331 // aBufLength to its length.
 1332 // Note: GetFullPathName() doesn't perform case-correction, only string manipulation.
 1333 // GetLongPathName() skips name components which are not 8.3-compliant.
 1334 {
 1335     ASSERT(aBufSize > 3);
 1336     ASSERT(aFilespec != aBuf);
 1337     if (!*aFilespec)
 1338         return NULL;
 1339     LPTSTR dir_start, dir_end;
 1340     size_t built_length;
 1341     // Start with something easy, the drive letter:
 1342     if (aFilespec[1] == ':' && aFilespec[2] == '\\')
 1343     {
 1344         aBuf[0] = ctoupper(aFilespec[0]);
 1345         aBuf[1] = ':';
 1346         aBuf[2] = '\\';
 1347         // MSDN: "An attempt to open a search with a trailing backslash will always fail."
 1348         dir_start = aFilespec + 3; // Skip over the first backslash that goes with the drive letter.
 1349         built_length = 3;
 1350     }
 1351     else // it's probably a UNC
 1352     {
 1353         if (_tcsncmp(aFilespec, _T("\\\\"), 2))
 1354             // It doesn't appear to be a UNC either, so not sure how to deal with it.
 1355             return NULL;
 1356         // I think MS says you can't use FindFirstFile() directly on a share name, so we
 1357         // want to omit both that and the server name from consideration (i.e. we don't attempt
 1358         // to find their proper case).  MSDN: "Similarly, on network shares, you can use an
 1359         // lpFileName of the form "\\server\service\*" but you cannot use an lpFileName that
 1360         // points to the share itself, such as "\\server\service".
 1361         dir_start = aFilespec + 2;
 1362         LPTSTR end_of_server_name = _tcschr(dir_start, '\\');
 1363         if (end_of_server_name)
 1364         {
 1365             dir_start = end_of_server_name + 1;
 1366             LPTSTR end_of_share_name = _tcschr(dir_start, '\\');
 1367             if (end_of_share_name)
 1368                 dir_start = end_of_share_name + 1;
 1369         }
 1370         built_length = dir_start - aFilespec;
 1371         if (built_length >= aBufSize) // Too long.
 1372             return NULL;
 1373         tmemcpy(aBuf, aFilespec, built_length);
 1374     }
 1375     WIN32_FIND_DATA found_file;
 1376     size_t found_length;
 1377     HANDLE file_search;
 1378     for ( ; dir_end = _tcschr(dir_start, '\\'); dir_start = dir_end + 1)
 1379     {
 1380         *dir_end = '\0';  // Temporarily terminate.
 1381         file_search = FindFirstFile(aFilespec, &found_file);
 1382         *dir_end = '\\'; // Restore it before we do anything else.
 1383         if (file_search == INVALID_HANDLE_VALUE)
 1384             return NULL;
 1385         FindClose(file_search);
 1386         // Append the case-corrected version of this directory name:
 1387         found_length = _tcslen(found_file.cFileName);
 1388         if (built_length + found_length + 1 > aBufSize) // Too long (+1 for the slash).
 1389             return NULL;
 1390         tmemcpy(aBuf + built_length, found_file.cFileName, found_length);
 1391         built_length += found_length;
 1392         aBuf[built_length++] = '\\';
 1393     }
 1394     if (*dir_start) // Not a path ending in '\\'.
 1395     {
 1396         // Now do the filename itself:
 1397         if (   (file_search = FindFirstFile(aFilespec, &found_file)) == INVALID_HANDLE_VALUE   )
 1398             return NULL;
 1399         FindClose(file_search);
 1400         found_length = _tcslen(found_file.cFileName);
 1401         if (built_length + found_length > aBufSize) // Too long.
 1402             return NULL;
 1403         tmemcpy(aBuf + built_length, found_file.cFileName, found_length);
 1404         built_length += found_length;
 1405     }
 1406     aBuf[built_length] = '\0';
 1407     aBufLength = built_length;
 1408     return aBuf;
 1409 }
 1410 
 1411 
 1412 
 1413 void ConvertFilespecToCorrectCase(LPTSTR aBuf, size_t aBufSize, size_t &aBufLength)
 1414 {
 1415     TCHAR built_filespec[T_MAX_PATH];
 1416     if (aBufSize > _countof(built_filespec))
 1417         aBufSize = _countof(built_filespec);
 1418     if (ConvertFilespecToCorrectCase(aBuf, built_filespec, aBufSize, aBufLength))
 1419         tmemcpy(aBuf, built_filespec, aBufLength + 1);
 1420 }
 1421 
 1422 
 1423 
 1424 LPTSTR FileAttribToStr(LPTSTR aBuf, DWORD aAttr)
 1425 // Caller must ensure that aAttr is valid (i.e. that it's not 0xFFFFFFFF).
 1426 {
 1427     if (!aBuf) return aBuf;
 1428     int length = 0;
 1429     if (aAttr & FILE_ATTRIBUTE_READONLY)
 1430         aBuf[length++] = 'R';
 1431     if (aAttr & FILE_ATTRIBUTE_ARCHIVE)
 1432         aBuf[length++] = 'A';
 1433     if (aAttr & FILE_ATTRIBUTE_SYSTEM)
 1434         aBuf[length++] = 'S';
 1435     if (aAttr & FILE_ATTRIBUTE_HIDDEN)
 1436         aBuf[length++] = 'H';
 1437     if (aAttr & FILE_ATTRIBUTE_NORMAL)
 1438         aBuf[length++] = 'N';
 1439     if (aAttr & FILE_ATTRIBUTE_DIRECTORY)
 1440         aBuf[length++] = 'D';
 1441     if (aAttr & FILE_ATTRIBUTE_OFFLINE)
 1442         aBuf[length++] = 'O';
 1443     if (aAttr & FILE_ATTRIBUTE_COMPRESSED)
 1444         aBuf[length++] = 'C';
 1445     if (aAttr & FILE_ATTRIBUTE_TEMPORARY)
 1446         aBuf[length++] = 'T';
 1447     aBuf[length] = '\0';  // Perform the final termination.
 1448     return aBuf;
 1449 }
 1450 
 1451 
 1452 
 1453 unsigned __int64 GetFileSize64(HANDLE aFileHandle)
 1454 // Returns ULLONG_MAX on failure.  Otherwise, it returns the actual file size.
 1455 {
 1456     ULARGE_INTEGER ui = {0};
 1457     ui.LowPart = GetFileSize(aFileHandle, &ui.HighPart);
 1458     if (ui.LowPart == MAXDWORD && GetLastError() != NO_ERROR)
 1459         return ULLONG_MAX;
 1460     return (unsigned __int64)ui.QuadPart;
 1461 }
 1462 
 1463 
 1464 
 1465 LPTSTR GetWin32ErrorText(LPTSTR aBuf, DWORD aBufSize, DWORD aError)
 1466 // aBufSize is an int to preserve any negative values the caller might pass in.
 1467 {
 1468     if (aBufSize < 1)
 1469         return aBuf;
 1470     if (aBufSize == 1)
 1471     {
 1472         *aBuf = '\0';
 1473         return aBuf;
 1474     }
 1475     FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM|FORMAT_MESSAGE_IGNORE_INSERTS // Ignore inserts: https://blogs.msdn.microsoft.com/oldnewthing/20071128-00/?p=24353
 1476         , NULL, aError, 0, aBuf, (DWORD)aBufSize - 1, NULL);
 1477     return aBuf;
 1478 }
 1479 
 1480 
 1481 
 1482 void AssignColor(LPTSTR aColorName, COLORREF &aColor, HBRUSH &aBrush)
 1483 // Assign the color indicated in aColorName (either a name or a hex RGB value) to both
 1484 // aColor and aBrush, deleting any prior handle in aBrush first.  If the color cannot
 1485 // be determined, it will always be set to CLR_DEFAULT (and aBrush set to NULL to match).
 1486 // It will never be set to CLR_NONE.
 1487 {
 1488     COLORREF color;
 1489     if (!*aColorName)
 1490         color = CLR_DEFAULT;
 1491     else
 1492     {
 1493         color = ColorNameToBGR(aColorName);
 1494         if (color == CLR_NONE) // A matching color name was not found, so assume it's a hex color value.
 1495             // It seems strtol() automatically handles the optional leading "0x" if present:
 1496             color = rgb_to_bgr(_tcstol(aColorName, NULL, 16));
 1497             // if aColorName does not contain something hex-numeric, black (0x00) will be assumed,
 1498             // which seems okay given how rare such a problem would be.
 1499     }
 1500     if (color != aColor) // It's not already the right color.
 1501     {
 1502         aColor = color; // Set default.  v1.0.44.09: Added this line to fix the inability to change to a previously selected color after having changed to the default color.
 1503         if (aBrush) // Free the resources of the old brush.
 1504             DeleteObject(aBrush);
 1505         if (color == CLR_DEFAULT) // Caller doesn't need brush for CLR_DEFAULT, assuming that's even possible.
 1506             aBrush = NULL;
 1507         else
 1508             if (   !(aBrush = CreateSolidBrush(color))   ) // Failure should be very rare.
 1509                 aColor = CLR_DEFAULT; // A NULL HBRUSH should always corresponds to CLR_DEFAULT.
 1510     }
 1511 }
 1512 
 1513 
 1514 
 1515 COLORREF ColorNameToBGR(LPTSTR aColorName)
 1516 // These are the main HTML color names.  Returns CLR_NONE if a matching HTML color name can't be found.
 1517 // Returns CLR_DEFAULT only if aColorName is the word Default.
 1518 {
 1519     if (!aColorName || !*aColorName) return CLR_NONE;
 1520     if (!_tcsicmp(aColorName, _T("Black")))  return 0x000000;  // These colors are all in BGR format, not RGB.
 1521     if (!_tcsicmp(aColorName, _T("Silver"))) return 0xC0C0C0;
 1522     if (!_tcsicmp(aColorName, _T("Gray")))   return 0x808080;
 1523     if (!_tcsicmp(aColorName, _T("White")))  return 0xFFFFFF;
 1524     if (!_tcsicmp(aColorName, _T("Maroon"))) return 0x000080;
 1525     if (!_tcsicmp(aColorName, _T("Red")))    return 0x0000FF;
 1526     if (!_tcsicmp(aColorName, _T("Purple"))) return 0x800080;
 1527     if (!_tcsicmp(aColorName, _T("Fuchsia")))return 0xFF00FF;
 1528     if (!_tcsicmp(aColorName, _T("Green")))  return 0x008000;
 1529     if (!_tcsicmp(aColorName, _T("Lime")))   return 0x00FF00;
 1530     if (!_tcsicmp(aColorName, _T("Olive")))  return 0x008080;
 1531     if (!_tcsicmp(aColorName, _T("Yellow"))) return 0x00FFFF;
 1532     if (!_tcsicmp(aColorName, _T("Navy")))   return 0x800000;
 1533     if (!_tcsicmp(aColorName, _T("Blue")))   return 0xFF0000;
 1534     if (!_tcsicmp(aColorName, _T("Teal")))   return 0x808000;
 1535     if (!_tcsicmp(aColorName, _T("Aqua")))   return 0xFFFF00;
 1536     if (!_tcsicmp(aColorName, _T("Default")))return CLR_DEFAULT;
 1537     return CLR_NONE;
 1538 }
 1539 
 1540 
 1541 
 1542 POINT CenterWindow(int aWidth, int aHeight)
 1543 // Given a the window's width and height, calculates where to position its upper-left corner
 1544 // so that it is centered EVEN IF the task bar is on the left side or top side of the window.
 1545 // This does not currently handle multi-monitor systems explicitly, since those calculations
 1546 // require API functions that don't exist in Win95/NT (and thus would have to be loaded
 1547 // dynamically to allow the program to launch).  Therefore, windows will likely wind up
 1548 // being centered across the total dimensions of all monitors, which usually results in
 1549 // half being on one monitor and half in the other.  This doesn't seem too terrible and
 1550 // might even be what the user wants in some cases (i.e. for really big windows).
 1551 {
 1552     RECT rect;
 1553     SystemParametersInfo(SPI_GETWORKAREA, 0, &rect, 0);  // Get desktop rect excluding task bar.
 1554     // Note that rect.left will NOT be zero if the taskbar is on docked on the left.
 1555     // Similarly, rect.top will NOT be zero if the taskbar is on docked at the top of the screen.
 1556     POINT pt;
 1557     pt.x = rect.left + (((rect.right - rect.left) - aWidth) / 2);
 1558     pt.y = rect.top + (((rect.bottom - rect.top) - aHeight) / 2);
 1559     return pt;
 1560 }
 1561 
 1562 
 1563 
 1564 bool FontExist(HDC aHdc, LPCTSTR aTypeface)
 1565 {
 1566     LOGFONT lf;
 1567     lf.lfCharSet = DEFAULT_CHARSET;  // Enumerate all char sets.
 1568     lf.lfPitchAndFamily = 0;  // Must be zero.
 1569     tcslcpy(lf.lfFaceName, aTypeface, LF_FACESIZE);
 1570     bool font_exists = false;
 1571     EnumFontFamiliesEx(aHdc, &lf, (FONTENUMPROC)FontEnumProc, (LPARAM)&font_exists, 0);
 1572     return font_exists;
 1573 }
 1574 
 1575 
 1576 
 1577 int CALLBACK FontEnumProc(ENUMLOGFONTEX *lpelfe, NEWTEXTMETRICEX *lpntme, DWORD FontType, LPARAM lParam)
 1578 {
 1579     *(bool *)lParam = true; // Indicate to the caller that the font exists.
 1580     return 0;  // Stop the enumeration after the first, since even one match means the font exists.
 1581 }
 1582 
 1583 
 1584 
 1585 void ScreenToWindow(POINT &aPoint, HWND aHwnd)
 1586 // Convert screen coordinates to window coordinates (i.e. relative to the window's upper-left corner).
 1587 {
 1588     RECT rect;
 1589     GetWindowRect(aHwnd, &rect);
 1590     aPoint.x -= rect.left;
 1591     aPoint.y -= rect.top;
 1592 }
 1593 
 1594 
 1595 
 1596 void CoordToScreen(int &aX, int &aY, int aWhichMode)
 1597 // aX and aY are interpreted according to the current coord mode.  If necessary, they are converted to
 1598 // screen coordinates based on the position of the active window's upper-left corner (or its client area).
 1599 {
 1600     int coord_mode = ((g->CoordMode >> aWhichMode) & COORD_MODE_MASK);
 1601 
 1602     if (coord_mode == COORD_MODE_SCREEN)
 1603         return;
 1604 
 1605     HWND active_window = GetForegroundWindow();
 1606     if (active_window && !IsIconic(active_window))
 1607     {
 1608         if (coord_mode == COORD_MODE_WINDOW)
 1609         {
 1610             RECT rect;
 1611             if (GetWindowRect(active_window, &rect))
 1612             {
 1613                 aX += rect.left;
 1614                 aY += rect.top;
 1615             }
 1616         }
 1617         else // (coord_mode == COORD_MODE_CLIENT)
 1618         {
 1619             POINT pt = {0};
 1620             if (ClientToScreen(active_window, &pt))
 1621             {
 1622                 aX += pt.x;
 1623                 aY += pt.y;
 1624             }
 1625         }
 1626     }
 1627     //else no active window per se, so don't convert the coordinates.  Leave them as-is as desired
 1628     // by the caller.  More details:
 1629     // Revert to screen coordinates if the foreground window is minimized.  Although it might be
 1630     // impossible for a visible window to be both foreground and minimized, it seems that hidden
 1631     // windows -- such as the script's own main window when activated for the purpose of showing
 1632     // a popup menu -- can be foreground while simultaneously being minimized.  This fixes an
 1633     // issue where the mouse will move to the upper-left corner of the screen rather than the
 1634     // intended coordinates (v1.0.17).
 1635 }
 1636 
 1637 
 1638 
 1639 void CoordToScreen(POINT &aPoint, int aWhichMode)
 1640 // For convenience. See function above for comments.
 1641 {
 1642     CoordToScreen((int &)aPoint.x, (int &)aPoint.y, aWhichMode);
 1643 }
 1644 
 1645 
 1646 
 1647 void GetVirtualDesktopRect(RECT &aRect)
 1648 {
 1649     aRect.right = GetSystemMetrics(SM_CXVIRTUALSCREEN);
 1650     if (aRect.right) // A non-zero value indicates the OS supports multiple monitors or at least SM_CXVIRTUALSCREEN.
 1651     {
 1652         aRect.left = GetSystemMetrics(SM_XVIRTUALSCREEN);  // Might be negative or greater than zero.
 1653         aRect.right += aRect.left;
 1654         aRect.top = GetSystemMetrics(SM_YVIRTUALSCREEN);   // Might be negative or greater than zero.
 1655         aRect.bottom = aRect.top + GetSystemMetrics(SM_CYVIRTUALSCREEN);
 1656     }
 1657     else // Win95/NT do not support SM_CXVIRTUALSCREEN and such, so zero was returned.
 1658         GetWindowRect(GetDesktopWindow(), &aRect);
 1659 }
 1660 
 1661 
 1662 
 1663 DWORD GetEnvVarReliable(LPCTSTR aEnvVarName, LPTSTR aBuf)
 1664 // Returns the length of what has been copied into aBuf.
 1665 // Caller has ensured that aBuf is large enough (though anything >=32767 is always large enough).
 1666 // This function was added in v1.0.46.08 to fix a long-standing bug that was more fully revealed
 1667 // by 1.0.46.07's reduction of DEREF_BUF_EXPAND_INCREMENT from 32 to 16K (which allowed the Win9x
 1668 // version of GetEnvironmentVariable() to detect that we were lying about the buffer being 32767
 1669 // in size).  The reason for lying is that we don't know exactly how big the buffer is, but we do
 1670 // know it's large enough. So we just pass 32767 in an attempt to make it always succeed
 1671 // (mostly because GetEnvironmentVariable() is such a slow call, so it's best to avoid calling it
 1672 // a second time just to get the length).
 1673 // UPDATE: This is now called for all versions of Windows to avoid any chance of crashing or misbehavior,
 1674 // which tends to happen whenever lying to the API (even if it's for a good cause).  See similar problems
 1675 // at ReadRegString(). See other comments below.
 1676 {
 1677     // Windows 9x is apparently capable of detecting a lie about the buffer size.
 1678     // For example, if the memory capacity is only 16K but we pass 32767, it sometimes/always detects that
 1679     // and returns 0, even if the string being retrieved is short enough (which it is because the caller
 1680     // already verified it).  To work around this, give it a genuinely large buffer with an accurate size,
 1681     // then copy the result out into the caller's variable.  This is almost certainly much faster than
 1682     // doing a second call to GetEnvironmentVariable() to get the length because GetEnv() is known to be a
 1683     // very slow call.
 1684     //
 1685     // Don't use a size greater than 32767 because that will cause it to fail on Win95 (tested by Robert Yalkin).
 1686     // According to MSDN, 32767 is exactly large enough to handle the largest variable plus its zero terminator.
 1687     TCHAR buf[32767];
 1688     DWORD length = GetEnvironmentVariable(aEnvVarName, buf, _countof(buf));
 1689     // GetEnvironmentVariable() could be called twice, the first time to get the actual size.  But that would
 1690     // probably perform worse since GetEnvironmentVariable() is a very slow function.  In addition, it would
 1691     // add code complexity, so it seems best to fetch it into a large buffer then just copy it to dest-var.
 1692     if (length) // Probably always true under the conditions in effect for our callers.
 1693         tmemcpy(aBuf, buf, length + 1); // memcpy() usually benches a little faster than strcpy().
 1694     else // Failure. The buffer's contents might be undefined in this case.
 1695         *aBuf = '\0'; // Caller's buf should always have room for an empty string. So make it empty for maintainability, even if not strictly required by caller.
 1696     return length;
 1697 }
 1698 
 1699 
 1700 
 1701 DWORD ReadRegString(HKEY aRootKey, LPTSTR aSubkey, LPTSTR aValueName, LPTSTR aBuf, DWORD aBufSize, DWORD aFlag)
 1702 // Returns the length of the string (0 if empty).
 1703 // Caller must ensure that size of aBuf is REALLY aBufSize (even when it knows aBufSize is more than
 1704 // it needs) because the API apparently reads/writes parts of the buffer beyond the string it writes!
 1705 // Caller must ensure that aBuf isn't NULL because it doesn't seem worth having a "give me the size only" mode.
 1706 // This is because the API might return a size that omits the zero terminator, and the only way to find out for
 1707 // sure is probably to actually fetch the data and check if the terminator is present.
 1708 {
 1709     HKEY hkey;
 1710     if (RegOpenKeyEx(aRootKey, aSubkey, 0, KEY_QUERY_VALUE | aFlag, &hkey) != ERROR_SUCCESS)
 1711     {
 1712         *aBuf = '\0';
 1713         return 0;
 1714     }
 1715     DWORD buf_size = aBufSize * sizeof(TCHAR); // Caller's value might be a constant memory area, so need a modifiable copy.
 1716     LONG result = RegQueryValueEx(hkey, aValueName, NULL, NULL, (LPBYTE)aBuf, &buf_size);
 1717     RegCloseKey(hkey);
 1718     if (result != ERROR_SUCCESS || !buf_size) // Relies on short-circuit boolean order.
 1719     {
 1720         *aBuf = '\0'; // MSDN says the contents of the buffer is undefined after the call in some cases, so reset it.
 1721         return 0;
 1722     }
 1723     buf_size /= sizeof(TCHAR); // RegQueryValueEx returns size in bytes.
 1724     // Otherwise success and non-empty result.  This also means that buf_size is accurate and <= to what we sent in.
 1725     // Fix for v1.0.47: ENSURE PROPER STRING TERMINATION. This is suspected to be a source of crashing.
 1726     // MSDN: "If the data has the REG_SZ, REG_MULTI_SZ or REG_EXPAND_SZ type, the string may not have been
 1727     // stored with the proper null-terminating characters. Therefore, even if the function returns
 1728     // ERROR_SUCCESS, the application should ensure that the string is properly terminated before using
 1729     // it; otherwise, it may overwrite a buffer. (Note that REG_MULTI_SZ strings should have two
 1730     // null-terminating characters.)"
 1731     // MSDN: "If the data has the REG_SZ, REG_MULTI_SZ or REG_EXPAND_SZ type, this size includes any
 1732     // terminating null character or characters."
 1733     --buf_size; // Convert to the index of the last character written.  This is safe because above already checked that buf_size>0.
 1734     if (aBuf[buf_size] == '\0') // It wrote at least one zero terminator (it might write more than one for Unicode, or if it's simply stored with more than one in the registry).
 1735     {
 1736         while (buf_size && !aBuf[buf_size - 1]) // Scan leftward in case more than one consecutive terminator.
 1737             --buf_size;
 1738         return buf_size; // There's a tiny chance that this could the wrong length, namely when the string contains binary zero(s) to the left of non-zero characters.  But that seems too rare to be worth calling strlen() for.
 1739     }
 1740     // Otherwise, it didn't write a terminator, so provide one.
 1741     ++buf_size; // To reflect the fact that we're about to write an extra char.
 1742     if (buf_size >= aBufSize) // There's no room for a terminator without truncating the data (very rare).  Seems best to indicate failure.
 1743     {
 1744         *aBuf = '\0';
 1745         return 0;
 1746     }
 1747     // Otherwise, there's room for the terminator.
 1748     aBuf[buf_size] = '\0';
 1749     return buf_size; // There's a tiny chance that this could the wrong length, namely when the string contains binary zero(s) to the left of non-zero characters.  But that seems too rare to be worth calling strlen() for.
 1750 }
 1751 
 1752 
 1753 
 1754 #ifndef _WIN64
 1755 // Load function dynamically to allow the program to launch on Win2k/XPSP1:
 1756 typedef BOOL (WINAPI *PFN_IsWow64Process)(HANDLE, PBOOL);
 1757 static PFN_IsWow64Process _IsWow64Process = (PFN_IsWow64Process)GetProcAddress(GetModuleHandle(_T("kernel32"))
 1758     , "IsWow64Process");
 1759 #endif
 1760 
 1761 BOOL IsProcess64Bit(HANDLE aHandle)
 1762 {
 1763     BOOL is32on64;
 1764 #ifdef _WIN64
 1765     // No need to load the function dynamically in this case since it should exist on all OSes
 1766     // which are able to load 64-bit executables (such as ours):
 1767     if (IsWow64Process(aHandle, &is32on64))
 1768         return !is32on64; // 64-bit if not running under WOW64.
 1769     // Since above didn't return, an error occurred.  MSDN isn't clear about what conditions can
 1770     // cause this, so for simplicity just assume the target process is 64-bit (like this one).
 1771     return TRUE;
 1772 #else
 1773     if (_IsWow64Process && _IsWow64Process(GetCurrentProcess(), &is32on64))
 1774     {
 1775         if (is32on64)
 1776         {
 1777             // We're running under WOW64.  Since WOW64 only exists on 64-bit systems and on such systems
 1778             // 32-bit processes can run ONLY under WOW64, if the target process is also running under
 1779             // WOW64 it must be 32-bit; otherwise it must be 64-bit.
 1780             if (_IsWow64Process(aHandle, &is32on64))
 1781                 return !is32on64;
 1782         }
 1783     }
 1784     // Since above didn't return, one of the following is true:
 1785     //  a) IsWow64Process doesn't exist, so the OS and all running processes must be 32-bit.
 1786     //  b) IsWow64Process failed on the first or second call.  MSDN isn't clear about what conditions
 1787     //     can cause this, so for simplicity just assume the target process is 32-bit (like this one).
 1788     //  c) The current process is not running under WOW64.  Since we know it is 32-bit (due to our use
 1789     //     of conditional compilation), the OS and all running processes must be 32-bit.
 1790     return FALSE;
 1791 #endif
 1792 }
 1793 
 1794 BOOL IsOS64Bit()
 1795 {
 1796 #ifdef _WIN64
 1797     // OS must be 64-bit to run this program.
 1798     return TRUE;
 1799 #else
 1800     // If OS is 64-bit, this program must be running in WOW64.
 1801     BOOL is32on64;
 1802     if (_IsWow64Process && _IsWow64Process(GetCurrentProcess(), &is32on64))
 1803         return is32on64;
 1804     return FALSE;
 1805 #endif
 1806 }
 1807 
 1808 
 1809 
 1810 LPVOID AllocInterProcMem(HANDLE &aHandle, DWORD aSize, HWND aHwnd, DWORD aExtraAccess)
 1811 // aHandle is an output parameter that receives the process handle.
 1812 // Returns NULL on failure (in which case caller should ignore the value of aHandle).
 1813 {
 1814     LPVOID mem;
 1815     DWORD pid;
 1816     GetWindowThreadProcessId(aHwnd, &pid);
 1817     // Even if the PID is our own, open the process anyway to simplify the code. After all, it would be
 1818     // pretty silly for a script to access its own ListViews via this method.
 1819     if (   !(aHandle = OpenProcess(PROCESS_VM_OPERATION | PROCESS_VM_READ | PROCESS_VM_WRITE | aExtraAccess, FALSE, pid))   )
 1820         return NULL; // Let ErrorLevel tell the story.
 1821     // Reason for using VirtualAllocEx(): When sending LVITEM structures to a control in a remote process, the
 1822     // structure and its pszText buffer must both be memory inside the remote process rather than in our own.
 1823     mem = VirtualAllocEx(aHandle, NULL, aSize, MEM_RESERVE | MEM_COMMIT, PAGE_READWRITE);
 1824     if (!mem)
 1825         CloseHandle(aHandle); // Caller should ignore the value of aHandle when return value is NULL.
 1826     //else leave the handle open.  It's the caller's responsibility to close it.
 1827     return mem;
 1828 }
 1829 
 1830 
 1831 
 1832 void FreeInterProcMem(HANDLE aHandle, LPVOID aMem)
 1833 {
 1834     VirtualFreeEx(aHandle, aMem, 0, MEM_RELEASE); // Size 0 is used with MEM_RELEASE.
 1835     CloseHandle(aHandle);
 1836 }
 1837 
 1838 
 1839 
 1840 HBITMAP LoadPicture(LPTSTR aFilespec, int aWidth, int aHeight, int &aImageType, int aIconNumber
 1841     , bool aUseGDIPlusIfAvailable, bool *apNoDelete, HMODULE *apModule)
 1842 // Returns NULL on failure.
 1843 // If aIconNumber > 0, an HICON or HCURSOR is returned (both should be interchangeable), never an HBITMAP.
 1844 // However, aIconNumber==1 is treated as a special icon upon which LoadImage is given preference over ExtractIcon
 1845 // for .ico/.cur/.ani files.
 1846 // Otherwise, .ico/.cur/.ani files are normally loaded as HICON (unless aUseGDIPlusIfAvailable is true or
 1847 // something else unusual happened such as file contents not matching file's extension).  This is done to preserve
 1848 // any properties that HICONs have but HBITMAPs lack, namely the ability to be animated and perhaps other things.
 1849 //
 1850 // Loads a JPG/GIF/BMP/ICO/etc. and returns an HBITMAP or HICON to the caller (which it may call
 1851 // DeleteObject()/DestroyIcon() upon, though upon program termination all such handles are freed
 1852 // automatically).  The image is scaled to the specified width and height.  If zero is specified
 1853 // for either, the image's actual size will be used for that dimension.  If -1 is specified for one,
 1854 // that dimension will be kept proportional to the other dimension's size so that the original aspect
 1855 // ratio is retained.
 1856 {
 1857     HBITMAP hbitmap = NULL;
 1858     aImageType = -1; // The type of image currently inside hbitmap.  Set default value for output parameter as "unknown".
 1859     if (apNoDelete)
 1860         *apNoDelete = false; // Set default.
 1861 
 1862     if (!*aFilespec) // Allow blank filename to yield NULL bitmap (and currently, some callers do call it this way).
 1863         return NULL;
 1864     // Lexikos: Negative values now indicate an icon's integer resource ID.
 1865     //if (aIconNumber < 0) // Allowed to be called this way by GUI and others (to avoid need for validation of user input there).
 1866     //  aIconNumber = 0; // Use the default behavior, which is "load icon or bitmap, whichever is most appropriate".
 1867 
 1868     bool script_passed_handle = false, script_owns_handle = false;
 1869     if (   !_tcsnicmp(aFilespec, _T("hicon:"), 6)
 1870         || !_tcsnicmp(aFilespec, _T("hbitmap:"), 8)   )
 1871     {
 1872         if (aFilespec[5] == ':') // hicon:
 1873         {
 1874             aImageType = IMAGE_ICON;
 1875             aFilespec += 6;
 1876         }
 1877         else
 1878         {
 1879             aImageType = IMAGE_BITMAP;
 1880             aFilespec += 8;
 1881         }
 1882         script_passed_handle = true;
 1883         script_owns_handle = (*aFilespec == '*'); // The "don't delete my icon/bitmap" flag.
 1884         if (script_owns_handle)
 1885         {
 1886             ++aFilespec;
 1887             if (apNoDelete) // Caller supports conditional delete.
 1888                 *apNoDelete = true; // May be overridden if a resized copy is created below.
 1889         }
 1890         hbitmap = (HBITMAP)(UINT_PTR)ATOI64(aFilespec);
 1891         if (!hbitmap)
 1892             return NULL;
 1893     }
 1894 
 1895     LPTSTR file_ext = _tcsrchr(aFilespec, '.');
 1896     if (file_ext)
 1897         ++file_ext;
 1898 
 1899     // v1.0.43.07: If aIconNumber is zero, caller didn't specify whether it wanted an icon or bitmap.  Thus,
 1900     // there must be some kind of detection for whether ExtractIcon is needed instead of GDIPlus/OleLoadPicture.
 1901     // Although this could be done by attempting ExtractIcon only after GDIPlus/OleLoadPicture fails (or by
 1902     // somehow checking the internal nature of the file), for performance and code size, it seems best to not
 1903     // to incur this extra I/O and instead make only one attempt based on the file's extension.
 1904     // Must use ExtractIcon() if either of the following is true:
 1905     // 1) Caller gave an icon index of the second or higher icon in the file.  Update for v1.0.43.05: There
 1906     //    doesn't seem to be any reason to allow a caller to explicitly specify ExtractIcon as the method of
 1907     //    loading the *first* icon from a .ico file since LoadImage is likely always superior.  This is
 1908     //    because unlike ExtractIcon/Ex, LoadImage: 1) Doesn't distort icons, especially 16x16 icons; 2) is
 1909     //    capable of loading icons other than the first by means of width and height parameters.
 1910     // 2) The target file is of type EXE/DLL/ICL/CPL/etc. (LoadImage() is documented not to work on those file types).
 1911     //    ICL files (v1.0.43.05): Apparently ICL files are an unofficial file format. Someone on the newsgroups
 1912     //    said that an ICL is an "ICon Library... a renamed 16-bit Windows .DLL (an NE format executable) which
 1913     //    typically contains nothing but a resource section. The ICL extension seems to be used by convention."
 1914     // L17: Support negative numbers to mean resource IDs. These are supported by the resource extraction method directly, and by ExtractIcon if aIconNumber < -1.
 1915     bool ExtractIcon_was_used = !hbitmap && (aIconNumber > 1 || aIconNumber < 0 || (file_ext && (
 1916            !_tcsicmp(file_ext, _T("exe"))
 1917         || !_tcsicmp(file_ext, _T("dll"))
 1918         || !_tcsicmp(file_ext, _T("icl")) // Icon library: Unofficial dll container, see notes above.
 1919         || !_tcsicmp(file_ext, _T("cpl")) // Control panel extension/applet (ExtractIcon is said to work on these).
 1920         || !_tcsicmp(file_ext, _T("scr")) // Screen saver (ExtractIcon should work since these are really EXEs).
 1921         // v1.0.44: Below are now omitted to reduce code size and improve performance. They are still supported
 1922         // indirectly because ExtractIcon is attempted whenever LoadImage() fails further below.
 1923         //|| !_tcsicmp(file_ext, _T("drv")) // Driver (ExtractIcon is said to work on these).
 1924         //|| !_tcsicmp(file_ext, _T("ocx")) // OLE/ActiveX Control Extension
 1925         //|| !_tcsicmp(file_ext, _T("vbx")) // Visual Basic Extension
 1926         //|| !_tcsicmp(file_ext, _T("acm")) // Audio Compression Manager Driver
 1927         //|| !_tcsicmp(file_ext, _T("bpl")) // Delphi Library (like a DLL?)
 1928         // Not supported due to rarity, code size, performance, and uncertainty of whether ExtractIcon works on them.
 1929         // Update for v1.0.44: The following are now supported indirectly because ExtractIcon is attempted whenever
 1930         // LoadImage() fails further below.
 1931         //|| !_tcsicmp(file_ext, _T("nil")) // Norton Icon Library 
 1932         //|| !_tcsicmp(file_ext, _T("wlx")) // Total/Windows Commander Lister Plug-in
 1933         //|| !_tcsicmp(file_ext, _T("wfx")) // Total/Windows Commander File System Plug-in
 1934         //|| !_tcsicmp(file_ext, _T("wcx")) // Total/Windows Commander Plug-in
 1935         //|| !_tcsicmp(file_ext, _T("wdx")) // Total/Windows Commander Plug-in
 1936         )));
 1937 
 1938     if (ExtractIcon_was_used)
 1939     {
 1940         aImageType = IMAGE_ICON;
 1941 
 1942         // L17: Manually extract the most appropriately sized icon resource for the best results.
 1943         hbitmap = (HBITMAP)ExtractIconFromExecutable(aFilespec, aIconNumber, aWidth, aHeight, apModule);
 1944 
 1945         // At this time it seems unnecessary to fall back to any of the following methods:
 1946         /*
 1947         if (aWidth && aHeight) // Lexikos: Alternate methods that give better results than ExtractIcon.
 1948         {
 1949             int icon_index = aIconNumber > 0 ? aIconNumber - 1 : aIconNumber < -1 ? aIconNumber : 0;
 1950             // Testing shows ExtractIcon retrieves the first icon in the icon group and resizes it to
 1951             // the system large icon size. In case scripts expect this behaviour, and because it is
 1952             // debatable which size will actually look better when scaled, use ExtractIconEX only if
 1953             // a system size is exactly specified. Callers who specifically want the system small or
 1954             // large icon should call GetSystemMetrics() to get the correct aWidth and aHeight.
 1955             // For convenience and because the system icon sizes are probably always square,
 1956             // assume aWidth == -1 is equivalent to aWidth == aHeight (and vice versa).
 1957             if ((aWidth == GetSystemMetrics(SM_CXSMICON) || aWidth == -1) && (aHeight == GetSystemMetrics(SM_CYSMICON) || aHeight == -1))
 1958             {
 1959                 // Retrieve icon via phiconSmall.
 1960                 ExtractIconEx(aFilespec, icon_index, NULL, (HICON*)&hbitmap, 1);
 1961             }
 1962             else if ((aWidth == GetSystemMetrics(SM_CXICON) || aWidth == -1) && (aHeight == GetSystemMetrics(SM_CYICON) || aHeight == -1))
 1963             {
 1964                 // Retrieve icon via phiconLarge.
 1965                 ExtractIconEx(aFilespec, icon_index, (HICON*)&hbitmap, NULL, 1);
 1966             }
 1967             else
 1968             {
 1969                 UINT icon_id;
 1970                 // This is the simplest method of loading an icon of an arbitrary size.
 1971                 // "However, this function is deprecated not intended for general use."
 1972                 // It is also not documented to support resource IDs, unlike ExtractIcon and ExtractIconEx.
 1973                 if (-1 == PrivateExtractIcons(aFilespec, icon_index, aWidth == -1 ? aHeight : aWidth, aHeight == -1 ? aWidth : aHeight, (HICON*)&hbitmap, &icon_id, 1, 0))
 1974                     hbitmap = NULL;
 1975             }
 1976         }
 1977         // Lexikos: ExtractIcon supports resource IDs by specifying nIconIndex < -1, where Abs(nIconIndex)
 1978         // is the resource ID. nIconIndex MUST NOT BE -1, which is used to indicate the total number of
 1979         // icons should be returned. ExtractIconEx could be used to support ID -1, but it has different
 1980         // behaviour to ExtractIcon, and the method above should work in most instances.
 1981         if (!hbitmap) // The other methods failed or were not used.
 1982             hbitmap = (HBITMAP)ExtractIcon(g_hInstance, aFilespec, aIconNumber > 0 ? aIconNumber - 1 : aIconNumber < -1 ? aIconNumber : 0);
 1983         // Above: Although it isn't well documented at MSDN, apparently both ExtractIcon() and LoadIcon()
 1984         // scale the icon to the system's large-icon size (usually 32x32) regardless of the actual size of
 1985         // the icon inside the file.  For this reason, callers should call us in a way that allows us to
 1986         // give preference to LoadImage() over ExtractIcon() (unless the caller needs to retain backward
 1987         // compatibility with existing scripts that explicitly specify icon #1 to force the ExtractIcon
 1988         // method to be used).
 1989         */
 1990         if (hbitmap < (HBITMAP)2) // i.e. it's NULL or 1. Return value of 1 means "incorrect file type".
 1991             return NULL; // v1.0.44: Fixed to return NULL vs. hbitmap, since 1 is an invalid handle (perhaps rare since no known bugs caused by it).
 1992         //else continue on below so that the icon can be resized to the caller's specified dimensions.
 1993     }
 1994     else if (file_ext) // Make an initial guess of the type of image if the above didn't already determine the type.
 1995     {
 1996         if (!_tcsicmp(file_ext, _T("ico")))
 1997             aImageType = IMAGE_ICON;
 1998         else if (!_tcsicmp(file_ext, _T("cur")) || !_tcsicmp(file_ext, _T("ani")))
 1999             aImageType = IMAGE_CURSOR;
 2000         else if (!_tcsicmp(file_ext, _T("bmp")))
 2001             aImageType = IMAGE_BITMAP;
 2002         //else for other extensions, leave set to "unknown" so that the below knows to use IPic or GDI+ to load it.
 2003     }
 2004     //else same comment as above.
 2005 
 2006     if ((aWidth == -1 || aHeight == -1) && (!aWidth || !aHeight))
 2007         aWidth = aHeight = 0; // i.e. One dimension is zero and the other is -1, which resolves to the same as "keep original size".
 2008     bool keep_aspect_ratio = (aWidth == -1 || aHeight == -1);
 2009 
 2010     // Caller should ensure that aUseGDIPlusIfAvailable==false when aIconNumber > 0, since it makes no sense otherwise.
 2011     HINSTANCE hinstGDI = NULL;
 2012     if (aUseGDIPlusIfAvailable && !(hinstGDI = LoadLibrary(_T("gdiplus")))) // Relies on short-circuit boolean order for performance.
 2013         aUseGDIPlusIfAvailable = false; // Override any original "true" value as a signal for the section below.
 2014 
 2015     if (!hbitmap && aImageType > -1 && !aUseGDIPlusIfAvailable)
 2016     {
 2017         // Since image hasn't yet be loaded and since the file type appears to be one supported by
 2018         // LoadImage() [icon/cursor/bitmap], attempt that first.  If it fails, fall back to the other
 2019         // methods below in case the file's internal contents differ from what the file extension indicates.
 2020         int desired_width, desired_height;
 2021         if (keep_aspect_ratio) // Load image at its actual size.  It will be rescaled to retain aspect ratio later below.
 2022         {
 2023             desired_width = 0;
 2024             desired_height = 0;
 2025         }
 2026         else
 2027         {
 2028             desired_width = aWidth;
 2029             desired_height = aHeight;
 2030         }
 2031         // For LoadImage() below:
 2032         // LR_CREATEDIBSECTION applies only when aImageType == IMAGE_BITMAP, but seems appropriate in that case.
 2033         // Also, if width and height are non-zero, that will determine which icon of a multi-icon .ico file gets
 2034         // loaded (though I don't know the exact rules of precedence).
 2035         // KNOWN LIMITATIONS/BUGS:
 2036         // LoadImage() fails when requesting a size of 1x1 for an image whose orig/actual size is small (e.g. 1x2).
 2037         // Unlike CopyImage(), perhaps it detects that division by zero would occur and refuses to do the
 2038         // calculation rather than providing more code to do a correct calculation that doesn't divide by zero.
 2039         // For example:
 2040         // LoadImage() Success:
 2041         //   Gui, Add, Pic, h2 w2, bitmap 1x2.bmp
 2042         //   Gui, Add, Pic, h1 w1, bitmap 4x6.bmp
 2043         // LoadImage() Failure:
 2044         //   Gui, Add, Pic, h1 w1, bitmap 1x2.bmp
 2045         // LoadImage() also fails on:
 2046         //   Gui, Add, Pic, h1, bitmap 1x2.bmp
 2047         // And then it falls back to GDIplus, which in the particular case above appears to traumatize the
 2048         // parent window (or its picture control), because the GUI window hangs (but not the script) after
 2049         // doing a FileSelectFolder.  For example:
 2050         //   Gui, Add, Button,, FileSelectFile
 2051         //   Gui, Add, Pic, h1, bitmap 1x2.bmp  ; Causes GUI window to hang after FileSelectFolder (due to LoadImage failing then falling back to GDIplus; i.e. GDIplus is somehow triggering the problem).
 2052         //   Gui, Show
 2053         //   return
 2054         //   ButtonFileSelectFile:
 2055         //   FileSelectFile, outputvar
 2056         //   return
 2057         if (hbitmap = (HBITMAP)LoadImage(NULL, aFilespec, aImageType, desired_width, desired_height
 2058             , LR_LOADFROMFILE | LR_CREATEDIBSECTION))
 2059         {
 2060             // The above might have loaded an HICON vs. an HBITMAP (it has been confirmed that LoadImage()
 2061             // will return an HICON vs. HBITMAP is aImageType is IMAGE_ICON/CURSOR).  Note that HICON and
 2062             // HCURSOR are identical for most/all Windows API uses.  Also note that LoadImage() will load
 2063             // an icon as a bitmap if the file contains an icon but IMAGE_BITMAP was passed in (at least
 2064             // on Windows XP).
 2065             if (!keep_aspect_ratio && !aIconNumber) // No further resizing or conversion is needed.
 2066                 return hbitmap;
 2067             // Otherwise, continue on so that the image can be resized via a second call to LoadImage().
 2068         }
 2069         // v1.0.40.10: Abort if file doesn't exist so that GDIPlus isn't even attempted. This is done because
 2070         // loading GDIPlus apparently disrupts the color palette of certain games, at least old ones that use
 2071         // DirectDraw in 256-color depth.
 2072         else if (GetFileAttributes(aFilespec) == 0xFFFFFFFF) // For simplicity, we don't check if it's a directory vs. file, since that should be too rare.
 2073             return NULL;
 2074         else if (aIconNumber > 0)
 2075         {
 2076             // UPDATE for v1.0.44: Attempt ExtractIcon in case its some extension that's
 2077             // was recognized as an icon container (such as AutoHotkeySC.bin) and thus wasn't handled higher above.
 2078             //hbitmap = (HBITMAP)ExtractIcon(g_hInstance, aFilespec, aIconNumber - 1);
 2079 
 2080             // L17: Manually extract the most appropriately sized icon resource for the best results.
 2081             hbitmap = (HBITMAP)ExtractIconFromExecutable(aFilespec, aIconNumber, aWidth, aHeight, apModule);
 2082 
 2083             if (hbitmap < (HBITMAP)2) // i.e. it's NULL or 1. Return value of 1 means "incorrect file type".
 2084                 return NULL;
 2085             ExtractIcon_was_used = true;
 2086             aImageType = IMAGE_ICON;
 2087         }
 2088         //else file exists, so continue on so that the other methods are attempted in case file's contents
 2089         // differ from what the file extension indicates, or in case the other methods can be successful
 2090         // even when the above failed.
 2091     }
 2092 
 2093     IPicture *pic = NULL; // Also used to detect whether IPic method was used to load the image.
 2094 
 2095     if (!hbitmap) // Above hasn't loaded the image yet, so use the fall-back methods.
 2096     {
 2097         // At this point, regardless of the image type being loaded (even an icon), it will
 2098         // definitely be converted to a Bitmap below.  So set the type:
 2099         aImageType = IMAGE_BITMAP;
 2100         // Find out if this file type is supported by the non-GDI+ method.  This check is not foolproof
 2101         // since all it does is look at the file's extension, not its contents.  However, it doesn't
 2102         // need to be 100% accurate because its only purpose is to detect whether the higher-overhead
 2103         // calls to GdiPlus can be avoided.
 2104         if (aUseGDIPlusIfAvailable || !file_ext || (_tcsicmp(file_ext, _T("jpg"))
 2105             && _tcsicmp(file_ext, _T("jpeg")) && _tcsicmp(file_ext, _T("gif")))) // Non-standard file type (BMP is already handled above).
 2106             if (!hinstGDI) // We don't yet have a handle from an earlier call to LoadLibary().
 2107                 hinstGDI = LoadLibrary(_T("gdiplus"));
 2108         // If it is suspected that the file type isn't supported, try to use GdiPlus if available.
 2109         // If it's not available, fall back to the old method in case the filename doesn't properly
 2110         // reflect its true contents (i.e. in case it really is a JPG/GIF/BMP internally).
 2111         // If the below LoadLibrary() succeeds, either the OS is XP+ or the GdiPlus extensions have been
 2112         // installed on an older OS.
 2113         if (hinstGDI)
 2114         {
 2115             // LPVOID and "int" are used to avoid compiler errors caused by... namespace issues?
 2116             typedef int (WINAPI *GdiplusStartupType)(ULONG_PTR*, LPVOID, LPVOID);
 2117             typedef VOID (WINAPI *GdiplusShutdownType)(ULONG_PTR);
 2118             typedef int (WINGDIPAPI *GdipCreateBitmapFromFileType)(LPVOID, LPVOID);
 2119             typedef int (WINGDIPAPI *GdipCreateHBITMAPFromBitmapType)(LPVOID, LPVOID, DWORD);
 2120             typedef int (WINGDIPAPI *GdipDisposeImageType)(LPVOID);
 2121             GdiplusStartupType DynGdiplusStartup = (GdiplusStartupType)GetProcAddress(hinstGDI, "GdiplusStartup");
 2122             GdiplusShutdownType DynGdiplusShutdown = (GdiplusShutdownType)GetProcAddress(hinstGDI, "GdiplusShutdown");
 2123             GdipCreateBitmapFromFileType DynGdipCreateBitmapFromFile = (GdipCreateBitmapFromFileType)GetProcAddress(hinstGDI, "GdipCreateBitmapFromFile");
 2124             GdipCreateHBITMAPFromBitmapType DynGdipCreateHBITMAPFromBitmap = (GdipCreateHBITMAPFromBitmapType)GetProcAddress(hinstGDI, "GdipCreateHBITMAPFromBitmap");
 2125             GdipDisposeImageType DynGdipDisposeImage = (GdipDisposeImageType)GetProcAddress(hinstGDI, "GdipDisposeImage");
 2126 
 2127             ULONG_PTR token;
 2128             Gdiplus::GdiplusStartupInput gdi_input;
 2129             Gdiplus::GpBitmap *pgdi_bitmap;
 2130             if (DynGdiplusStartup && DynGdiplusStartup(&token, &gdi_input, NULL) == Gdiplus::Ok)
 2131             {
 2132 #ifndef UNICODE
 2133                 WCHAR filespec_wide[MAX_WIDE_PATH]; // MAX_WIDE_PATH vs. MAX_PATH allows this to work with long paths (\\?\ prefix may be required).
 2134                 ToWideChar(aFilespec, filespec_wide, _countof(filespec_wide)); // Dest. size is in wchars, not bytes.
 2135                 if (DynGdipCreateBitmapFromFile(filespec_wide, &pgdi_bitmap) == Gdiplus::Ok)
 2136 #else
 2137                 if (DynGdipCreateBitmapFromFile(aFilespec, &pgdi_bitmap) == Gdiplus::Ok)
 2138 #endif
 2139                 {
 2140                     if (DynGdipCreateHBITMAPFromBitmap(pgdi_bitmap, &hbitmap, CLR_DEFAULT) != Gdiplus::Ok)
 2141                         hbitmap = NULL; // Set to NULL to be sure.
 2142                     DynGdipDisposeImage(pgdi_bitmap); // This was tested once to make sure it really returns Gdiplus::Ok.
 2143                 }
 2144                 // The current thought is that shutting it down every time conserves resources.  If so, it
 2145                 // seems justified since it is probably called infrequently by most scripts:
 2146                 DynGdiplusShutdown(token);
 2147             }
 2148             FreeLibrary(hinstGDI);
 2149         }
 2150         else // Using old picture loading method.
 2151         {
 2152             // Based on code sample at http://www.codeguru.com/Cpp/G-M/bitmap/article.php/c4935/
 2153             HANDLE hfile = CreateFile(aFilespec, GENERIC_READ, 0, NULL, OPEN_EXISTING, 0, NULL);
 2154             if (hfile == INVALID_HANDLE_VALUE)
 2155                 return NULL;
 2156             DWORD size = GetFileSize(hfile, NULL);
 2157             HGLOBAL hglobal = GlobalAlloc(GMEM_MOVEABLE, size);
 2158             if (!hglobal)
 2159             {
 2160                 CloseHandle(hfile);
 2161                 return NULL;
 2162             }
 2163             LPVOID hlocked = GlobalLock(hglobal);
 2164             if (!hlocked)
 2165             {
 2166                 CloseHandle(hfile);
 2167                 GlobalFree(hglobal);
 2168                 return NULL;
 2169             }
 2170             // Read the file into memory:
 2171             ReadFile(hfile, hlocked, size, &size, NULL);
 2172             GlobalUnlock(hglobal);
 2173             CloseHandle(hfile);
 2174             LPSTREAM stream;
 2175             if (FAILED(CreateStreamOnHGlobal(hglobal, FALSE, &stream)) || !stream)  // Relies on short-circuit boolean order.
 2176             {
 2177                 GlobalFree(hglobal);
 2178                 return NULL;
 2179             }
 2180             // Specify TRUE to have it do the GlobalFree() for us.  But since the call might fail, it seems best
 2181             // to free the mem ourselves to avoid uncertainty over what it does on failure:
 2182             if (FAILED(OleLoadPicture(stream, 0, FALSE, IID_IPicture, (void **)&pic)))
 2183                 pic = NULL;
 2184             stream->Release();
 2185             GlobalFree(hglobal);
 2186             if (!pic)
 2187                 return NULL;
 2188             pic->get_Handle((OLE_HANDLE *)&hbitmap);
 2189             // Above: MSDN: "The caller is responsible for this handle upon successful return. The variable is set
 2190             // to NULL on failure."
 2191             if (!hbitmap)
 2192             {
 2193                 pic->Release();
 2194                 return NULL;
 2195             }
 2196             // Don't pic->Release() yet because that will also destroy/invalidate hbitmap handle.
 2197         } // IPicture method was used.
 2198     } // IPicture or GDIPlus was used to load the image, not a simple LoadImage() or ExtractIcon().
 2199 
 2200     // Above has ensured that hbitmap is now not NULL.
 2201     // Adjust things if "keep aspect ratio" is in effect:
 2202     if (keep_aspect_ratio)
 2203     {
 2204         HBITMAP hbitmap_to_analyze;
 2205         ICONINFO ii; // Must be declared at this scope level.
 2206         if (aImageType == IMAGE_BITMAP)
 2207             hbitmap_to_analyze = hbitmap;
 2208         else // icon or cursor
 2209         {
 2210             if (GetIconInfo((HICON)hbitmap, &ii)) // Works on cursors too.
 2211                 hbitmap_to_analyze = ii.hbmMask; // Use Mask because MSDN implies hbmColor can be NULL for monochrome cursors and such.
 2212             else
 2213             {
 2214                 DestroyIcon((HICON)hbitmap);
 2215                 return NULL; // No need to call pic->Release() because since it's an icon, we know IPicture wasn't used (it only loads bitmaps).
 2216             }
 2217         }
 2218         // Above has ensured that hbitmap_to_analyze is now not NULL.  Find bitmap's dimensions.
 2219         BITMAP bitmap;
 2220         GetObject(hbitmap_to_analyze, sizeof(BITMAP), &bitmap); // Realistically shouldn't fail at this stage.
 2221         if (aHeight == -1)
 2222         {
 2223             // Caller wants aHeight calculated based on the specified aWidth (keep aspect ratio).
 2224             if (bitmap.bmWidth) // Avoid any chance of divide-by-zero.
 2225                 aHeight = (int)(((double)bitmap.bmHeight / bitmap.bmWidth) * aWidth + .5); // Round.
 2226         }
 2227         else
 2228         {
 2229             // Caller wants aWidth calculated based on the specified aHeight (keep aspect ratio).
 2230             if (bitmap.bmHeight) // Avoid any chance of divide-by-zero.
 2231                 aWidth = (int)(((double)bitmap.bmWidth / bitmap.bmHeight) * aHeight + .5); // Round.
 2232         }
 2233         if (aImageType != IMAGE_BITMAP)
 2234         {
 2235             // It's our responsibility to delete these two when they're no longer needed:
 2236             DeleteObject(ii.hbmColor);
 2237             DeleteObject(ii.hbmMask);
 2238             // If LoadImage() vs. ExtractIcon() was used originally, call LoadImage() again because
 2239             // I haven't found any other way to retain an animated cursor's animation (and perhaps
 2240             // other icon/cursor attributes) when resizing the icon/cursor (CopyImage() doesn't
 2241             // retain animation):
 2242             if (!ExtractIcon_was_used && !script_passed_handle)
 2243             {
 2244                 DestroyIcon((HICON)hbitmap); // Destroy the original HICON.
 2245                 // Load a new one, but at the size newly calculated above.
 2246                 return (HBITMAP)LoadImage(NULL, aFilespec, aImageType, aWidth, aHeight, LR_LOADFROMFILE);
 2247             }
 2248         }
 2249     }
 2250 
 2251     HBITMAP hbitmap_new; // To hold the scaled image (if scaling is needed).
 2252     if (pic) // IPicture method was used.
 2253     {
 2254         // The below statement is confirmed by having tested that DeleteObject(hbitmap) fails
 2255         // if called after pic->Release():
 2256         // "Copy the image. Necessary, because upon pic's release the handle is destroyed."
 2257         // MSDN: CopyImage(): "[If either width or height] is zero, then the returned image will have the
 2258         // same width/height as the original."
 2259         // Note also that CopyImage() seems to provide better scaling quality than using MoveWindow()
 2260         // (followed by redrawing the parent window) on the static control that contains it:
 2261         hbitmap_new = (HBITMAP)CopyImage(hbitmap, IMAGE_BITMAP, aWidth, aHeight // We know it's IMAGE_BITMAP in this case.
 2262             , (aWidth || aHeight) ? 0 : LR_COPYRETURNORG); // Produce original size if no scaling is needed.
 2263         pic->Release();
 2264         // No need to call DeleteObject(hbitmap), see above.
 2265     }
 2266     else // GDIPlus or a simple method such as LoadImage or ExtractIcon was used.
 2267     {
 2268         if (!aWidth && !aHeight // No resizing needed.
 2269             && (!script_owns_handle || apNoDelete) // No copying needed.
 2270             && (aIconNumber < 1 || aImageType == IMAGE_ICON)) // No conversion to icon needed.
 2271             return hbitmap;
 2272         // The following will also handle HICON/HCURSOR correctly if aImageType == IMAGE_ICON/CURSOR.
 2273         // Also, LR_COPYRETURNORG|LR_COPYDELETEORG is used because it might allow the animation of
 2274         // a cursor to be retained if the specified size happens to match the actual size of the
 2275         // cursor.  This is because normally, it seems that CopyImage() omits cursor animation
 2276         // from the new object.  MSDN: "LR_COPYRETURNORG returns the original hImage if it satisfies
 2277         // the criteria for the copy—that is, correct dimensions and color depth—in which case the
 2278         // LR_COPYDELETEORG flag is ignored. If this flag is not specified, a new object is always created."
 2279         // KNOWN BUG: Calling CopyImage() when the source image is tiny and the destination width/height
 2280         // is also small (e.g. 1) causes a divide-by-zero exception.
 2281         // For example:
 2282         //   Gui, Add, Pic, h1 w-1, bitmap 1x2.bmp  ; Crash (divide by zero)
 2283         //   Gui, Add, Pic, h1 w-1, bitmap 2x3.bmp  ; Crash (divide by zero)
 2284         // However, such sizes seem too rare to document or put in an exception handler for.
 2285         hbitmap_new = (HBITMAP)CopyImage(hbitmap, aImageType, aWidth, aHeight
 2286             , script_owns_handle ? (apNoDelete ? LR_COPYRETURNORG : 0) // If the script owns the original handle, never deleted it, and return it only if the caller can be told not to delete it.
 2287                 : (LR_COPYRETURNORG | LR_COPYDELETEORG));
 2288         // Above's LR_COPYDELETEORG deletes the original to avoid cascading resource usage.  MSDN's
 2289         // LoadImage() docs say:
 2290         // "When you are finished using a bitmap, cursor, or icon you loaded without specifying the
 2291         // LR_SHARED flag, you can release its associated memory by calling one of [the three functions]."
 2292         // Therefore, it seems best to call the right function even though DeleteObject might work on
 2293         // all of them on some or all current OSes.  UPDATE: Evidence indicates that DestroyIcon()
 2294         // will also destroy cursors, probably because icons and cursors are literally identical in
 2295         // every functional way.  One piece of evidence:
 2296         //> No stack trace, but I know the exact source file and line where the call
 2297         //> was made. But still, it is annoying when you see 'DestroyCursor' even though
 2298         //> there is 'DestroyIcon'.
 2299         // "Can't be helped. Icons and cursors are the same thing" (Tim Robinson (MVP, Windows SDK)).
 2300         //
 2301         // Finally, the reason this is important is that it eliminates one handle type
 2302         // that we would otherwise have to track.  For example, if a gui window is destroyed and
 2303         // and recreated multiple times, its bitmap and icon handles should all be destroyed each time.
 2304         // Otherwise, resource usage would cascade upward until the script finally terminated, at
 2305         // which time all such handles are freed automatically.
 2306     }
 2307     if (aIconNumber > 0 && aImageType == IMAGE_BITMAP)
 2308     {
 2309         // aIconNumber > 0 means the caller requires an icon.
 2310         ICONINFO iconinfo;
 2311         iconinfo.fIcon = TRUE;
 2312         iconinfo.hbmMask = hbitmap_new;
 2313         iconinfo.hbmColor = hbitmap_new;
 2314         HICON new_icon = CreateIconIndirect(&iconinfo);
 2315         if (!script_owns_handle)
 2316             DeleteObject(hbitmap_new);
 2317         hbitmap_new = (HBITMAP)new_icon;
 2318         aImageType = IMAGE_ICON;
 2319     }
 2320     if (hbitmap != hbitmap_new) // A new icon/bitmap was created above.
 2321         if (apNoDelete)
 2322             *apNoDelete = false; // Override any previously set value.
 2323         //else caller assumes it must take responsibility for the handle.
 2324     return hbitmap_new;
 2325 }
 2326 
 2327 
 2328 struct ResourceIndexToIdEnumData
 2329 {
 2330     int find_index;
 2331     int index;
 2332     LPTSTR result;
 2333 };
 2334 
 2335 BOOL CALLBACK ResourceIndexToIdEnumProc(HMODULE hModule, LPCTSTR lpszType, LPTSTR lpszName, LONG_PTR lParam)
 2336 {
 2337     ResourceIndexToIdEnumData &enum_data = *(ResourceIndexToIdEnumData*)lParam;
 2338     
 2339     if (++enum_data.index == enum_data.find_index)
 2340     {
 2341         enum_data.result = lpszName;
 2342         return FALSE; // Stop
 2343     }
 2344     return TRUE; // Continue
 2345 }
 2346 
 2347 static TCHAR RESOURCE_ID_NOT_FOUND[] = {0};
 2348 
 2349 // L17: Find ID of resource from one-based index. i.e. IconNumber -> resource ID.
 2350 // v1.1.22.05: Return LPTSTR since some (very few) icons have a string ID.
 2351 LPTSTR ResourceIndexToId(HMODULE aModule, LPCTSTR aType, int aIndex)
 2352 {
 2353     ResourceIndexToIdEnumData enum_data;
 2354     enum_data.find_index = aIndex;
 2355     enum_data.index = 0;
 2356     // NULL can't be used to indicate "not found", as any value between 0 and 0xFFFF is an
 2357     // integer ID, including zero, even though some compilers replace it with "0" (string).
 2358     // (LPTSTR)-1 or "" could be used instead, but this method should be safest, since we
 2359     // know the API cannot ever return a string at this address:
 2360     enum_data.result = RESOURCE_ID_NOT_FOUND;
 2361 
 2362     EnumResourceNames(aModule, aType, &ResourceIndexToIdEnumProc, (LONG_PTR)&enum_data);
 2363 
 2364     return enum_data.result;
 2365 }
 2366 
 2367 // L17: Extract icon of the appropriate size from an executable (or compatible) file.
 2368 HICON ExtractIconFromExecutable(LPTSTR aFilespec, int aIconNumber, int aWidth, int aHeight, HMODULE *apModule)
 2369 {
 2370     HICON hicon = NULL;
 2371 
 2372     // If the module is already loaded as an executable, LoadLibraryEx returns its handle.
 2373     // Otherwise each call will receive its own handle to a data file mapping.
 2374     HMODULE hdatafile = aFilespec ? LoadLibraryEx(aFilespec, NULL, LOAD_LIBRARY_AS_DATAFILE) : g_hInstance;
 2375     if (hdatafile)
 2376     {
 2377         LPTSTR group_icon_id = (aIconNumber < 0)
 2378             ? MAKEINTRESOURCE(-aIconNumber)
 2379             : ResourceIndexToId(hdatafile, (LPCTSTR)RT_GROUP_ICON, aIconNumber ? aIconNumber : 1);
 2380 
 2381         HRSRC hres;
 2382         HGLOBAL hresdata;
 2383         LPVOID presdata;
 2384 
 2385         // MSDN indicates resources are unloaded when the *process* exits, but also states
 2386         // that the pointer returned by LockResource is valid until the *module* containing
 2387         // the resource is unloaded. Testing seems to indicate that unloading a module indeed
 2388         // unloads or invalidates any resources it contains.
 2389         if (group_icon_id != RESOURCE_ID_NOT_FOUND
 2390             && (hres = FindResource(hdatafile, group_icon_id, RT_GROUP_ICON))
 2391             && (hresdata = LoadResource(hdatafile, hres))
 2392             && (presdata = LockResource(hresdata)))
 2393         {
 2394 #pragma pack(push, 1) // For RESDIR, mainly.
 2395             struct NEWHEADER {
 2396                 WORD Reserved;
 2397                 WORD ResType;
 2398                 WORD ResCount;
 2399             };
 2400             struct ICONRESDIR {
 2401                 BYTE Width;
 2402                 BYTE Height;
 2403                 BYTE ColorCount;
 2404                 BYTE reserved;
 2405             };
 2406             // Note that the definition of RESDIR at http://msdn.microsoft.com/en-us/library/ms648026 is
 2407             // completely wrong as at 2015-01-10, but the correct definition is posted in the comments.
 2408             struct RESDIR {
 2409                 ICONRESDIR Icon;
 2410                 WORD Planes;
 2411                 WORD BitCount;
 2412                 DWORD BytesInRes;
 2413                 WORD IconCursorId;
 2414             };
 2415 #pragma pack(pop)
 2416 
 2417             if (aWidth == -1)
 2418                 aWidth = aHeight;
 2419             if (aWidth == 0)
 2420                 aWidth = GetSystemMetrics(SM_CXICON);
 2421 
 2422             NEWHEADER *resHead = (NEWHEADER *)presdata;
 2423             WORD resCount = resHead->ResCount;
 2424             RESDIR *resDir = (RESDIR *)(resHead + 1), *chosen = NULL;
 2425             int chosen_width = 0;
 2426             for (int i = 0; i < resCount; ++i)
 2427             {
 2428                 int this_width = resDir[i].Icon.Width;
 2429                 if (!this_width) // Workaround for 256x256 icons.
 2430                     this_width = 256;
 2431                 // Find the closest match for size, preferring the next larger icon if there's
 2432                 // no exact match.  Normally the system will just pick the closest size, but
 2433                 // at least for our icon, the 32x32 icon rendered at 20x20 looks much better
 2434                 // than the 16x16 icon rendered at 20x20 (i.e. small icon size for 125% DPI).
 2435                 if (this_width > chosen_width
 2436                     ? chosen_width < aWidth // Current icon smaller than desired, so up-size.
 2437                     : this_width >= aWidth) // This icon is closer to the desired size, so down-size.
 2438                 {
 2439                     chosen = &resDir[i];
 2440                     chosen_width = this_width;
 2441                 }
 2442             }
 2443             if (   (chosen) // It would be NULL if there were no icons.
 2444                 && (hres = FindResource(hdatafile, MAKEINTRESOURCE(chosen->IconCursorId), RT_ICON))
 2445                 && (hresdata = LoadResource(hdatafile, hres))
 2446                 && (presdata = LockResource(hresdata))   )
 2447             {
 2448                 hicon = CreateIconFromResourceEx((PBYTE)presdata, SizeofResource(hdatafile, hres), TRUE, 0x30000, 0, 0, 0);
 2449             }
 2450         }
 2451 
 2452         if (apModule && hicon) // Only return the module if an icon was loaded; otherwise free it.
 2453             *apModule = hdatafile;
 2454         else if (aFilespec)
 2455             FreeLibrary(hdatafile); // Decrements the executable module's reference count or frees the data file mapping.
 2456     }
 2457 
 2458     // L20: Fall back to ExtractIcon if the above method failed. This may work on some versions of Windows where
 2459     // ExtractIcon supports 16-bit "executables" (such as ICL files) that cannot be loaded by LoadLibraryEx.
 2460     // However, resource ID -1 is not supported, and if multiple icon sizes exist in the file, the first is used
 2461     // rather than the most appropriate.
 2462     if (!hicon)
 2463         hicon = ExtractIcon(0, aFilespec, aIconNumber > 0 ? aIconNumber - 1 : aIconNumber < -1 ? aIconNumber : 0);
 2464 
 2465     return hicon;
 2466 }
 2467 
 2468 
 2469 HBITMAP IconToBitmap(HICON ahIcon, bool aDestroyIcon)
 2470 // Converts HICON to an HBITMAP that has ahIcon's actual dimensions.
 2471 // The incoming ahIcon will be destroyed if the caller passes true for aDestroyIcon.
 2472 // Returns NULL on failure, in which case aDestroyIcon will still have taken effect.
 2473 // If the icon contains any transparent pixels, they will be mapped to CLR_NONE within
 2474 // the bitmap so that the caller can detect them.
 2475 {
 2476     if (!ahIcon)
 2477         return NULL;
 2478 
 2479     HBITMAP hbitmap = NULL;  // Set default.  This will be the value returned.
 2480 
 2481     HDC hdc_desktop = GetDC(HWND_DESKTOP);
 2482     HDC hdc = CreateCompatibleDC(hdc_desktop); // Don't pass NULL since I think that would result in a monochrome bitmap.
 2483     if (hdc)
 2484     {
 2485         ICONINFO ii;
 2486         if (GetIconInfo(ahIcon, &ii))
 2487         {
 2488             BITMAP icon_bitmap;
 2489             // Find out how big the icon is and create a bitmap compatible with the desktop DC (not the memory DC,
 2490             // since its bits per pixel (color depth) is probably 1.
 2491             if (GetObject(ii.hbmColor, sizeof(BITMAP), &icon_bitmap)
 2492                 && (hbitmap = CreateCompatibleBitmap(hdc_desktop, icon_bitmap.bmWidth, icon_bitmap.bmHeight))) // Assign
 2493             {
 2494                 // To retain maximum quality in case caller needs to resize the bitmap we return, convert the
 2495                 // icon to a bitmap that matches the icon's actual size:
 2496                 HGDIOBJ old_object = SelectObject(hdc, hbitmap);
 2497                 if (old_object) // Above succeeded.
 2498                 {
 2499                     // Use DrawIconEx() vs. DrawIcon() because someone said DrawIcon() always draws 32x32
 2500                     // regardless of the icon's actual size.
 2501                     // If it's ever needed, this can be extended so that the caller can pass in a background
 2502                     // color to use in place of any transparent pixels within the icon (apparently, DrawIconEx()
 2503                     // skips over transparent pixels in the icon when drawing to the DC and its bitmap):
 2504                     RECT rect = {0, 0, icon_bitmap.bmWidth, icon_bitmap.bmHeight}; // Left, top, right, bottom.
 2505                     HBRUSH hbrush = CreateSolidBrush(CLR_DEFAULT);
 2506                     FillRect(hdc, &rect, hbrush);
 2507                     DeleteObject(hbrush);
 2508                     // Probably something tried and abandoned: FillRect(hdc, &rect, (HBRUSH)GetStockObject(NULL_BRUSH));
 2509                     DrawIconEx(hdc, 0, 0, ahIcon, icon_bitmap.bmWidth, icon_bitmap.bmHeight, 0, NULL, DI_NORMAL);
 2510                     // Debug: Find out properties of new bitmap.
 2511                     //BITMAP b;
 2512                     //GetObject(hbitmap, sizeof(BITMAP), &b);
 2513                     SelectObject(hdc, old_object); // Might be needed (prior to deleting hdc) to prevent memory leak.
 2514                 }
 2515             }
 2516             // It's our responsibility to delete these two when they're no longer needed:
 2517             DeleteObject(ii.hbmColor);
 2518             DeleteObject(ii.hbmMask);
 2519         }
 2520         DeleteDC(hdc);
 2521     }
 2522     ReleaseDC(HWND_DESKTOP, hdc_desktop);
 2523     if (aDestroyIcon)
 2524         DestroyIcon(ahIcon);
 2525     return hbitmap;
 2526 }
 2527 
 2528 
 2529 // Lexikos: Used for menu icons on Windows Vista and later. Some similarities to IconToBitmap, maybe should be merged if IconToBitmap does not specifically need to create a device-dependent bitmap?
 2530 HBITMAP IconToBitmap32(HICON ahIcon, bool aDestroyIcon)
 2531 {
 2532     // Get the icon's internal colour and mask bitmaps.
 2533     // hbmColor is needed to measure the icon.
 2534     // hbmMask is needed to generate an alpha channel if the icon does not have one.
 2535     ICONINFO icon_info;
 2536     if (!GetIconInfo(ahIcon, &icon_info))
 2537         return NULL;
 2538 
 2539     HBITMAP hbitmap = NULL; // Set default in case of failure.
 2540 
 2541     // Get size of icon's internal bitmap.
 2542     BITMAP icon_bitmap;
 2543     if (GetObject(icon_info.hbmColor, sizeof(BITMAP), &icon_bitmap))
 2544     {
 2545         int width = icon_bitmap.bmWidth;
 2546         int height = icon_bitmap.bmHeight;
 2547 
 2548         HDC hdc = CreateCompatibleDC(NULL);
 2549         if (hdc)
 2550         {
 2551             BITMAPINFO bitmap_info = {0};
 2552             // Set parameters for 32-bit bitmap. May also be used to retrieve bitmap data from the icon's mask bitmap.
 2553             BITMAPINFOHEADER &bitmap_header = bitmap_info.bmiHeader;
 2554             bitmap_header.biSize = sizeof(BITMAPINFOHEADER);
 2555             bitmap_header.biWidth = width;
 2556             bitmap_header.biHeight = height;
 2557             bitmap_header.biBitCount = 32;
 2558             bitmap_header.biPlanes = 1;
 2559 
 2560             // Create device-independent bitmap.
 2561             UINT *bits;
 2562             if (hbitmap = CreateDIBSection(hdc, &bitmap_info, 0, (void**)&bits, NULL, 0))
 2563             {
 2564                 HGDIOBJ old_object = SelectObject(hdc, hbitmap);
 2565                 if (old_object) // Above succeeded.
 2566                 {
 2567                     // Draw icon onto bitmap. Use DrawIconEx because DrawIcon always draws a large (usually 32x32) icon!
 2568                     DrawIconEx(hdc, 0, 0, ahIcon, 0, 0, 0, NULL, DI_NORMAL);
 2569 
 2570                     // May be necessary for bits to be in sync, according to documentation for CreateDIBSection:
 2571                     GdiFlush();
 2572 
 2573                     // Calculate end of bitmap data.
 2574                     UINT *bits_end = bits + width*height;
 2575                     
 2576                     UINT *this_pixel; // Used in a few loops below.
 2577 
 2578                     // Check for alpha data.
 2579                     bool has_nonzero_alpha = false;
 2580                     for (this_pixel = bits; this_pixel < bits_end; ++this_pixel)
 2581                     {
 2582                         if (*this_pixel >> 24)
 2583                         {
 2584                             has_nonzero_alpha = true;
 2585                             break;
 2586                         }
 2587                     }
 2588 
 2589                     if (!has_nonzero_alpha)
 2590                     {
 2591                         // Get bitmap data from the icon's mask.
 2592                         UINT *mask_bits = (UINT*)_alloca(height*width*4);
 2593                         if (GetDIBits(hdc, icon_info.hbmMask, 0, height, (LPVOID)mask_bits, &bitmap_info, 0))
 2594                         {
 2595                             UINT *this_mask_pixel;
 2596                             // Use the icon's mask to generate alpha data.
 2597                             for (this_pixel = bits, this_mask_pixel = mask_bits; this_pixel < bits_end; ++this_pixel, ++this_mask_pixel)
 2598                             {
 2599                                 if (*this_mask_pixel)
 2600                                     *this_pixel = 0;
 2601                                 else
 2602                                     *this_pixel |= 0xff000000;
 2603                             }
 2604                         }
 2605                         else
 2606                         {
 2607                             // GetDIBits failed, simply make the bitmap opaque.
 2608                             for (this_pixel = bits; this_pixel < bits_end; ++this_pixel)
 2609                                 *this_pixel |= 0xff000000;
 2610                         }
 2611                     }
 2612 
 2613                     SelectObject(hdc, old_object);
 2614                 }
 2615                 else
 2616                 {
 2617                     // Probably very rare, but be on the safe side.
 2618                     DeleteObject(hbitmap);
 2619                     hbitmap = NULL;
 2620                 }
 2621             }
 2622             DWORD dwError = GetLastError();
 2623             DeleteDC(hdc);
 2624         }
 2625     }
 2626 
 2627     // It's our responsibility to delete these two when they're no longer needed:
 2628     DeleteObject(icon_info.hbmColor);
 2629     DeleteObject(icon_info.hbmMask);
 2630 
 2631     if (aDestroyIcon)
 2632         DestroyIcon(ahIcon);
 2633 
 2634     return hbitmap;
 2635 }
 2636 
 2637 
 2638 HRESULT MySetWindowTheme(HWND hwnd, LPCWSTR pszSubAppName, LPCWSTR pszSubIdList)
 2639 {
 2640     // The library must be loaded dynamically, otherwise the app will not launch on OSes older than XP.
 2641     // Theme DLL is normally available only on XP+, but an attempt to load it is made unconditionally
 2642     // in case older OSes can ever have it.
 2643     HRESULT hresult = !S_OK; // Set default as "failure".
 2644     HINSTANCE hinstTheme = LoadLibrary(_T("uxtheme"));
 2645     if (hinstTheme)
 2646     {
 2647         typedef HRESULT (WINAPI *MySetWindowThemeType)(HWND, LPCWSTR, LPCWSTR);
 2648         MySetWindowThemeType DynSetWindowTheme = (MySetWindowThemeType)GetProcAddress(hinstTheme, "SetWindowTheme");
 2649         if (DynSetWindowTheme)
 2650             hresult = DynSetWindowTheme(hwnd, pszSubAppName, pszSubIdList);
 2651         FreeLibrary(hinstTheme);
 2652     }
 2653     return hresult;
 2654 }
 2655 
 2656 
 2657 
 2658 HRESULT MyEnableThemeDialogTexture(HWND hwnd, DWORD dwFlags)
 2659 {
 2660     // The library must be loaded dynamically, otherwise the app will not launch on OSes older than XP.
 2661     // Theme DLL is normally available only on XP+, but an attempt to load it is made unconditionally
 2662     // in case older OSes can ever have it.
 2663     HRESULT hresult = !S_OK; // Set default as "failure".
 2664     HINSTANCE hinstTheme = LoadLibrary(_T("uxtheme"));
 2665     if (hinstTheme)
 2666     {
 2667         typedef HRESULT (WINAPI *MyEnableThemeDialogTextureType)(HWND, DWORD);
 2668         MyEnableThemeDialogTextureType DynEnableThemeDialogTexture = (MyEnableThemeDialogTextureType)GetProcAddress(hinstTheme, "EnableThemeDialogTexture");
 2669         if (DynEnableThemeDialogTexture)
 2670             hresult = DynEnableThemeDialogTexture(hwnd, dwFlags);
 2671         FreeLibrary(hinstTheme);
 2672     }
 2673     return hresult;
 2674 }
 2675 
 2676 
 2677 
 2678 BOOL MyIsAppThemed()
 2679 {
 2680     BOOL result = FALSE;
 2681     HINSTANCE hinstTheme = GetModuleHandle(_T("uxtheme")); // Should always succeed if app is themed.
 2682     if (hinstTheme)
 2683     {
 2684         typedef BOOL (WINAPI *IsAppThemedType)();
 2685         // Unlike IsThemeActive, IsAppThemed will return false if the "Disable visual styles"
 2686         // compatibility setting is turned on for this script's EXE.
 2687         IsAppThemedType DynIsAppThemed = (IsAppThemedType)GetProcAddress(hinstTheme, "IsAppThemed");
 2688         if (DynIsAppThemed)
 2689             result = DynIsAppThemed();
 2690     }
 2691     return result;
 2692 }
 2693 
 2694 
 2695 
 2696 LPTSTR ConvertEscapeSequences(LPTSTR aBuf, TCHAR aEscapeChar, bool aAllowEscapedSpace)
 2697 // Replaces any escape sequences in aBuf with their reduced equivalent.  For example, if aEscapeChar
 2698 // is accent, Each `n would become a literal linefeed.  aBuf's length should always be the same or
 2699 // lower than when the process started, so there is no chance of overflow.
 2700 {
 2701     LPTSTR cp, cp1;
 2702     for (cp = aBuf; ; ++cp)  // Increment to skip over the symbol just found by the inner for().
 2703     {
 2704         for (; *cp && *cp != aEscapeChar; ++cp);  // Find the next escape char.
 2705         if (!*cp) // end of string.
 2706             break;
 2707         cp1 = cp + 1;
 2708         switch (*cp1)
 2709         {
 2710             // Only lowercase is recognized for these:
 2711             case 'a': *cp1 = '\a'; break;  // alert (bell) character
 2712             case 'b': *cp1 = '\b'; break;  // backspace
 2713             case 'f': *cp1 = '\f'; break;  // formfeed
 2714             case 'n': *cp1 = '\n'; break;  // newline
 2715             case 'r': *cp1 = '\r'; break;  // carriage return
 2716             case 't': *cp1 = '\t'; break;  // horizontal tab
 2717             case 'v': *cp1 = '\v'; break;  // vertical tab
 2718             case 's': // space (not always allowed for backward compatibility reasons).
 2719                 if (aAllowEscapedSpace)
 2720                     *cp1 = ' ';
 2721                 //else do nothing extra, just let the standard action for unrecognized escape sequences.
 2722                 break;
 2723             // Otherwise, if it's not one of the above, the escape-char is considered to
 2724             // mark the next character as literal, regardless of what it is. Examples:
 2725             // `` -> `
 2726             // `:: -> :: (effectively)
 2727             // `; -> ;
 2728             // `c -> c (i.e. unknown escape sequences resolve to the char after the `)
 2729         }
 2730         // Below has a final +1 to include the terminator:
 2731         tmemmove(cp, cp1, _tcslen(cp1) + 1);
 2732     }
 2733     return aBuf;
 2734 }
 2735 
 2736 
 2737 
 2738 int FindNextDelimiter(LPCTSTR aBuf, TCHAR aDelimiter, int aStartIndex, LPCTSTR aLiteralMap)
 2739 // Returns the index of the next delimiter, taking into account quotes, parentheses, etc.
 2740 // If the delimiter is not found, returns the length of aBuf.
 2741 {
 2742     bool in_quotes = false;
 2743     int open_parens = 0;
 2744     for (int mark = aStartIndex; ; ++mark)
 2745     {
 2746         if (aBuf[mark] == aDelimiter)
 2747         {
 2748             if (!in_quotes && open_parens <= 0 && !(aLiteralMap && aLiteralMap[mark]))
 2749                 // A delimiting comma other than one in a sub-statement or function.
 2750                 return mark;
 2751             // Otherwise, its a quoted/literal comma or one in parentheses (such as function-call).
 2752             continue;
 2753         }
 2754         switch (aBuf[mark])
 2755         {
 2756         case '"': // There are sections similar this one later below; so see them for comments.
 2757             in_quotes = !in_quotes;
 2758             break;
 2759         case '(': // For our purpose, "(", "[" and "{" can be treated the same.
 2760         case '[': // If they aren't balanced properly, a later stage will detect it.
 2761         case '{': //
 2762             if (!in_quotes) // Literal parentheses inside a quoted string should not be counted for this purpose.
 2763                 ++open_parens;
 2764             break;
 2765         case ')':
 2766         case ']':
 2767         case '}':
 2768             if (!in_quotes)
 2769                 --open_parens; // If this makes it negative, validation later on will catch the syntax error.
 2770             break;
 2771         case '\0':
 2772             // Reached the end of the string without finding a delimiter.  Return the
 2773             // index of the null-terminator since that's typically what the caller wants.
 2774             return mark;
 2775         //default: some other character; just have the loop skip over it.
 2776         }
 2777     }
 2778 }
 2779 
 2780 
 2781 
 2782 // FindExprDelim: The successor to FindNextDelimiter(), ported from the v2 branch.
 2783 int FindExprDelim(LPCTSTR aBuf, TCHAR aDelimiter, int aStartIndex, LPCTSTR aLiteralMap)
 2784 // Returns the index of the next delimiter, taking into account quotes, parentheses, etc.
 2785 // If the delimiter is not found, returns the length of aBuf.
 2786 {
 2787     TCHAR close_char;
 2788     for (int mark = aStartIndex; ; ++mark)
 2789     {
 2790         if (aBuf[mark] == aDelimiter && (aDelimiter != ':' || aBuf[mark+1] != '='))
 2791             return mark;
 2792         switch (aBuf[mark])
 2793         {
 2794         case '\0':
 2795             // Reached the end of the string without finding a delimiter.  Return the
 2796             // index of the null-terminator since that's typically what the caller wants.
 2797             return mark;
 2798         default:
 2799         //case '`': // May indicate an attempt to escape something when aLiteralMap==NULL, but escape has no meaning here.
 2800             // Not a meaningful character; just have the loop skip over it.
 2801             continue;
 2802         case '"':
 2803             do {
 2804                 ++mark;
 2805                 if (!aBuf[mark])
 2806                     return mark; // See case '\0' for comments.
 2807             } while (aBuf[mark] != '"');
 2808             continue;
 2809         case ')':
 2810         case ']':
 2811         case '}':
 2812             if (aDelimiter && aDelimiter != ':') // Caller wants to find a specific symbol and it's not this one.
 2813                 continue; // Unbalanced parentheses etc are caught at a later stage.
 2814             return mark;
 2815         case ':':
 2816             if (aDelimiter // See above.
 2817                 || aBuf[mark + 1] == '=')
 2818                 continue;
 2819             // Since aDelimiter is zero, this colon doesn't belong to a ternary expression
 2820             // or object literal which is part of this sub-expression, so should effectively
 2821             // terminate the sub-expression (likely a fat arrow function).
 2822             return mark;
 2823         case '?':
 2824             if (aDelimiter && aDelimiter != ':')
 2825                 continue; // The following isn't needed in this case.
 2826             // Scan for the corresponding ':' (or some other closing symbol if that's missing)
 2827             // so that it won't terminate the sub-expression.
 2828             mark = FindExprDelim(aBuf, ':', mark + 1, aLiteralMap);
 2829             if (!aBuf[mark]) // i.e. it isn't safe to do ++mark.
 2830                 return mark; // See case '\0' for comments.
 2831             continue; // The colon is also skipped via the loop's increment.
 2832         case '(': close_char = ')'; break;
 2833         case '[': close_char = ']'; break;
 2834         case '{': close_char = '}'; break;
 2835         }
 2836         // Since above didn't "return" or "continue":
 2837         mark = FindExprDelim(aBuf, close_char, mark + 1, aLiteralMap);
 2838         if (!aBuf[mark]) // i.e. it isn't safe to do ++mark.
 2839             return mark; // See case '\0' for comments.
 2840         // Otherwise, continue the loop.
 2841     } // for each character.
 2842 }
 2843 
 2844 
 2845 
 2846 bool IsStringInList(LPTSTR aStr, LPTSTR aList, bool aFindExactMatch)
 2847 // Checks if aStr exists in aList (which is a comma-separated list).
 2848 // If aStr is blank, aList must start with a delimiting comma for there to be a match.
 2849 {
 2850     // Must use a temp. buffer because otherwise there's no easy way to properly match upon strings
 2851     // such as the following:
 2852     // if var in string,,with,,literal,,commas
 2853     TCHAR buf[LINE_SIZE];
 2854     TCHAR *next_field, *cp, *end_buf = buf + _countof(buf) - 1;
 2855 
 2856     // v1.0.48.01: Performance improved by Lexikos.
 2857     for (TCHAR *this_field = aList; *this_field; this_field = next_field) // For each field in aList.
 2858     {
 2859         for (cp = buf, next_field = this_field; *next_field && cp < end_buf; ++cp, ++next_field) // For each char in the field, copy it over to temporary buffer.
 2860         {
 2861             if (*next_field == ',') // This is either a delimiter (,) or a literal comma (,,).
 2862             {
 2863                 ++next_field;
 2864                 if (*next_field != ',') // It's "," instead of ",," so treat it as the end of this field.
 2865                     break;
 2866                 // Otherwise it's ",," and next_field now points at the second comma; so copy that comma
 2867                 // over as a literal comma then continue copying.
 2868             }
 2869             *cp = *next_field;
 2870         }
 2871 
 2872         // The end of this field has been reached (or reached the capacity of the buffer), so terminate the string
 2873         // in the buffer.
 2874         *cp = '\0';
 2875 
 2876         if (*buf) // It is possible for this to be blank only for the first field.  Example: if var in ,abc
 2877         {
 2878             if (aFindExactMatch)
 2879             {
 2880                 if (!g_tcscmp(aStr, buf)) // Match found
 2881                     return true;
 2882             }
 2883             else // Substring match
 2884                 if (g_tcsstr(aStr, buf)) // Match found
 2885                     return true;
 2886         }
 2887         else // First item in the list is the empty string.
 2888             if (aFindExactMatch) // In this case, this is a match if aStr is also blank.
 2889             {
 2890                 if (!*aStr)
 2891                     return true;
 2892             }
 2893             else // Empty string is always found as a substring in any other string.
 2894                 return true;
 2895     } // for()
 2896 
 2897     return false;  // No match found.
 2898 }
 2899 
 2900 
 2901 
 2902 LPTSTR InStrAny(LPTSTR aStr, LPTSTR aNeedle[], int aNeedleCount, size_t &aFoundLen)
 2903 {
 2904     // For each character in aStr:
 2905     for ( ; *aStr; ++aStr)
 2906         // For each needle:
 2907         for (int i = 0; i < aNeedleCount; ++i)
 2908             // For each character in this needle:
 2909             for (LPTSTR needle_pos = aNeedle[i], str_pos = aStr; ; ++needle_pos, ++str_pos)
 2910             {
 2911                 if (!*needle_pos)
 2912                 {
 2913                     // All characters in needle matched aStr at this position, so we've
 2914                     // found our string.  If this needle is empty, it implicitly matches
 2915                     // at the first position in the string.
 2916                     aFoundLen = needle_pos - aNeedle[i];
 2917                     return aStr;
 2918                 }
 2919                 // Otherwise, we haven't reached the end of the needle. If we've reached
 2920                 // the end of aStr, *str_pos and *needle_pos won't match, so the check
 2921                 // below will break out of the loop.
 2922                 if (*needle_pos != *str_pos)
 2923                     // Not a match: continue on to the next needle, or the next starting
 2924                     // position in aStr if this is the last needle.
 2925                     break;
 2926             }
 2927     // If the above loops completed without returning, no matches were found.
 2928     return NULL;
 2929 }
 2930 
 2931 
 2932 
 2933 int CompareVersion(LPCTSTR a, LPCTSTR b)
 2934 {
 2935     while (*a || *b)
 2936     {
 2937         // 1.1-a001 < 1.1 = 1.1.0 = 1.1.0+foo
 2938         LPTSTR pa, pb;
 2939         int ia = _tcstol(a, &pa, 10);
 2940         int ib = _tcstol(b, &pb, 10);
 2941         // If *pa is not in the set .-+\0, this component is non-numeric (and not empty).
 2942         // Treat non-numeric as greater than numeric (but assume any absent component is 0).
 2943         if (!_tcschr(_T(".-+"), *pa)) ia = INT_MAX; else a = pa;
 2944         if (!_tcschr(_T(".-+"), *pb)) ib = INT_MAX; else b = pb;
 2945         if (ia < ib) return -1;
 2946         if (ia > ib) return  1;
 2947         // They are either equal or both non-numeric.
 2948         if (*a == '.' || *b == '.')
 2949         {
 2950             if (*a == '.') ++a;
 2951             if (*b == '.') ++b;
 2952             continue; // On to the next component.
 2953         }
 2954         // Give -pre-release lower precedence.
 2955         if (*a == '-' && *b != '-') return -1;
 2956         if (*b == '-' && *a != '-') return  1;
 2957         for (;; ++a, ++b)
 2958         {
 2959             auto ac = *a == '+' || *a == '.' ? '\0' : *a; // Ignore any + suffix (treat as terminator).
 2960             auto bc = *b == '+' || *b == '.' ? '\0' : *b;
 2961             if (ac != bc) return ac < bc ? -1 : 1;
 2962             if (!ac) // End of both components.
 2963             {
 2964                 if (*a == '.' || *b == '.')
 2965                     break; // Try to compare the next component as numeric.
 2966                 return 0; // Both reached the end; a and b are equal.
 2967             }
 2968         }
 2969     }
 2970     return 0;
 2971 }
 2972 
 2973 
 2974 
 2975 #if defined(_MSC_VER) && defined(_DEBUG)
 2976 void OutputDebugStringFormat(LPCTSTR fmt, ...)
 2977 {
 2978     CString sMsg;
 2979     va_list ap;
 2980 
 2981     va_start(ap, fmt);
 2982     sMsg.FormatV(fmt, ap);
 2983     OutputDebugString(sMsg);
 2984 }
 2985 #endif