"Fossies" - the Fresh Open Source Software Archive

Member "AutoHotkey_L-1.1.33.09/source/clipboard.cpp" (8 May 2021, 25542 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 "clipboard.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 "clipboard.h"
   19 #include "globaldata.h"  // for g_script.ScriptError() and g_ClipboardTimeout
   20 #include "application.h" // for MsgSleep()
   21 #include "util.h" // for strlcpy()
   22 
   23 size_t Clipboard::Get(LPTSTR aBuf)
   24 // If aBuf is NULL, it returns the length of the text on the clipboard and leaves the
   25 // clipboard open.  Otherwise, it copies the clipboard text into aBuf and closes
   26 // the clipboard (UPDATE: But only if the clipboard is still open from a prior call
   27 // to determine the length -- see later comments for details).  In both cases, the
   28 // length of the clipboard text is returned (or the value CLIPBOARD_FAILURE if error).
   29 // If the clipboard is still open when the next MsgSleep() is called -- presumably
   30 // because the caller never followed up with a second call to this function, perhaps
   31 // due to having insufficient memory -- MsgSleep() will close it so that our
   32 // app doesn't keep the clipboard tied up.  Note: In all current cases, the caller
   33 // will use MsgBox to display an error, which in turn calls MsgSleep(), which will
   34 // immediately close the clipboard.
   35 {
   36     // Seems best to always have done this even if we return early due to failure:
   37     if (aBuf)
   38         // It should be safe to do this even at its peak capacity, because caller
   39         // would have then given us the last char in the buffer, which is already
   40         // a zero terminator, so this would have no effect:
   41         *aBuf = '\0';
   42 
   43     UINT i, file_count = 0;
   44     BOOL clipboard_contains_text = IsClipboardFormatAvailable(CF_NATIVETEXT);
   45     BOOL clipboard_contains_files = IsClipboardFormatAvailable(CF_HDROP);
   46     if (!(clipboard_contains_text || clipboard_contains_files))
   47         return 0;
   48 
   49     if (!mIsOpen)
   50     {
   51         // As a precaution, don't give the caller anything from the clipboard
   52         // if the clipboard isn't already open from the caller's previous
   53         // call to determine the size of what's on the clipboard (no other app
   54         // can alter its size while we have it open).  The is to prevent a
   55         // buffer overflow from happening in a scenario such as the following:
   56         // Caller calls us and we return zero size, either because there's no
   57         // CF_TEXT on the clipboard or there was a problem opening the clipboard.
   58         // In these two cases, the clipboard isn't open, so by the time the
   59         // caller calls us again, there's a chance (vanishingly small perhaps)
   60         // that another app (if our thread were preempted long enough, or the
   61         // platform is multiprocessor) will have changed the contents of the
   62         // clipboard to something larger than zero.  Thus, if we copy that
   63         // into the caller's buffer, the buffer might overflow:
   64         if (aBuf)
   65             return 0;
   66         if (!Open())
   67         {
   68             // Since this should be very rare, a shorter message is now used.  Formerly, it was
   69             // "Could not open clipboard for reading after many timed attempts. Another program is probably holding it open."
   70             Close(CANT_OPEN_CLIPBOARD_READ);
   71             return CLIPBOARD_FAILURE;
   72         }
   73         if (   !(mClipMemNow = g_clip.GetClipboardDataTimeout(clipboard_contains_text ? CF_NATIVETEXT : CF_HDROP))   )
   74         {
   75             // v1.0.47.04: Commented out the following that had been in effect when clipboard_contains_files==false:
   76             //    Close("GetClipboardData"); // Short error message since so rare.
   77             //    return CLIPBOARD_FAILURE;
   78             // This was done because there are situations when GetClipboardData can fail indefinitely.
   79             // For example, in Firefox, pulling down the Bookmarks menu then right-clicking "Bookmarks Toolbar
   80             // Folder" then selecting "Copy" puts one or more formats on the clipboard that cause this problem.
   81             // For details, search the forum for TYMED_NULL.
   82             //
   83             // v1.0.42.03: For the fix below, GetClipboardDataTimeout() knows not to try more than once
   84             // for CF_HDROP.
   85             // Fix for v1.0.31.02: When clipboard_contains_files==true, tolerate failure, which happens
   86             // as a normal/expected outcome when there are files on the clipboard but either:
   87             // 1) zero of them;
   88             // 2) the CF_HDROP on the clipboard is somehow misformatted.
   89             // If you select the parent ".." folder in WinRar then use the following hotkey, the script
   90             // would previously yield a runtime error:
   91             //#q::
   92             //Send, ^c
   93             //ClipWait, 0.5, 1
   94             //msgbox %Clipboard%
   95             //Return
   96             Close();
   97             if (aBuf)
   98                 *aBuf = '\0';
   99             return CLIPBOARD_FAILURE; // Return this because otherwise, Contents() returns mClipMemNowLocked, which is NULL.
  100         }
  101         // Although GlobalSize(mClipMemNow) can yield zero in some cases -- in which case GlobalLock() should
  102         // not be attempted -- it probably can't yield zero for CF_HDROP and CF_TEXT because such a thing has
  103         // never been reported by anyone.  Therefore, GlobalSize() is currently not called.
  104         if (   !(mClipMemNowLocked = (LPTSTR)GlobalLock(mClipMemNow))   )
  105         {
  106             Close(_T("GlobalLock"));  // Short error message since so rare.
  107             return CLIPBOARD_FAILURE;
  108         }
  109         // Otherwise: Update length after every successful new open&lock:
  110         // Determine the length (size - 1) of the buffer than would be
  111         // needed to hold what's on the clipboard:
  112         if (clipboard_contains_text)
  113         {
  114             // See below for comments.
  115             mLength = _tcslen(mClipMemNowLocked);
  116         }
  117         else // clipboard_contains_files
  118         {
  119             if (file_count = DragQueryFile((HDROP)mClipMemNowLocked, 0xFFFFFFFF, _T(""), 0))
  120             {
  121                 mLength = (file_count - 1) * 2;  // Init; -1 if don't want a newline after last file.
  122                 for (i = 0; i < file_count; ++i)
  123                     mLength += DragQueryFile((HDROP)mClipMemNowLocked, i, NULL, 0);
  124             }
  125             else
  126                 mLength = 0;
  127         }
  128         if (mLength >= CLIPBOARD_FAILURE) // Can't realistically happen, so just indicate silent failure.
  129             return CLIPBOARD_FAILURE;
  130     }
  131     if (!aBuf)
  132         return mLength;
  133         // Above: Just return the length; don't close the clipboard because we expect
  134         // to be called again soon.  If for some reason we aren't called, MsgSleep()
  135         // will automatically close the clipboard and clean up things.  It's done this
  136         // way to avoid the chance that the clipboard contents (and thus its length)
  137         // will change while we don't have it open, possibly resulting in a buffer
  138         // overflow.  In addition, this approach performs better because it avoids
  139         // the overhead of having to close and reopen the clipboard.
  140 
  141     // Otherwise:
  142     if (clipboard_contains_text) // Fixed for v1.1.16.02: Prefer text over files if both are present.
  143     {
  144         // Because the clipboard is being retrieved as text, return this text even if
  145         // the clipboard also contains files.  Contents() relies on this since it only
  146         // calls Get() once and does not provide a buffer.  Contents() would be used
  147         // in "c := Clipboard" or "MsgBox %Clipboard%" because ArgMustBeDereferenced()
  148         // returns true only if the clipboard contains files but not text.
  149         _tcscpy(aBuf, mClipMemNowLocked);  // Caller has already ensured that aBuf is large enough.
  150     }
  151     else // clipboard_contains_files
  152     {
  153         if (file_count = DragQueryFile((HDROP)mClipMemNowLocked, 0xFFFFFFFF, _T(""), 0))
  154             for (i = 0; i < file_count; ++i)
  155             {
  156                 // Caller has already ensured aBuf is large enough to hold them all:
  157                 aBuf += DragQueryFile((HDROP)mClipMemNowLocked, i, aBuf, 999);
  158                 if (i < file_count - 1) // i.e. don't add newline after the last filename.
  159                 {
  160                     *aBuf++ = '\r';  // These two are the proper newline sequence that the OS prefers.
  161                     *aBuf++ = '\n';
  162                 }
  163                 //else DragQueryFile() has ensured that aBuf is terminated.
  164             }
  165         // else aBuf has already been terminated upon entrance to this function.
  166     }
  167     // Fix for v1.0.37: Close() is no longer called here because it prevents the clipboard variable
  168     // from being referred to more than once in a line.  For example:
  169     // Msgbox %Clipboard%%Clipboard%
  170     // ToolTip % StrLen(Clipboard) . Clipboard
  171     // Instead, the clipboard is later closed in other places (search on CLOSE_CLIPBOARD_IF_OPEN
  172     // to find them).  The alternative to fixing it this way would be to let it reopen the clipboard
  173     // by means getting rid of the following lines above:
  174     //if (aBuf)
  175     //  return 0;
  176     // However, that has the risks described in the comments above those two lines.
  177     return mLength;
  178 }
  179 
  180 
  181 
  182 ResultType Clipboard::Set(LPCTSTR aBuf, UINT_PTR aLength)
  183 // Returns OK or FAIL.
  184 {
  185     // It was already open for writing from a prior call.  Return failure because callers that do this
  186     // are probably handling things wrong:
  187     if (IsReadyForWrite()) return FAIL;
  188 
  189     if (!aBuf)
  190     {
  191         aBuf = _T("");
  192         aLength = 0;
  193     }
  194     else
  195         if (aLength == UINT_MAX) // Caller wants us to determine the length.
  196             aLength = (UINT)_tcslen(aBuf);
  197 
  198     if (aLength)
  199     {
  200         if (!PrepareForWrite(aLength + 1))
  201             return FAIL;  // It already displayed the error.
  202         tcslcpy(mClipMemNewLocked, aBuf, aLength + 1);  // Copy only a substring, if aLength specifies such.
  203     }
  204     // else just do the below to empty the clipboard, which is different than setting
  205     // the clipboard equal to the empty string: it's not truly empty then, as reported
  206     // by IsClipboardFormatAvailable(CF_TEXT) -- and we want to be able to make it truly
  207     // empty for use with functions such as ClipWait:
  208     return Commit();  // It will display any errors.
  209 }
  210 
  211 
  212 
  213 LPTSTR Clipboard::PrepareForWrite(size_t aAllocSize)
  214 {
  215     if (!aAllocSize) return NULL; // Caller should ensure that size is at least 1, i.e. room for the zero terminator.
  216     if (IsReadyForWrite())
  217         // It was already prepared due to a prior call.  Currently, the most useful thing to do
  218         // here is return the memory area that's already been reserved:
  219         return mClipMemNewLocked;
  220     // Note: I think GMEM_DDESHARE is recommended in addition to the usual GMEM_MOVEABLE:
  221     // UPDATE: MSDN: "The following values are obsolete, but are provided for compatibility
  222     // with 16-bit Windows. They are ignored.": GMEM_DDESHARE
  223     if (   !(mClipMemNew = GlobalAlloc(GMEM_MOVEABLE, aAllocSize * sizeof(TCHAR)))   )
  224     {
  225         g_script.ScriptError(_T("GlobalAlloc"));  // Short error message since so rare.
  226         return NULL;
  227     }
  228     if (   !(mClipMemNewLocked = (LPTSTR)GlobalLock(mClipMemNew))   )
  229     {
  230         mClipMemNew = GlobalFree(mClipMemNew);  // This keeps mClipMemNew in sync with its state.
  231         g_script.ScriptError(_T("GlobalLock")); // Short error message since so rare.
  232         return NULL;
  233     }
  234     mCapacity = (UINT)aAllocSize; // Keep mCapacity in sync with the state of mClipMemNewLocked.
  235     *mClipMemNewLocked = '\0'; // Init for caller.
  236     return mClipMemNewLocked;  // The caller can now write to this mem.
  237 }
  238 
  239 
  240 
  241 ResultType Clipboard::Commit(UINT aFormat)
  242 // If this is called while mClipMemNew is NULL, the clipboard will be set to be truly
  243 // empty, which is different from writing an empty string to it.  Note: If the clipboard
  244 // was already physically open, this function will close it as part of the commit (since
  245 // whoever had it open before can't use the prior contents, since they're invalid).
  246 {
  247     if (!mIsOpen && !Open())
  248         // Since this should be very rare, a shorter message is now used.  Formerly, it was
  249         // "Could not open clipboard for writing after many timed attempts.  Another program is probably holding it open."
  250         return AbortWrite(CANT_OPEN_CLIPBOARD_WRITE);
  251     if (!EmptyClipboard())
  252     {
  253         Close();
  254         return AbortWrite(_T("EmptyClipboard")); // Short error message since so rare.
  255     }
  256     if (mClipMemNew)
  257     {
  258         bool new_is_empty = false;
  259         // Unlock prior to calling SetClipboardData:
  260         if (mClipMemNewLocked) // probably always true if we're here.
  261         {
  262             // Best to access the memory while it's still locked, which is why this temp var is used:
  263             // v1.0.40.02: The following was fixed to properly recognize 0x0000 as the Unicode string terminator,
  264             // which fixes problems with Transform Unicode.
  265             new_is_empty = aFormat == CF_UNICODETEXT ? !*(LPWSTR)mClipMemNewLocked : !*(LPSTR)mClipMemNewLocked;
  266             GlobalUnlock(mClipMemNew); // mClipMemNew not mClipMemNewLocked.
  267             mClipMemNewLocked = NULL;  // Keep this in sync with the above action.
  268             mCapacity = 0; // Keep mCapacity in sync with the state of mClipMemNewLocked.
  269         }
  270         if (new_is_empty)
  271             // Leave the clipboard truly empty rather than setting it to be the
  272             // empty string (i.e. these two conditions are NOT the same).
  273             // But be sure to free the memory since we're not giving custody
  274             // of it to the system:
  275             mClipMemNew = GlobalFree(mClipMemNew);
  276         else
  277             if (SetClipboardData(aFormat, mClipMemNew))
  278                 // In any of the failure conditions above, Close() ensures that mClipMemNew is
  279                 // freed if it was allocated.  But now that we're here, the memory should not be
  280                 // freed because it is owned by the clipboard (it will free it at the appropriate time).
  281                 // Thus, we relinquish the memory because we shouldn't be looking at it anymore:
  282                 mClipMemNew = NULL;
  283             else
  284             {
  285                 Close();
  286                 return AbortWrite(_T("SetClipboardData")); // Short error message since so rare.
  287             }
  288     }
  289     // else we will close it after having done only the EmptyClipboard(), above.
  290     // Note: Decided not to update mLength for performance reasons (in case clipboard is huge).
  291     // Anyway, it seems rather pointless because once the clipboard is closed, our app instantly
  292     // loses sight of how large it is, so the the value of mLength wouldn't be reliable unless
  293     // the clipboard were going to be immediately opened again.
  294     return Close();
  295 }
  296 
  297 
  298 
  299 ResultType Clipboard::AbortWrite(LPTSTR aErrorMessage)
  300 // Always returns FAIL.
  301 {
  302     // Since we were called in conjunction with an aborted attempt to Commit(), always
  303     // ensure the clipboard is physically closed because even an attempt to Commit()
  304     // should physically close it:
  305     Close();
  306     if (mClipMemNewLocked)
  307     {
  308         GlobalUnlock(mClipMemNew); // mClipMemNew not mClipMemNewLocked.
  309         mClipMemNewLocked = NULL;
  310         mCapacity = 0; // Keep mCapacity in sync with the state of mClipMemNewLocked.
  311     }
  312     // Above: Unlock prior to freeing below.
  313     if (mClipMemNew)
  314         mClipMemNew = GlobalFree(mClipMemNew);
  315     // Caller needs us to always return FAIL:
  316     return *aErrorMessage ? g_script.ScriptError(aErrorMessage) : FAIL;
  317 }
  318 
  319 
  320 
  321 ResultType Clipboard::Close(LPTSTR aErrorMessage)
  322 // Returns OK or FAIL (but it only returns FAIL if caller gave us a non-NULL aErrorMessage).
  323 {
  324     // Always close it ASAP so that it is free for other apps to use:
  325     if (mIsOpen)
  326     {
  327         if (mClipMemNowLocked)
  328         {
  329             GlobalUnlock(mClipMemNow); // mClipMemNow not mClipMemNowLocked.
  330             mClipMemNowLocked = NULL;  // Keep this in sync with its state, since it's used as an indicator.
  331         }
  332         // Above: It's probably best to unlock prior to closing the clipboard.
  333         CloseClipboard();
  334         mIsOpen = false;  // Even if above fails (realistically impossible?), seems best to do this.
  335         // Must do this only after GlobalUnlock():
  336         mClipMemNow = NULL;
  337     }
  338     // Do this cleanup for callers that didn't make it far enough to even open the clipboard.
  339     // UPDATE: DO *NOT* do this because it is valid to have the clipboard in a "ReadyForWrite"
  340     // state even after we physically close it.  Some callers rely on that.
  341     //if (mClipMemNewLocked)
  342     //{
  343     //  GlobalUnlock(mClipMemNew); // mClipMemNew not mClipMemNewLocked.
  344     //  mClipMemNewLocked = NULL;
  345     //  mCapacity = 0; // Keep mCapacity in sync with the state of mClipMemNewLocked.
  346     //}
  347     //// Above: Unlock prior to freeing below.
  348     //if (mClipMemNew)
  349     //  // Commit() was never called after a call to PrepareForWrite(), so just free the memory:
  350     //  mClipMemNew = GlobalFree(mClipMemNew);
  351     if (aErrorMessage && *aErrorMessage)
  352         // Caller needs us to always return FAIL if an error was displayed:
  353         return g_script.ScriptError(aErrorMessage);
  354 
  355     // Seems best not to reset mLength.  But it will quickly become out of date once
  356     // the clipboard has been closed and other apps can use it.
  357     return OK;
  358 }
  359 
  360 
  361 
  362 HANDLE Clipboard::GetClipboardDataTimeout(UINT uFormat, BOOL *aNullIsOkay)
  363 // Update for v1.1.16: The comments below are obsolete; search for "v1.1.16" for related comments.
  364 // Same as GetClipboardData() except that it doesn't give up if the first call to GetClipboardData() fails.
  365 // Instead, it continues to retry the operation for the number of milliseconds in g_ClipboardTimeout.
  366 // This is necessary because GetClipboardData() has been observed to fail in repeatable situations (this
  367 // is strange because our thread already has the clipboard locked open -- presumably it happens because the
  368 // GetClipboardData() is unable to start a data stream from the application that actually serves up the data).
  369 // If cases where the first call to GetClipboardData() fails, a subsequent call will often succeed if you give
  370 // the owning application (such as Excel and Word) a little time to catch up.  This is especially necessary in
  371 // the OnClipboardChange label, where sometimes a clipboard-change notification comes in before the owning
  372 // app has finished preparing its data for subsequent readers of the clipboard.
  373 {
  374 #ifdef DEBUG_BY_LOGGING_CLIPBOARD_FORMATS  // Provides a convenient log of clipboard formats for analysis.
  375     static FILE *fp = fopen("c:\\debug_clipboard_formats.txt", "w");
  376 #endif
  377 
  378     if (aNullIsOkay)
  379         *aNullIsOkay = FALSE; // Set default.
  380 
  381     TCHAR format_name[MAX_PATH + 1]; // MSDN's RegisterClipboardFormat() doesn't document any max length, but the ones we're interested in certainly don't exceed MAX_PATH.
  382     if (uFormat < 0xC000 || uFormat > 0xFFFF) // It's a registered format (you're supposed to verify in-range before calling GetClipboardFormatName()).  Also helps performance.
  383         *format_name = '\0'; // Don't need the name if it's a standard/CF_* format.
  384     else
  385     {
  386         // v1.0.42.04:
  387         // Probably need to call GetClipboardFormatName() rather than comparing directly to uFormat because
  388         // MSDN implies that OwnerLink and other registered formats might not always have the same ID under
  389         // all OSes (past and future).
  390         GetClipboardFormatName(uFormat, format_name, MAX_PATH);
  391         // Since RegisterClipboardFormat() is case insensitive, the case might vary.  So use stricmp() when
  392         // comparing format_name to anything.
  393         // "Link Source", "Link Source Descriptor" , and anything else starting with "Link Source" is likely
  394         // to be data that should not be attempted to be retrieved because:
  395         // 1) It causes unwanted bookmark effects in various versions of MS Word.
  396         // 2) Tests show that these formats are on the clipboard only if MS Word is open at the time
  397         //    ClipboardAll is accessed.  That implies they're transitory formats that aren't as essential
  398         //    or well suited to ClipboardAll as the other formats (but if it weren't for #1 above, this
  399         //    wouldn't be enough reason to omit it).
  400         // 3) Although there is hardly any documentation to be found at MSDN or elsewhere about these formats,
  401         //    it seems they're related to OLE, with further implications that the data is transitory.
  402         // Here are the formats that Word 2002 removes from the clipboard when it the app closes:
  403         // 0xC002 ObjectLink  >>> Causes WORD bookmarking problem.
  404         // 0xC003 OwnerLink
  405         // 0xC00D Link Source  >>> Causes WORD bookmarking problem.
  406         // 0xC00F Link Source Descriptor  >>> Doesn't directly cause bookmarking, but probably goes with above.
  407         // 0xC0DC Hyperlink
  408         if (   !_tcsnicmp(format_name, _T("Link Source"), 11) || !_tcsicmp(format_name, _T("ObjectLink"))
  409             || !_tcsicmp(format_name, _T("OwnerLink"))
  410             // v1.0.44.07: The following were added to solve interference with MS Outlook's MS Word editor.
  411             // If a hotkey like ^F1::ClipboardSave:=ClipboardAll is pressed after pressing Ctrl-C in that
  412             // editor (perhaps only when copying HTML), two of the following error dialogs would otherwise
  413             // be displayed (this occurs in Outlook 2002 and probably later versions):
  414             // "An outgoing call cannot be made since the application is dispatching an input-synchronous call."
  415             || !_tcsicmp(format_name, _T("Native")) || !_tcsicmp(format_name, _T("Embed Source"))   )
  416             return NULL;
  417         if (!_tcsicmp(format_name, _T("MSDEVColumnSelect")) || !_tcsicmp(format_name, _T("MSDEVLineSelect")))
  418         {
  419             // v1.1.16: These formats are used by Visual Studio, Scintilla controls and perhaps others for
  420             // copying whole lines and rectangular blocks.  Because their very presence/absence is used as
  421             // a boolean indicator, the data is irrelevant.  Presumably for this reason, Scintilla controls
  422             // set NULL data, though doing so and then not handling WM_RENDERFORMAT is probably invalid.
  423             // Note newer versions of Visual Studio use "VisualStudioEditorOperationsLineCutCopyClipboardTag"
  424             // for line copy, but that doesn't need to be handled here because it has non-NULL data (and the
  425             // latest unreleased Scintilla [as at 2014-08-19] uses both, so we can discard the long one).
  426             // Since we just want to preserve this format's presence, indicate to caller that NULL is okay:
  427             if (aNullIsOkay) // i.e. caller passed a variable for us to set.
  428                 *aNullIsOkay = TRUE;
  429             return NULL;
  430         }
  431     }
  432 
  433 #ifdef DEBUG_BY_LOGGING_CLIPBOARD_FORMATS
  434     _ftprintf(fp, _T("%04X\t%s\n"), uFormat, format_name);  // Since fclose() is never called, the program has to exit to close/release the file.
  435 #endif
  436 
  437 #ifndef ENABLE_CLIPBOARDGETDATA_TIMEOUT
  438     // v1.1.16: The timeout and retry behaviour of this function is currently disabled, since it does more
  439     // harm than good.  It previously did NO GOOD WHATSOEVER, because SLEEP_WITHOUT_INTERRUPTION indirectly
  440     // calls g_clip.Close() via CLOSE_CLIPBOARD_IF_OPEN, so any subsequent attempts to retrieve data by us
  441     // or our caller always fail.  The main point of failure where retrying helps is OpenClipboard(), when
  442     // another program has the clipboard open -- and that's handled elsewhere.  If the timeout is re-enabled
  443     // for this function, the following format will need to be excluded to prevent unnecessary delays:
  444     //  - FileContents (CSTR_FILECONTENTS): MSDN says it is used "to transfer data as if it were a file,
  445     //    regardless of how it is actually stored".  For example, it could be a file inside a zip folder.
  446     //    However, on Windows 8 it seems to also be present for normal files.  It might be possible to
  447     //    retrieve its data via OleGetClipboard(), though it could be very large.
  448 
  449     // Just return the data, even if NULL:
  450     return GetClipboardData(uFormat);
  451 #else
  452     HANDLE h;
  453     for (DWORD start_time = GetTickCount();;)
  454     {
  455         // Known failure conditions:
  456         // GetClipboardData() apparently fails when the text on the clipboard is greater than a certain size
  457         // (Even though GetLastError() reports "Operation completed successfully").  The data size at which
  458         // this occurs is somewhere between 20 to 96 MB (perhaps depending on system's memory and CPU speed).
  459         if (h = GetClipboardData(uFormat)) // Assign
  460             return h;
  461 
  462         // It failed, so act according to the type of format and the timeout that's in effect.
  463         // Certain standard (numerically constant) clipboard formats are known to validly yield NULL from a
  464         // call to GetClipboardData().  Never retry these because it would only cause unnecessary delays
  465         // (i.e. a failure until timeout).
  466         // v1.0.42.04: More importantly, retrying them appears to cause problems with saving a Word/Excel
  467         // clipboard via ClipboardAll.
  468         if (uFormat == CF_HDROP // This format can fail "normally" for the reasons described at "clipboard_contains_files".
  469             || !_tcsicmp(format_name, _T("OwnerLink"))) // Known to validly yield NULL from a call to GetClipboardData(), so don't retry it to avoid having to wait the full timeout period.
  470             return NULL;
  471 
  472         if (g_ClipboardTimeout != -1) // We were not told to wait indefinitely and...
  473             if (!g_ClipboardTimeout   // ...we were told to make only one attempt, or ...
  474                 || (int)(g_ClipboardTimeout - (GetTickCount() - start_time)) <= SLEEP_INTERVAL_HALF) //...it timed out.
  475                 // Above must cast to int or any negative result will be lost due to DWORD type.
  476                 return NULL;
  477 
  478         // Use SLEEP_WITHOUT_INTERRUPTION to prevent MainWindowProc() from accepting new hotkeys
  479         // during our operation, since a new hotkey subroutine might interfere with
  480         // what we're doing here (e.g. if it tries to use the clipboard, or perhaps overwrites
  481         // the deref buffer if this object's caller gave it any pointers into that memory area):
  482         SLEEP_WITHOUT_INTERRUPTION(INTERVAL_UNSPECIFIED)
  483     }
  484 #endif
  485 }
  486 
  487 
  488 
  489 ResultType Clipboard::Open()
  490 {
  491     if (mIsOpen)
  492         return OK;
  493     for (DWORD start_time = GetTickCount();;)
  494     {
  495         if (OpenClipboard(g_hWnd))
  496         {
  497             mIsOpen = true;
  498             return OK;
  499         }
  500         if (g_ClipboardTimeout != -1) // We were not told to wait indefinitely...
  501             if (!g_ClipboardTimeout   // ...and we were told to make only one attempt, or ...
  502                 || (int)(g_ClipboardTimeout - (GetTickCount() - start_time)) <= SLEEP_INTERVAL_HALF) //...it timed out.
  503                 // Above must cast to int or any negative result will be lost due to DWORD type.
  504                 return FAIL;
  505         // Use SLEEP_WITHOUT_INTERRUPTION to prevent MainWindowProc() from accepting new hotkeys
  506         // during our operation, since a new hotkey subroutine might interfere with
  507         // what we're doing here (e.g. if it tries to use the clipboard, or perhaps overwrites
  508         // the deref buffer if this object's caller gave it any pointers into that memory area):
  509         SLEEP_WITHOUT_INTERRUPTION(INTERVAL_UNSPECIFIED)
  510     }
  511 }