How do I make it so that users can copy static text on a dialog box to the clipboard easily?


Given that you have a Win32 dialog box with static text in an LTEXT control, how do you make it so that users can easily copy that text to the clipboard?

The traditional solution is to create a borderless read-only edit control (which draws as static text by default). Add it to the tab order by setting the WS_TABSTOP style, and maybe even give it a keyboard accelerator for accessibility.

Starting in Windows Vista, version 6 of the common controls provides an alternative. (A less accessible alternative, mind you.) Static text controls automatically copy their contents to the clipboard when you double-click them if you set the SS_NOTIFY style.

Let’s try it:

#include <windows.h>
#include <windowsx.h>
#include <commctrl.h>

#pragma comment(linker, \
 "\"/manifestdependency:type='Win32' "\
 "name='Microsoft.Windows.Common-Controls' "\
 "version='6.0.0.0' "\
 "processorArchitecture='*' "\
 "publicKeyToken='6595b64144ccf1df' "\
 "language='*'\"")

INT_PTR CALLBACK DlgProc(
    HWND hdlg, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
 switch (uMsg) {
 case WM_INITDIALOG:
  return TRUE;
 case WM_COMMAND:
  switch (GET_WM_COMMAND_ID(wParam, lParam)) {
  case IDCANCEL:
   EndDialog(hdlg, 0);
   break;
  }
 }
 return FALSE;
}

int WINAPI WinMain(HINSTANCE hinst, HINSTANCE hinstPrev,
                   LPSTR lpCmdLine, int nShowCmd)
{
 return DialogBox(hinst, MAKEINTRESOURCE(1), NULL, DlgProc);
}

// resource file
#include <windows.h>

1 DIALOG 50, 50, 100, 50
STYLE DS_SHELLFONT | WS_SYSMENU
CAPTION "Sample"
FONT 8, "MS Shell Dlg"
BEGIN
 LTEXT "Sample text 1",100,10,10,80,10,SS_NOTIFY
 LTEXT "Sample text 2",101,10,20,80,10,SS_NOTIFY
 LTEXT "Sample text 3",102,10,30,80,10
END

Run this program and double-click on the text controls, and observe that the text gets copied to the clipboard, or at least it does for the first two, since I set the SS_NOTIFY style on them.

Now, when the double-click to copy feature was added to the static control, there was no way to suppress it. The STN_DBLCLK notification is documented as ignoring its return code, so it would be a compatibility problem if suddenly it started studying its return code so that the parent could respond “No, I handled the click, don’t do your default action.” Instead, if you want to disable the double-click to copy feature on a SS_NOTIFY static control, you have to subclass the static control and eat the clicks yourself.

LRESULT CALLBACK SuppressCopyOnClick(
    HWND hwnd, UINT uMsg, WPARAM wParam,
    LPARAM lParam, UINT_PTR uIdSubclass, DWORD_PTR dwRefData)
{
 switch (uMsg) {
 case WM_LBUTTONDBLCLK: return 0; // eat the double-click
 case WM_NCDESTROY:
  RemoveWindowSubclass(hwnd, SuppressCopyOnClick, uIdSubclass);
  break;
 }
 return DefSubclassProc(hwnd, uMsg, wParam, lParam);
}

INT_PTR CALLBACK DlgProc(
    HWND hdlg, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
 switch (uMsg) {
 case WM_INITDIALOG:
  SetWindowSubclass(GetDlgItem(hdlg, 101),
                    SuppressCopyOnClick, 0, 0);
  return TRUE;
 ...

“Why would you add a style that enabled a feature, and then disable the feature?”

Maybe you want some other aspects of the feature but not the copy-on-double-click behavior. Maybe somebody else is adding the SS_NOTIFY style behind your back. For example, a UI framework might add it automatically to all static controls.

And actually, in that UI framework case, you probably want the STN_DBLCLK notification to be fired when a double-click occurs, because you added an OnDoubleClick handler to your class. You just don’t want the copy-to-clipboard behavior. We can fix that by firing the notification in our subclass procedure.

 case WM_LBUTTONDBLCLK:
  if (GetWindowStyle(hwnd) & SS_NOTIFY) {
   FORWARD_WM_COMMAND(GetParent(hwnd), GetDlgCtrlID(hwnd), hwnd,
                      STN_DBLCLK, SendMessage);
  }
  return 0; // message handled

To illustrate this change, we’ll make our dialog box beep when it gets a double-click notification. In real life, of course, you would do whatever you want to happen on the “double click on a static control” event. Actually, in real life, the code that responds to the STN_DBLCLK lives inside your framework, and it turns around and raises an OnDoubleClick event, but for simplicity, we’ll just code it inline.

 case WM_COMMAND:
     switch (GET_WM_COMMAND_ID(wParam, lParam)) {
     case IDCANCEL:
        EndDialog(hdlg, 0);
        break;
     case 100:
     case 101:
     case 102:
      switch (GET_WM_COMMAND_CMD(wParam, lParam)) {
      // Obviously we would do something more interesting here
      case STN_DBLCLK: MessageBeep(MB_OK); break;
      }
     }

Each of the static controls on the dialog behaves differently. The first one is SS_NOTIFY with no subclassing, so double-clicking copies the text to the clipboard and also beeps. The second one is SS_NOTIFY with subclassing to disable the copy-to-clipboard, so double-clicking merely beeps. And the third one doesn’t have the SS_NOTIFY style at all, so it neither copies the next nor responds to double-click.

Comments (20)
  1. John says:

    [Static text controls automatically copy their contents to the clipboard when you double-click them if you set the SS_NOTIFY style.]

    The best part about this feature is that it's not documented (as far as I can tell).

  2. Rangoric says:

    Documented on Result #2 on a search engine for me: msdn.microsoft.com/…/bb760767(v=vs.85).aspx

  3. Mike Dimmick says:

    That, I'm afraid, smells like a feature that was needed in one place that leaked into the base implementation. It should have been a new SS_COPYTOCLIPBOARD style that people opted into, it's completely inappropriate to cause random new behaviour in existing applications.

    Yes, I know, you have to opt in to the new common controls via the manifest, but come on: you really think people are going to check that LABELS still have the same functionality before turning this on?

  4. Joshua says:

    I prefer the readonly text controls.

  5. JW says:

    While I don't mind the new feature (have to opt-in through the controls v6), I do agree that it is a very curious thing to add at this point. Also, besides the already mentioned issue of near impossible discoverability, there is no consistency nor feedback available either! This is almost as bad of an issue as the Ctrl+C for MessageBox, except that short-cut is universal and can eventually be discovered by a considerable leap of faith and frustration by a user with average Windows experience.

    Some text may or may not copy when you doubleclick, but the only way you will find out whether it did is by trying to paste something (and if you are unlucky, you just pasted 20 paragraphs from a letter you had been working on earlier…) The user never knows what to expect with regards to this control because its behaviour is not consistent.

    As for the feedback.. if I actually doubleclick something accidentally and it happens to copy something, I want to know so I don't end up tearing my hairs out wondering why the hell my clipboard got messed up. It best give some sort of visual feedback to avoid this problem. (I have not tested this; I can't make a test program right now and do not know where to find a label in the OS to test with; but as it was not mentioned I presume there is no such feedback at present.)

  6. John says:

    @Rangoric:  Where on that page does it mention anything about copying text to the clipboard?  Only in a comment posted by a user.

  7. jader3rd says:

    It's always painful to be reading text and not have the ability to copy it, regardless of the Control.

  8. Anonymous Coward says:

    And in addition to the flaws already mentioned, it is completely undiscoverable. But remember folks, this isn't "curious", it's called "design".

    [I agree with everyone else that this was a poorly-designed feature. But this is Practical Programming: Whether something was designed well or not, you still have to deal with it. -Raymond]
  9. Rangoric says:

    @John – "Where does it mention anything, ignoring where it says it". Um yes the comment. That comment is by someone who works for Microsoft and that comment has been there for 3 going on 4 years.

  10. Myria says:

    I've worked with the Windows API since Win16, and I didn't know that you could copy the contents of a MessageBoxW with control-C…

    By the way, I wish that Microsoft's example code would stop using the ANSI version of the Windows API.  Many programmers copy and paste such code.  I'm tired of applications that don't work the instant you try to give them a filename containing Unicode characters.  The example above should use wWinMain.  (Personally, I explicitly use the W versions of functions rather than rely upon the #define.)

  11. John says:

    @Rangoric:  Maybe it's just me, but I don't consider random posts in the comments section as "documentation" even if it is from an alleged Microsoft employee; have you seen some of the stuff that gets posted there?

  12. Marc says:

    I guess that  sums up Windows Vista :)

  13. Danny says:

    Please someone tell me I misread or interpret it wrongly. If you add a static text, starting with Vista, if you don't add the SS_NOTIFY style it will not fire the double click event. Because that is my understanding. Please tell me I got it wrong because if I got right…then LOOOOOOOOOOL…..and more……ROFLMAO…and even more LARONFLOOLMAOOOOO

  14. A. says:

    Wait a second… you mean if I absentmindedly double-click static text in a dialog it *might* copy it to the clipboard?  WTF?!! How are users supposed to know about this behavior change, if most developers don't even know about it!

  15. Ken Hagan says:

    @Rangoric – I don't normally google for biographies of people who add random comments to web pages, so it frankly doesn't matter how long this person has or has not been working for Microsoft. All I can see is a comment, made 3-4 years ago that *still* hasn't been incorporated into the official docs.

    To me, the most likely explanations are EITHER that the comment is untrue OR that this isn't behaviour that I should depend upon. Raymond's pretty much made a blogging career out of documenting the reasons why you shouldn't depend on something just because it happens to be true in the one version of Windows that you tried it on.

  16. waleri says:

    >>> so it would be a compatibility problem if suddenly it started studying its return code so that the parent could respond

    No, it wouldn't be. Old applications use old version, new applications use "version 6" – no problem to change behaviour for new apps. I understand, that changing "version 6" NOW would be potentially problematic, but still, it won't be a problem for "version 7" controls. Even adding SS_COPYTOCLIPBOARD won't be a compatibility problem for "version 7" – only it should be very well documented, listed in "changes since last version", etc…

    [This was a change to version 6, which already shipped in Windows XP. And you may have noticed that all the available style bits are used up. But as I noted earlier, I think this was a poorly-designed featured. -Raymond]
  17. TC says:

    @Ken Hagan

    > All I can see is a comment, made 3-4 years ago that *still* hasn't been incorporated into the official docs. To me, the most likely explanations are EITHER that the comment is untrue OR that this isn't behaviour that I should depend upon.

    Or (surely far more likely), they just don't read those comments at all – let alone submit them to their documentation update process.

  18. @Rangoric Even if this comment is from Microsoft employee, I don't consider it documentation. Additionally this comment must have been made on the page documenting the styles of static controls.

    Nevertheless this feature has to be *properly* documented.

  19. Joel says:

    @JW – I have been in IT for years, working exclusively in Windows, and didn't know about Ctrl-C on a Message box. I feel like I probably should (and also shouldn't have manually typed out so many message box errors!)

  20. waleri says:

    >> This was a change to version 6, which already shipped in Windows XP

    I agree about the design and I didn't notice, that all availabe style bits are used, however, nothing to stop you from changing the required OS version and/or any other means, included, but not limited to, additional API that would configure the particular flag usage or by specifying some configuration information in the manifest. Whether or not is worth the efforts is whole another issue.

Comments are closed.