第5回 クリップボード その2

 

前回に続き、クリップボードの使い方をお伝えします。

 

(1)クリップボードからプレーンテキストを取り出す

 

クリップボードからプレーンテキストを取り出す方法です。前回同様に、クリップボードからデータを取り出す手順を兼ねまてます。

        //(A)クリップボードに自分で処理可能なデータ(ここではプレーンテキスト)があるかどうかを調べます

          if (IsClipboardFormatAvailable(CF_TEXT)) {

 

                //(B)クリップボードをオープンします。

                ::OpenClipboard(NULL);

 

                //(C)クリップボードに入っているデータを取り出します。

                //   取得したハンドルの所有者はクリップボードですので、プログラムでハンドルを廃棄したりしてはいけません。

                //   データの内容を変更することも厳禁です。

                HANDLE hData;

                hData = ::GetClipboardData(CF_TEXT);

 

                //(D)取得データを処理します。CF_TEXTの場合、ハンドルはグローバルメモリハンドルです

                //   また、新たにクリップボードへデータが登録されてしまったら、そのハンドルはもう使えません。

                //   ハンドルを保持するのではなく、その内容をコピーしておきましょう。

                char *pszData = (char *)GlobalLock(hData);

                … ここで文字列を処理します。

                GlobalUnlock(hData);

 

                //(E)クリップボードをクローズします

                ::CloseClipboard();

        }

 

−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−

(A)で指定するクリップボードフォーマットを変えれば、任意のクリップボードフォーマットのデータを処理できます。

もちろん、 RegisterClipboardFormat で登録したクリップボードフォーマットを指定することもできます。

 

なお、クリップボードフォーマットによって(D)の部分の処理の仕方が変りますからご注意ください。

 

 

 

(2)複数のクリップボードフォーマットのデータがある場合

 

クリップボードフォーマットに優先度をつけてデータを処理します。

        //(A)クリップボードフォーマットの優先度を指定します。

        UINT cflist[10];

        cflist[0] = CF_TEXT;            // 一番優先度が高いクリップボードフォーマットを指定します

        cflist[1] = CF_HDROP;           // 次に優先度が高いクリップボードフォーマットを指定します

        cflist[2] = CF_BITMAP;          // その次です

 

        //(B)指定したクリップボードフォーマットのなかで、実際にクリップボードに存在していて、かつ、優先度の高いる物を取得します。

        int cf = ::GetPriorityClipboardFormat(cflist, 3);

        if (cf > 0) {

                // (C)クリップボードをオープンします

                ::OpenClipboard(NULL);

 

                //(D)クリップボードに入っているデータを取り出します。

                HANDLE hData;

                hData = ::GetClipboardData(cf);

 

                //(E)クリップボードフォーマットに応じて処理を変えます。

                switch(cf) {

                case CF_TEXT:

                        //(F)取得データを処理します。CF_TEXTの場合、ハンドルはグローバルメモリハンドルです

                        char *pszData = (char *)GlobalLock(hData);

                        … ここで文字列を処理します。

                        GlobalUnlock(hData);

                        Break;

 

                case ????:

                       

                }

 

                //(G)クリップボードをクローズします

                ::CloseClipboard();

        }

−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−

優先度を付けなくても、クリップボードに入っているものを全て処理するというのも有りですかね?

そんな場合には、EnumClipboardFormats というAPIが使えるかも。

残念ながら使ったことが無いので、サンプルは無しです。

 

 

 

(3)CF_HDROPのデータを受け取る

 

エクスプローラでファイルをコピーして、BTMemoで貼り付けた場合の処理です。

エクスプローラ同士だとファイルを移動したりコピーしたりしますが、BTMemoはパス名を受け取るだけです。

        //(A)クリップボードにデータがあるかどうかを調べます

          if (IsClipboardFormatAvailable(CF_HDROP)) {

 

                //(B)クリップボードをオープンします。

                ::OpenClipboard(NULL);

 

                //(C)クリップボードに入っているデータを取り出します。

                //   クリップボードフォーマットがCF_HDROPの場合、登録されているデータはHDROPという形式のハンドルです。

                HDROP hData;

                hData = (HDROP)::GetClipboardData(CF_HDROP);

 

                //(D)何個のファイルが格納されているか調べます。その個数分だけループして全ファイルを処理します

                UINT nFiles = ::DragQueryFile((HDROP)hData, (UINT)-1, NULL, 0);

                for (UINT iFile=0; iFile<nFiles; ++iFile) {

 

                        //(E)HDROPに格納されているファイルの中でiFile番目のファイルのパス名を得ます。

                        char szPath[_MAX_PATH];

                        ::DragQueryFile((HDROP)hData, iFile, szPath, sizeof(szPath));

                        … ここでパス名を処理します。(BTMemoではリンクを作成します)

                }

 

                //(F)クリップボードをクローズします

                ::CloseClipboard();

        }

 

 

 

(4)CF_BITMAPのデータを受け取る

 

ペイントブラシ等で画像をコピーして、BTMemoで貼り付けた場合の処理です。

        //(A)クリップボードにデータがあるかどうかを調べます

          if (IsClipboardFormatAvailable(CF_BITMAP)) {

 

                //(B)クリップボードをオープンします。

                ::OpenClipboard(NULL);

 

                //(C)クリップボードに入っているデータを取り出します。

                //   クリップボードフォーマットがCF_BITMAPの場合、登録されているデータはHBITMAPという形式のハンドルです。

                HBITMAP hData;

                hData = (HBITMAP)::GetClipboardData(CF_BITMAP);

                … ここでビットマップハンドルを処理します。

 

                //(D)クリップボードをクローズします

                ::CloseClipboard();

        }

 

−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−

単に描画するだけならビットマップハンドルをそのまま使用すればよいのですが、ハンドルを保持していてもいつ無効になるかわかりません。

データを確実に保持するため、あるいは、ファイルに保存したりするためには中の画像データを取り出す必要があります。

こんな感じです。

−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−

// 指定されたビットマップハンドルからイメージ情報を取得します

BITMAPINFO *GetBitmap(HBITMAP hBmp)

{

        // ビットマップハンドルから情報を取り出します

        BITMAP bmap;

        int nBit = GetObject(hBmp, sizeof(bmap), &bmap);

 

        // パレットエントリ数を判定します

        switch(bmap.bmBitsPixel) {

        case 1:         m_nColorTable =   2;    break;

        case 4:         m_nColorTable =  16;    break;

        case 8:         m_nColorTable = 256;    break;

        default:        m_nColorTable =   0;    break;         

        }

 

        // 必要なサイズを計算し、メモリを獲得します

        int nBmi = sizeof(RGBQUAD) * m_nColorTable;                                     // ヘッダーのサイズです

        int nImage = (((bmap.bmWidth * bmap.bmBitsPixel) + 31) / 8) * bmap.bmHeight;    // 画素情報のサイズです

        BITMAPINFO *pBmi = (BITMAPINFO *)malloc(m_nBmi + m_nImage);

        Char *pImage = ((char *)pBmi) + nBmi;

 

        // ヘッダー情報の作成

        memset(m_pBmi, 0, m_nBmi);

        pBmi->bmiHeader.biSize = sizeof(BITMAPINFOHEADER);

        pBmi->bmiHeader.biWidth = bmap.bmWidth;

        pBmi->bmiHeader.biHeight = bmap.bmHeight;

        pBmi->bmiHeader.biPlanes = 1;

        pBmi->bmiHeader.biBitCount = bmap.bmBitsPixel;

        pBmi->bmiHeader.biCompression = BI_RGB;

        pBmi->bmiHeader.biSizeImage = 0;

        pBmi->bmiHeader.biXPelsPerMeter = 0;

        pBmi->bmiHeader.biYPelsPerMeter = 0;

        pBmi->bmiHeader.biClrUsed = m_nColorTable;

        pBmi->bmiHeader.biClrImportant = m_nColorTable;

 

        // 画素情報取得

        HWND hWnd = ::GetDesktopWindow();

        HDC hDC = ::GetWindowDC(hWnd);

        GetDIBits(hDC, hBmp, 0, bmap.bmHeight, pImage, pBmi, DIB_RGB_COLORS);

        ::ReleaseDC(hWnd, hDC);

 

        return pBmi;

}