VisualStudioのMFCでクリップボードのデータの文字数をカウントできない

このQ&Aのポイント
  • VisualStudioのMFCを使用してクリップボードのデータの文字数をカウントしようとしていますが、うまくいきません。
  • 特定の操作を実行すると、文字列自体は認識されますが、文字数の値が0になってしまいます。
  • 解決策がわからず途方に暮れています。アドバイスをいただけないでしょうか。
回答を見る
  • ベストアンサー

CString データの文字数カウントができない

VusualStudioのMFCでクリップボードのデータの文字数をカウントしようとしています。 Webにあったように以下のようなクラスを作成し、 =========================================================== CString CClipboard::GetClipboardText() { CString strText; strText.Empty(); // クリップボードにテキストデータが入っているかを調べる if( !::IsClipboardFormatAvailable(CF_UNICODETEXT) ) return strText; // クリップボードのオープン if( !::OpenClipboard(NULL) ) return strText; // クリップボードからデータを取得し、strTextへコピー HANDLE hMem = ::GetClipboardData(CF_UNICODETEXT); LPTSTR pMem = (LPTSTR)::GlobalLock(hMem); ::lstrcpy((LPTSTR)(LPCTSTR)strText, pMem); ::GlobalUnlock(hMem); ::CloseClipboard(); return strText; } =========================================================== 適当にメモ帳などでコピー操作をしたのち、 CClipboard board; CString a = board.GetClipboardText(); int b = a.GetLength(); 上記コードが含まれた操作を実行するとaという文字列自体はデバッガ上から"test"のように 認識されているのですが、bの値が0になってしまいます。 ちょっとわけがわからず途方に暮れています。 アドバイスがあればよろしくお願いします。

質問者が選んだベストアンサー

  • ベストアンサー
回答No.4

> HANDLE hMem = ::GetClipboardData(CF_UNICODETEXT); > LPTSTR pMem = (LPTSTR)::GlobalLock(hMem); UNICODEでとってきたなら、LPTSTRじゃなくてLPWSTRにしないとダメなのでは? あとは strText = pMem; でいいような気もするけど。

ykino1978
質問者

お礼

ありがとうございます。No.1の方でも動きましたが、こちらでも 動きました。理屈的にはこちらでいいと思いました。 ただLPTSTRのままでいいとの私の理解です。 (LPTSTRはUNICODEの時に使用すると思っているのですが、間違っていますか)

その他の回答 (4)

回答No.5

> ただLPTSTRのままでいいとの私の理解です。 > (LPTSTRはUNICODEの時に使用すると思っているのですが、間違っていますか) LPTSTRは、UNICODEが#defineなどで定義されている場合にLPWSTRとなり、それ以外の場合はLPSTRとなります。 現在のプロジェクトではUNICODEが定義されているのでしょう。そうであれば、コード的には同じになります。しかし、そのコードを別のプロジェクトで使用しようとした場合に、そのプロジェクトでUNICODEが定義されていないと、UNICODE文字列が入っているバッファの内容を、マルチバイト文字列として処理しようとしてしまい、正しく動作しなくなるでしょう。 TCHARやLPTSTRなどは、プロジェクトの設定によって使用する文字コードが違っても、同じソースで済むようにするためのものです。最初からUNICODE文字列とわかっているなら、wchar_tやLPWSTRなどを使うべきです。

ykino1978
質問者

お礼

なるほど、確かにそうですね。 ありがとうございます。色々すっきりしました。

回答No.3

> ClipboardText内のローカル変数だから、用がすめば破壊されるけど 破壊されるのは戻り値が確定した後だから無問題じゃね?

ykino1978
質問者

お礼

ありがとうございます。No.1の方のもので動きました!

noname#157863
noname#157863
回答No.2

CString CClipboard::GetClipboardText() { CString strText; <---- ・・・ lstrcpy((LPTSTR)(LPCTSTR)strText, pMem); ・・・ return strText; } GetClipboardText内のローカル変数だから、用がすめば破壊されるけど

ykino1978
質問者

お礼

ありがとうございます。 No.3の方がおっしゃっているように問題ないと理解しました。

回答No.1

> ::lstrcpy((LPTSTR)(LPCTSTR)strText, pMem); ここがヘン。無理矢理感満載。 LPTSTR buf = strText.GetBuffer(文字列サイズ); ::lstrcpy(buf, pMem); strText.ReleaseBuffer();

参考URL:
http://msdn.microsoft.com/ja-jp/library/kt26tkzx.aspx
ykino1978
質問者

お礼

お返事がすぐにいただけていることに気づかず(メールが飛ぶと勘違いしていました)、ご連絡遅れました。 ありがとうございます。 上記でうまくいきました! ただ、GetBuffer, ReleaseBufの使い方の意味を完全に把握できていないのでこれは勉強しなおします。

関連するQ&A

  • c++ メモリの確保を動的に変更する

    VC++2008 Express版で以下のプログラム(第1引数をクリップボードにセット)を作成しましたがメモリの確保量を自動的に調節するようにしたいのですが、どうしたらよろしいですか #include <stdio.h> #include <windows.h> void main(int argc,char *argv[]) { OpenClipboard(NULL); int iStrLen = 8;//★ここを調整したい★ HGLOBAL hMem = ::GlobalAlloc(GMEM_FIXED, iStrLen); LPTSTR pMem = (LPTSTR)hMem; ::lstrcpy(pMem, (LPCTSTR)argv[1]); ::EmptyClipboard(); ::SetClipboardData(CF_TEXT, hMem); ::CloseClipboard(); }

  • クリップボードからJpgファイルへの保存方法(画質について)

    クリップボードにコピーされたデスクトップの画面を Jpgファイルに落とすプログラムです。 クリップボードから情報を取得してjpgファイルを作成することはできるのですが、画質が悪く (白黒のように)なってしまうのですが、なぜなのかわかりません。 アドバイスお願いします。 if (IsClipboardFormatAvailable(CF_DIB )) { ::OpenClipboard(NULL); HGLOBAL hGlobal; hGlobal = (HGLOBAL)::GetClipboardData(CF_DIB ); if( hGlobal == NULL ){ AfxMessageBox( "クリップボードへコピーできませんでした" ); return; } //ファイルに保存 ///////////////////// const CString szPptFilter = _T("PowerPoint Files (*.ppt)|*.ppt|"); CString szFilter = szPptFilter + _T("|"); CFileDialog dlg(FALSE, _T("ppt"), NULL, OFN_HIDEREADONLY | OFN_OVERWRITEPROMPT, szPptFilter); if( dlg.DoModal() == IDOK ) { double lfProp = 1.0; TCHAR szTemp[_MAX_PATH]; BOOL bTemp = (GetTempPath(_MAX_PATH, szTemp) == 0)? FALSE:TRUE; CString szTempPath = bTemp? szTemp:_T("c:\\"); CString szFileName = szTempPath + _T("_") + "JpegFile" + _T(".jpg"); void *pDIB = GlobalLock( hGlobal ); CDib dib((BYTE*)pDIB); CPicObject::EPicKind eKind = CPicObject::GetKind(szFileName); if(eKind == CPicObject::eJpg) { CPicJpg pic(dib); //tmpフォルダに一時的に作成 bStatus = pic.Write(szFileName); }

  • クリップボードへのコピー

    あるHPのコードを参考に文字をクリップボードへ コピーするコードを書いてみましたが、エラーが できます。なにかおかしいかご指摘いただけないでしょうか? HGLOBAL hText; wchar_t *pText; hText = GlobalAlloc(GMEM_DDESHARE | GMEM_MOVEABLE, 4); pText = (wchar_t*)GlobalLock(hText); lstrcpy(pText, L"abc"); GlobalUnlock(hText); OpenClipboard(NULL); EmptyClipboard(); SetClipboardData(CF_TEXT, hText);//ここでヒープが壊れていると起こられます。 CloseClipboard(); もっとも単純なテストコードです。 いろいろとチェックを手抜きしてますが、とりあえずOKとします。

  • 【エクセルのマクロ】クリップボードのbitmapをフォームに表示させたい

    こんにちは! クリップボードにビットマップが入っていたとき、そのデータをフォームに表示させたりすることはできませんか?API関数にgetclipboarddata(cf_bitmap)というものがあり、これを使うことでデータは取得していると思うのですが、例えばImage1.Picture=GetClipBoardData(CF_BITMAP)というようにやっても〔オブジェクトが必要です〕というエラーが出てしまいます。 openclipboard(0)とかcloseclipboardとか、これらの宣言とか、概ね必要と思われるものはコードに組み込んであると思います。 正直申し上げて、完全な初心者です。どなたかお分かりになる方いらっしゃいますか? また、エクセルのグラフやシェイプをマクロを使い、bitmap形式で保存する方法はありませんか?VBの参考サイトで調べてみるとメタファイル形式で取得してやってらっしゃったのですが、エクセルのマクロではこれはできないでしょうか(自分が見たサイトではエクセルでサポートしていない関数を使っていました)? どなたか助けてください。よろしくお願いいたします。

  • CStringのFindで文字列検索を行いたいのですが

    こんにちは。 いつもお世話になっております。 CStringのFindメソッドで文字列検索を行っているのですが、文字列ではなくコードで検索が行われてしまい困っています。 ------------------------------------------------------- CString TargetStr; TargetStr = "ハヒフヘホ"; if(TargetStr.Find("z", 1) != -1){ return FALSE; } ------------------------------------------------------- 上記で文字"ホ"のコードが「837A」で"z"が「7A」のため、 文字列が存在するという結果が帰ってきます。 コードではなく文字そのものの検索をするにはどうしたらよいでしょうか? 基本的なことで申し訳ありませんが、ご教示下さい。 <環境> Windows 2000, VC6.0

  • CString ←→ BSTRの変換について

    次のコードのように、CString ←→ BSTRの変換を行いたいのですが、データがUTF8だと文字化けしてしまいます。 どうすれば良いでしょうか? 環境:VC++7(.net 2003)+MFC+WinXP 【結果】 CString-------------------------- FFFFFFE2 FFFFFF97 FFFFFF8B 3C BSTR-------------------------- FFFFFFE2 FFFFFF97 FFFFFF81 45 【ソース】 int intCT; int nSize = 0; BYTE *pSource = (BYTE *)"○<"; this->ConvSJistoUtf8(pSource, (BYTE *)NULL, &nSize ); BYTE* pDist = new BYTE[ nSize + 1 ]; ZeroMemory( pDist, nSize + 1 ); this->ConvSJistoUtf8(pSource, pDist, &nSize ); CString str = CString(pDist); delete []pDist; pDist = NULL; BSTR bstr; bstr=str.AllocSysString();//CString→BSTRへの変換 CString str2=CString(bstr);//BSTR→CStringへの変換 TRACE("CString--------------------------\n "); for( intCT = 0; intCT < str.GetLength(); intCT++ ) { if( intCT%16 == 0 ) TRACE("\n"); TRACE("%02X " , str[intCT]); } TRACE("\n "); TRACE("BSTR--------------------------\n "); for( intCT = 0; intCT < str2.GetLength(); intCT++ ) { if( intCT%16 == 0 ) TRACE("\n"); TRACE("%02X " , str2[intCT]); } TRACE("\n "); BOOL ConvSJistoUtf8( BYTE* pSource, BYTE* pDist, int* pSize ) { *pSize = 0; //ShiftJISからUTF-16へ変換 const int nSize = ::MultiByteToWideChar( CP_ACP, 0, (LPCSTR)pSource, -1, NULL, 0 ); BYTE* buffUtf16 = new BYTE[ nSize * 2 + 2 ]; ::MultiByteToWideChar( CP_ACP, 0, (LPCSTR)pSource, -1, (LPWSTR) buffUtf16, nSize ); //UTF-16からShift-JISへ変換 const int nSizeUtf8 = ::WideCharToMultiByte( CP_UTF8, 0, (LPCWSTR) buffUtf16, -1, NULL, 0, NULL, NULL ); if( !pDist ){ *pSize = nSizeUtf8; delete buffUtf16; return TRUE; } BYTE* buffUtf8 = new BYTE[ nSizeUtf8 * 2 ]; ZeroMemory( buffUtf8, nSizeUtf8 * 2 ); ::WideCharToMultiByte( CP_UTF8, 0, (LPCWSTR)buffUtf16, -1, (LPSTR) buffUtf8, nSizeUtf8, NULL, NULL ); *pSize = lstrlen( (char*)buffUtf8 ); memcpy( pDist, buffUtf8, *pSize ); delete buffUtf16; delete buffUtf8; return TRUE; }

  • error C2440: 'static_cast' : 'CString' から 'LPCSTR' に変換できません

    CStringから LPCSTR型への変換orその逆について教えて下さい。 Visal Studio 2005のC++で以下のサンプルを動かしました。 http://www.g-ishihara.com/mfc_nw_01.htm すると、以下のプログラムを実行させると、IとIIでエラーが発生しました。 I  byteCP = static_cast<LPCSTR>(sendStr) +sendSum; error C2440: 'static_cast' : 'CString' から 'LPCSTR' に変換できません。 II  byteP = recvStr.GetBuffer(21); error C2440: '=' : 'wchar_t *' から 'LPSTR' に変換できません。 学習のため、サンプルに従って進めていきましたが、 そこでつまずいてしまいました。 CStringについては、全く知識がありません。 ご存じの方、教えて下さい。 void CClientSockDlg::OnBnClickedBtnSend() { CSocket sock; unsigned int port = 0; CString sendStr, recvStr; int send, recv, sendSum, recvSum; LPCSTR byteCP = NULL; LPSTR byteP = NULL; int err = 0; UpdateData(); // (1)ソケット作成 if (!err) if (!sock.Create()) err = 1; // (2)ポート取得 if (!err) if (_stscanf_s(m_xvEditPort, _T("%d"), &port) != 1) err = 1; // (3)接続 if (!err) if (!sock.Connect(m_xvEditIP, port)) err = 1; // (4)送信(20バイト固定) if (!err) { sendStr = m_xvEditMes; while (sendStr.GetLength() < 20) sendStr += _T(" "); sendStr = sendStr.Left(20); sendSum = 0; while (sendSum < 20) { byteCP = static_cast<LPCSTR>(sendStr) +sendSum; //------- I send = sock.Send(byteCP, 20 -sendSum); if (send == SOCKET_ERROR) {err = 1; break;} sendSum += send; } } if (!err) { m_xvEditLog += _T("Send : "); m_xvEditLog += sendStr +_T("\r\n"); } // (5)受信(20バイト固定) if (!err) { byteP = recvStr.GetBuffer(21);  //------- II recvSum = 0; while (recvSum < 20) { recv = sock.Receive(byteP +recvSum, 20 -recvSum); if (recv == SOCKET_ERROR || recv == 0) {err = 1; break;} recvSum += recv; } byteP[20] = '\0'; recvStr.ReleaseBuffer(); } if (!err) { m_xvEditLog += _T("Recv : "); m_xvEditLog += recvStr +_T("\r\n"); } // (6)エラー表示 if (err) { LPVOID lpMsgBuf = NULL; ::FormatMessage( FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, NULL, sock.GetLastError(), MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), (LPTSTR)&lpMsgBuf, 0, NULL); m_xvEditLog += _T("Error : "); m_xvEditLog += static_cast<LPTSTR>(lpMsgBuf); UpdateData(FALSE); LocalFree(lpMsgBuf); } // (7)切断 sock.Close(); UpdateData(FALSE); return; }

  • CListCtrlに表示している複数ファイルを他アプリへドラッグ&ドロップするには

    CListCtrlに表示している複数ファイルを他アプリへドラッグ&ドロップするソースに手間取っていますのでご教授をお願いします。 (VC++ 6.0のサンプルコードがあまりなくて) なんとか、1つのファイルはできるようになったのですが複数にするやり方がわかりません。 どのようにすればよいでしょうか? また、おかしい箇所などありましたら合わせてお願いします。 ※単純の繋げるだけじゃないんですよね?※ CString fname = "C:\\aaa.txt"; fname += "C:\\bbb.txt"; -環境- ・VC++ 6.0 ・MFC ・ダイアログベース -ソース- void aaaDlg::OnBegindragListView(NMHDR* pNMHDR, LRESULT* pResult) { NM_LISTVIEW* pNMListView = (NM_LISTVIEW*)pNMHDR; // TODO: この位置にコントロール通知ハンドラ用のコードを追加してください if(pNMListView->iItem != -1) { CString fname = "C:\\aaa.txt"; // 動作確認のため固定 HDROP hptr = DragCreateFiles(fname); if (hptr == NULL) { *pResult = 0; return; } m_DropData.CacheGlobalData(CF_HDROP, hptr); CRect rect(0,0,0,0); DROPEFFECT effect = m_DropData.DoDragDrop(DROPEFFECT_COPY, rect); } *pResult = 0; } static HDROP DragCreateFiles (LPCSTR fname) { HDROP hDrop; LPDROPFILES lpDropFileStruct; // Allocate dynamic memory for the DROPFILESTRUCT data // structure and for the extra zero-character identifying // that there are no pathnames in the block yet. int flen = lstrlen(fname); hDrop = (HDROP)GlobalAlloc(GMEM_MOVEABLE | GMEM_ZEROINIT, sizeof(DROPFILES) + flen + 2); // If unsuccessful, return NULL if (hDrop == NULL) return(hDrop); // Lock block and initialize the data members lpDropFileStruct = (LPDROPFILES) GlobalLock(hDrop); memset(lpDropFileStruct,0,sizeof(DROPFILES) + flen + 2); lpDropFileStruct->pFiles = sizeof(DROPFILES); lpDropFileStruct->pt.x = 0; lpDropFileStruct->pt.y = 0; lpDropFileStruct->fNC = FALSE; lpDropFileStruct->fWide = FALSE; char* szPathA = (char*) (&lpDropFileStruct[1]); lstrcpy(szPathA,fname); // Unlock the block and return its handle. GlobalUnlock(hDrop); return(hDrop); }

  • VC++2008 で クリップボードの監視を行いたい

    いつもおせわになっております。 ただいま、Visual C++ 2008 Express Edition を使いまして、クリップボード拡張アプリを作っております。 実装したい機能として・・・  A.クリップボードにデータがコピーされる度に、クリップボードのデータを取得する。  B.ただし、クリップボード上のデータは消さない。 というものがあります。 この使用を実装するために、下記のようにデータ存在の有無をタイマーな どでポーリングすれば良いと考えました。 >IDataObject ^data = System::Windows::Forms::Clipboard::GetDataObject(); >pictureShowPicture->Image->Dispose(); >if(data->GetDataPresent(DataFormats::Bitmap) == true){ しかし、この方法だと、一回でもデータがクリップボードにコピーされると、その後もずっと「データが存在する」状態となってしまい、新しいデータが来たのかどうか判断が出来ません。 クリップボード上のデータを消せば、「データが存在しない」状態となり、次にデータがコピーされたことが分かるのですが、クリップボード上のデータは消さない実装としたいのです。 このため、下記のようにすれば問題が解決できると思いました。  1.何らかの方法でクリップボードにデータがコピーされたという通知を受け取る。  2.現在のデータが直前のデータと同じか異なるかを判断する。    (ポーリングしておいて、データが異なれば新規データと判断) 上記1,2について、実現方法をご存知の方は教えていただけませんでしょうか。 ちなみに、受け取りたいデータ形式は、ビットマップ形式画像およびテキスト形式です。 お忙しいところ恐縮ですが、よろしくお願いいたします。

  • VBAでの「メソッドまたはデータメンバが見つかりま

    word2016で以下のプログラムを流したいのですが、「メソッドまたはデータメンバが見つかりません」のエラーが出ます。 Dim CB As Variant, i As Long CB = Application.ClipboardFormats If CB(1) = True Then MsgBox ”クリップボードになにも値がありません。”,48 Exit Sub End If どうすれば直るでしょうか?よろしくお願いします。