diff --git a/modules/highgui/src/window_w32.cpp b/modules/highgui/src/window_w32.cpp index 8b317dff7..a7aca0ec4 100644 --- a/modules/highgui/src/window_w32.cpp +++ b/modules/highgui/src/window_w32.cpp @@ -1286,6 +1286,10 @@ MainWindowProc( HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam ) switch(uMsg) { + case WM_COPY: + ::WindowProc(hwnd, uMsg, wParam, lParam); // call highgui proc. There may be a better way to do this. + break; + case WM_DESTROY: icvRemoveWindow(window); @@ -1448,6 +1452,81 @@ static LRESULT CALLBACK HighGUIProc( HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM // Process the message switch(uMsg) { + case WM_COPY: + { + if (!::OpenClipboard(hwnd) ) + break; + + HDC hDC = 0; + HDC memDC = 0; + HBITMAP memBM = 0; + + // We'll use a do-while(0){} scope as a single-run breakable scope + // Upon any error we can jump out of the single-time while scope to clean up the resources. + do + { + if (!::EmptyClipboard()) + break; + + if(!window->image) + break; + + // Get window device context + if (0 == (hDC = ::GetDC(hwnd))) + break; + + // Create another DC compatible with hDC + if (0 == (memDC = ::CreateCompatibleDC( hDC ))) + break; + + // Determine the bitmap's dimensions + int nchannels = 3; + SIZE size = {0,0}; + icvGetBitmapData( window, &size, &nchannels, 0 ); + + // Create bitmap to draw on and it in the new DC + if (0 == (memBM = ::CreateCompatibleBitmap ( hDC, size.cx, size.cy))) + break; + + if (!::SelectObject( memDC, memBM )) + break; + + // Begin drawing to DC + if (!::SetStretchBltMode(memDC, COLORONCOLOR)) + break; + + RGBQUAD table[256]; + if( 1 == nchannels ) + { + for(int i = 0; i < 256; ++i) + { + table[i].rgbBlue = (unsigned char)i; + table[i].rgbGreen = (unsigned char)i; + table[i].rgbRed = (unsigned char)i; + } + if (!::SetDIBColorTable(window->dc, 0, 255, table)) + break; + } + + // The image copied to the clipboard will be in its original size, regardless if the window itself was resized. + + // Render the image to the dc/bitmap (at original size). + if (!::BitBlt( memDC, 0, 0, size.cx, size.cy, window->dc, 0, 0, SRCCOPY )) + break; + + // Finally, set bitmap to clipboard + ::SetClipboardData(CF_BITMAP, memBM); + } while (0,0); // (0,0) instead of (0) to avoid MSVC compiler warning C4127: "conditional expression is constant" + + ////////////////////////////////////////////////////////////////////////// + // if handle is allocated (i.e. != 0) then clean-up. + memBM && ::DeleteObject(memBM); + memDC && ::DeleteDC(memDC); + hDC && ::ReleaseDC(hwnd, hDC); + ::CloseClipboard(); + break; + } + case WM_WINDOWPOSCHANGING: { LPWINDOWPOS pos = (LPWINDOWPOS)lParam; @@ -1798,6 +1877,11 @@ cvWaitKey( int delay ) is_processed = 1; return (int)(message.wParam << 16); } + + // Intercept Ctrl+C for copy to clipboard + if ('C' == message.wParam && (::GetKeyState(VK_CONTROL)>>15)) + ::PostMessage(message.hwnd, WM_COPY, 0, 0); + default: DispatchMessage(&message); is_processed = 1;