矩形領域を Clipbord に書き出す

マウス操作で選択された矩形領域をクリップボードに書き出します。
またクリップボードから画像を読み出して画面に表示します。

前田稔(Maeda Minoru)の超初心者のプログラム入門

クリップボードに書き出す

表示中の画面から矩形選択して書き出す手順は次のようになります。
  1. Window を生成した後で矩形領域を選択する透明のもう一つの Window を作成します。
  2. トップレベルに表示中の自分自身の Window を隠します。
  3. 矩形領域を選択するために画面いっぱいに透明の Window を貼り付けます。
  4. 透明 Window で矩形領域を設定して取り込む範囲を定めます。
  5. 透明 Window の hdc を取得します。
  6. hdc と互換性のあるメモリデバイスコンテキストを作ります。
  7. hdc と互換性のあるビットマップを作成します。
  8. メモリデバイスコンテキストにこのビットマップを選択します。
  9. StretchBlt で hdc をメモリデバイスコンテキストに転送します。
  10. ビットマップをクリップボードに転送します。
  11. 不要になったデバイスコンテキストを破棄します。
  12. 透明 Window を隠して、本来の Window を表示します。

プログラムの説明

それでは具体的に説明して行きましょう。
  1. Global Area に本来の Window(hMain)と透明 Window(hWhole)のハンドルを定義します。
    bCap と bBlock は矩形領域を設定するためのフラグです。
    本来の Window を作成した後で、透明 Window を生成する関数 CreateMyChild() を呼び出します。
        HWND        hWhole, hMain;
        BOOL        bCap, bBlock;
                    :
        //★ Windows Main 関数
        int WINAPI WinMain(...)
                    :
            if (!hWnd)  return FALSE;
    
            hMain = hWnd;
            CreateMyChild(hWnd);
                    :
        
  2. 透明 Window(NULL_BRUSH) を生成してその HWND を hWhole に格納する CreateMyChild() です。
    サイズは画面全体の大きさに設定します。(GetSystemMetrics())
        int CreateMyChild(HWND hWnd)
        {       :
            wc.lpfnWndProc = WholeProc;     //プロシージャ名
            wc.hbrBackground = (HBRUSH)GetStockObject(NULL_BRUSH);
            hInst = (HINSTANCE)GetWindowLong(hWnd, GWL_HINSTANCE);
                :
            RegisterClassEx(&wc);
    
            hwnd = CreateWindow("WHOLE", "", WS_POPUP, 0, 0,
                GetSystemMetrics(SM_CXSCREEN), GetSystemMetrics(SM_CYSCREEN),
                NULL, NULL, hInst, NULL);
            if (hwnd == NULL)
            {   MessageBox(hWnd, "Window作成失敗", "Failure", MB_OK);
                return -1;
            }
            hWhole = hwnd;
            return 0;
        }
        
  3. Main Window の CALLBACK 関数の処理です。
    IDM_CAP: で矩形領域を選択して画像を取得します。
    ShowWindow(hWnd, SW_HIDE); で Window を隠します。
    実行が終わるまで Sleep(300); で待機します。
    ShowWindow(hWhole, SW_SHOWNORMAL); で透明 Window を表示します。
            case WM_COMMAND:
                {
                          :
                    case IDM_CAP:
                        bCap = TRUE;
                        bBlock = FALSE;
                        ShowWindow(hWnd, SW_HIDE);
                        Sleep(300);
                        ShowWindow(hWhole, SW_SHOWNORMAL);
                        break;
                 }
                 break;
        
  4. 透明 Window の CALLBACK 関数です。
    マウスボタンを検出して透明 Window に矩形領域を DrawRect() で描画します。
    WM_LBUTTONUP: で矩形領域が確定します。
    矩形領域の画像を Clipboard に転送します。
    透明 Window を隠して、通常の Window を表示します。
        LRESULT CALLBACK WholeProc(HWND hWnd, UINT msg, WPARAM wp, LPARAM lp)
        {   HDC     hdc, hdc_mem;
            HBITMAP hBitmap;
    
            switch(msg)
            {   case WM_LBUTTONDOWN:
                    if (bCap)
                    {   bBlock = TRUE;
                        oldend = beg = MAKEPOINTS(lp);
                        DrawRect(hWnd, beg, oldend);
                        SetCursor(LoadCursor(NULL, IDC_CROSS));
                    }
                    break;
                case WM_MOUSEMOVE:
                    if(bBlock)
                    {   end = MAKEPOINTS(lp);
                        DrawRect(hWnd, beg, oldend);
                        DrawRect(hWnd, beg, end);
                        oldend = end;
                    }
                    break;
                case WM_LBUTTONUP:
                    if  (bBlock)
                    {   bBlock = bCap = FALSE;
                        SetCursor(LoadCursor(NULL, IDC_ARROW));
                        end = MAKEPOINTS(lp);
                        DrawRect(hWnd, beg, oldend);
                        x = abs(beg.x - end.x);
                        y = abs(beg.y - end.y);
                        hdc = GetDC(hWnd);
                        hdc_mem = CreateCompatibleDC(hdc);
                        hBitmap = CreateCompatibleBitmap(hdc, x, y);
                        if (hBitmap)
                        {   SelectObject(hdc_mem, hBitmap);
                            StretchBlt(hdc_mem,0,0,x,y,hdc,beg.x,beg.y,end.x-beg.x,
                                       end.y-beg.y,SRCCOPY);
                            OpenClipboard(hWnd);
                            EmptyClipboard();
                            SetClipboardData(CF_BITMAP, hBitmap);
                            CloseClipboard();
                            InvalidateRect(hWnd, NULL, TRUE);
                        }
                        else
                        {   MessageBeep(0);  }
                        DeleteDC(hdc_mem);
                        ReleaseDC(hWnd, hdc);
                    }
                    ShowWindow(hWhole, SW_HIDE);
                    ShowWindow(hMain, SW_RESTORE);
                    break;
                default:
                    return DefWindowProc(hWnd, msg, wp, lp);
            }
            return 0L;
        }
        
  5. 矩形を表示するコードです。
    矩形はマウスの移動に従って、描画したものを消して描き直さなければなりません。
    SetROP2() で描画モードを R2_NOT に設定すると、もう一度同じ矩形を描くとこれを消してくれます。
        void    DrawRect(HWND hWnd, POINTS beg, POINTS end)
        {   HDC     hdc;
            HPEN    hPen;
    
            hdc = GetDC(hWhole);
            SetROP2(hdc, R2_NOT);
            hPen = CreatePen(PS_SOLID, 7, RGB(0, 0, 0));
            SelectObject(hdc, hPen);
            MoveToEx(hdc, beg.x, beg.y, NULL);
            LineTo(hdc, end.x, beg.y);
            LineTo(hdc, end.x, end.y);
            LineTo(hdc, beg.x, end.y);
            LineTo(hdc, beg.x, beg.y);
        
            ReleaseDC(hWhole, hdc);
            DeleteObject(hPen);
            return;
        }
        
  6. WM_PAINT: ではクリップボードから画像を取得して描画します。
        case WM_PAINT:
             hdc = BeginPaint(hWnd, &ps);
             クリップボードから画像を取得して描画する
                          :
             EndPaint(hWnd, &ps);
             break;
        

超初心者のプログラム入門(Win32API C++)