次の方法で共有


クリップボード転送できる最大サイズが知りたい

質問

2016年2月18日木曜日 1:27

お世話になります。

windows7 VC;;2010で開発しています。

クリップボードへ転送できる最大サイズのAPIが知りたいです。

また、ツールか何かで、最大サイズを変更することはできますか?

すべての返信 (11)

2016年2月19日金曜日 6:46 ✅回答済み

ちょっと検;してみましたが、メタファイル(WMF)、拡張メタファイル(EMF)ともにクリップボードに入れられる大きさは40MBみたいですね。
※OLEのサイズ制限は確認していません

以下検;コード(簡単にするためエラー処理は行っていません)

RECT rect = { 0,0,100,100 };
HDC hdc = CreateMetaFile(TEXT("metafile.wmf"));
for (int i = 0; i < 1204702; ;;i) // 1204703だとだめ
{
    FillRect(hdc, &rect, (HBRUSH)GetStockObject(BLACK_BRUSH));
}
HMETAFILE hMetaFile = CloseMetaFile(hdc);
HANDLE hHandle = GlobalAlloc(GMEM_MOVEABLE | GMEM_DDESHARE, sizeof(METAFILEPICT));
METAFILEPICT *pMetaFilePict = (METAFILEPICT *)GlobalLock(hHandle);
pMetaFilePict->mm = MM_TEXT;
pMetaFilePict->xExt = 100;
pMetaFilePict->yExt = 100;
pMetaFilePict->hMF = hMetaFile;
GlobalUnlock(hHandle);
OpenClipboard(NULL);
EmptyClipboard();
MessageBox(0, SetClipboardData(CF_METAFILEPICT, pMetaFilePict) ? TEXT("成功") : TEXT("失敗"), 0, 0);
CloseClipboard();
DeleteMetaFile(hMetaFile);
RECT rect = { 0,0,100,100 };
HDC hdc = CreateEnhMetaFile(NULL, TEXT("enhmetafile.emf"), &rect, NULL);
for (int i = 0; i < 330321; ;;i) // 330322だとだめ
{
    FillRect(hdc, &rect, (HBRUSH)GetStockObject(BLACK_BRUSH));
}
HENHMETAFILE hEnhMetaFile = CloseEnhMetaFile(hdc);
OpenClipboard(NULL);
EmptyClipboard();
MessageBox(0, SetClipboardData(CF_ENHMETAFILE, hEnhMetaFile) ? TEXT("成功") : TEXT("失敗"), 0, 0);
CloseClipboard();
DeleteEnhMetaFile(hEnhMetaFile);

2016年2月18日木曜日 2:05

windows clipboard size でググるといろいろヒットしますがやってみましたか? 例えば下記:

How can I increase the size of the clipboard in window 7 ...
http://stackoverflow.com/questions/20855045/how-can-i-increase-the-size-of-the-clipboard-in-window-7

もしまだなら、まずググって調べてみることをお勧めします。その上で、どれを試したが効果がなかったなどの情報を書いていただけるとより話がしやすくなるのではと思いますので。


2016年2月18日木曜日 2:20

そもそも質問の「最大サイズ」の単位がわかりません。例えばエクスプローラーでファイルのcut & pasteであれば何GBのファイルであってもコピーできます。これはエクスプローラーがクリップボードを迂回しているからではありません。7-zipなどのアーカイバーからエクスプローラーへのcopy & pasteなどにおいても巨大ファイルは扱えます。

クリップボードは(用語が正しくないかもしれませんが)ソースとターゲットが協調して受け渡すデータフォーマットを決定します。例えばWebブラウザーがHTMLをコピーしたとしても、受け側がメモ帳であればテキストになります。もしくはWordであれば書式付きのテキストになったりと。

また例えば画像形式ですとHBITMAPで渡すことになるため、クリップボードサイズ以前にそもそもHBITMAPのサイズ上限が存在します。

以上を踏まえて、どのような上限を求めているのかを明確にしてください。


2016年2月18日木曜日 5:19

> クリップボードへ転送できる最大サイズのAPIが知りたいです。

結論から言うとそういったAPIはないようです。

クリップボードへ転送できるサイズの制限は、GlobalAlloc(GMEM_DDESHARE | GMEM_MOVEABLE, <<取得サイズ>>);で取得できる最大サイズです。なので、プログラム(32bit or 64bit)、他のプログラムの使用メモリ、搭載されている物理メモリ等により変わってきます。

<<取得サイズ>>の部分をGlobalMemoryStatusExやGetProcessMemoryInfoなどを使用して、おおよその確保できる値を知ることはできると思いますが、実際にその値で確保しようとしたときに失敗することがあります。


2016年2月18日木曜日 6:43

クリップボードへ転送できるサイズの制限は、GlobalAlloc(GMEM_DDESHARE | GMEM_MOVEABLE, <<取得サイズ>>);で取得できる最大サイズです。

それはTYMED_HGLOBALに限定した話で、それ以外にもTYMED_GDIやTYMED_ISTREAMなどいろいろな形式があるのでは? (参考 TYMED


2016年2月18日木曜日 7:38

お世話になります。自アプリで、自データをメタファイルにして、クリップボードに送っています。COleServerItem pItem = GetDocument()->GetEmbeddedItem();
pItem->CopyToClipboard(TRUE);//ここが問題っぽいのですが。。。この中でOnRenderDataがよばれ、独自のデータをメタファイルとして、メモリ上に作成しています。データ量が多い(メタファイル(画像)がいくつかドキュメントに貼られている)と、
CopyToClipboardで、落ちているようです。メタファイルデータを作成しているところで、GlobalAlloc等を行っているのですが、
問題なくメモリは確保されているようです。
落ちないときに試したことは、ドキュメントに貼り付けられているメタデータを削除して、クリップボードに転送した場合、成功しました。
デバックモードでの起動時には、あまり落ちないので(クリップボードへの転送はされていない)
データ量を少なくしたりすると、クリップボードに転送されます。環境にもよるのでしょうが、今のところファイルサイズ20MBの上下で成功と失敗があるようです。デバックモードで何回かクリップボードに転送する機能を実行してみた時、
(容量が多いデータで)ヒープ領域が破壊されました等のメッセージが表示されました。

2016年2月18日木曜日 9:57 | 2 票

COleServerItem ということは、MFCのOLEサーバーですよね。だとすると、OLEのプレゼンテーション用メタファイルの制限により16メガが最大値です。

より正確には、16bit OSの GlobalAllocの最大値までという制限になっています。

これは、OLEの仕様なので、この制限は今も変わりません。16ビット時代の名残とはいえ、うちも結構これには苦労させられているので。。。

これを回避するには、OLE用のプレゼンテーション用イメージとしてWMFを用意しないようにすれば対応できます。ただし、COleServerItemを使っている場合、絶対に WMF を作ってしまうので(回避手段はありません)、COleServerItem を使わずに、COleServerItem が行っているOLEサポート処理を実装する必要があります。

うちは、現時点では上記状況を制限として実装改めには踏み込んでません(作業コストをペイできるほどOLEに魅力がなくなっているというのもありますが...)。

とっちゃん@わんくま同盟, Visual Studio and Development Technologies http://blogs.wankuma.com/tocchann/default.aspx


2016年2月19日金曜日 2:28

ご返事ありがとうございます。

>>COleServerItem ということは、MFCのOLEサーバーですよね。だとすると、OLEのプレゼンテーション用メタファイルの制限によ>>り16メガが最大値です。

COleServerItemから派生したクラスを実装して、WMFを作成させないようにして、EMFファイルを作成するように修正したところ確かに問題なくクリップボードにコピーができました。ありがとうございました。

ただ別の問題が発生したのですが、次のようにメタのデバイスコンテキストを作成したとき、画像データがおかしくなります。

CDoc* pDoc = GetDocument();
POSITION pos = pDoc->GetFirstViewPosition();
CPatwinView* pFirstView = (CView*)pDoc->GetNextView( pos );

CMetaFileDC aEmfDC;
if ( !(aEmfDC.CreateEnhanced(pFirstView->GetDC(), NULL, NULL, NULL)) )
   return FALSE;

if(aEmfDC.m_hAttribDC == NULL) 
aEmfDC.m_hAttribDC = pFirstView->GetDC()->m_hAttribDC;

   OnDraw(&aEmfDC);// 描画

文字化けがおこる。※文字の末尾に不明な文字が付与される。

MM_ANISOTROPICにして、変換ファクタを変更すると、クリップボードには転送されているみたいですが、
描画データが表示されない。※ファイルに保存したところデータ量によって、
EMFファイルのサイズも比例するのですが、ペイントブラシで開くと、0幅で何もないものが開かれる。

マッピングモードを、MM_ANISOTROPICにして、

pDC->SetWindowExt( 1000,1000 );
pDC->SetViewportExt(1000, 1000);とすると0幅の画像データが作成されます。しかし
pDC->SetWindowExt( 1,1 );
pDC->SetViewportExt(1, 1);とすると幅がある画像データが作成されます。
原因が分かりません。おしえてください。

2016年2月19日金曜日 3:01

CreateEnhanced() の3つ目をNULLではなく、きちんとサイズ指定してやれば、サイズがセットされると思います。

Windowsメタファイルと、拡張メタファイルは;ているようでいて結構違いが多く、これでいいんじゃないの?というところはだいたい通用しません(自分の経験則でもありますが...)。

おかしな挙動をしているようだと思ったら、まずはリファレンスを見ることをお勧めします。

とっちゃん@わんくま同盟, Visual Studio and Development Technologies http://blogs.wankuma.com/tocchann/default.aspx


2016年2月19日金曜日 5:28

ご返事ありがとうございます。

>>CreateEnhanced() の3つ目をNULLではなく、きちんとサイズ指定してやれば、サイズがセットされると思います。

ではむりでしたが、APIを直接使用することで図が作成されました。

pDC->SetMapMode( MM_ANISOTROPIC );
::SetWindowExtEx( pDC->m_hDC, size.cx, size.cy, NULL );
::SetViewportExtEx( pDC->m_hDC, size.cx, size.cy, NULL );

また、EMFでのサイズの制限はありますでしょうか。


2016年2月19日金曜日 6:03

「EMF でのサイズ制限」という言い回しから、いろんな要素を含んでいる気がしますが、EMFのサイズ制限は0xFFFFFFFFバイトです。

クリップボードにコピーできるかどうかという話なら、実行環境依存です(このあたりはすでにほかのコメントで出ています)。

とっちゃん@わんくま同盟, Visual Studio and Development Technologies http://blogs.wankuma.com/tocchann/default.aspx