How Can I Paste a Picture?
I want to paste a picture from Paint into my program. My code is:
Code:
HANDLE handle = GetClipboardData( CF_METAFILEPICT );
if ( handle )
{
METAFILEPICT *mfp = (METAFILEPICT*) GlobalLock( handle );
NumBytes = GlobalSize( mfp->hMF );
}
When running the program, all the fields of the METAFILEPICT structure are set to reasonable values, but NumBytes is zero. The debugger also says that mfp->hMF is unused. If I ignore this and try to replay the picture nonetheless, my program crashes. I can however paste the same picture into WordPad with no problem. What's wrong with my program?
Another problem is that my program draws using the Direct2D APIs. I can't find an example on the internet of a program that replays a metafile into Direct2D. From the MS documentation I understand that I should use
Code:
SHCreateMemStream()
ID2D1Factory1::CreateGdiMetafile()
ID2D1DeviceContext::DrawGdiMetafile()
What pointer should I pass to SHCreateMemStream?
Any help is greatly appreciated.
Re: How Can I Paste a Picture?
From MSDN:
Quote:
GlobalSize
...
Return Values
If the function succeeds, the return value is the size, in bytes, of the specified global memory object.
If the specified handle is not valid or if the object has been discarded, the return value is zero. To get extended error information, call GetLastError.
Re: How Can I Paste a Picture?
GetLastError() returns 6. I can't find the meaning of this code, however.
GlobalFlags( mfp->hMF ) returns GMEM_INVALID_HANDLE
Re: How Can I Paste a Picture?
Error 6 means:
Quote:
6 The handle is invalid. ERROR_INVALID_HANDLE
Re: How Can I Paste a Picture?
what shall i do to get a valid handle from the METAFILEPICT structure?
Re: How Can I Paste a Picture?
Quote:
Originally Posted by
semispin
what shall i do to get a valid handle from the METAFILEPICT structure?
Are you sure that the clipboard format is CF_METAFILEPICT?
Did you open the clipboard before calling GetClipboardData?
Re: How Can I Paste a Picture?
Here is the whole function:
Code:
void PerformPaste( Document *doc )
{
HANDLE CDdata;
Note *note;
Rect *R;
PageInfo *page = doc->page;
Layout *L = page->piece;
int ceiling = doc->height;
BOOL PlainTextAvailable = FALSE, PictAvailable = FALSE;
UINT flavor = 0, pick, temp, result = kNoData;
if (! OpenClipboard( NULL ) ) return;
while (flavor = EnumClipboardFormats( flavor ))
{
UINT temp = kNoData;
switch ( flavor )
{
case CF_TEXT:
temp = kPlainTextData;
PlainTextAvailable = TRUE;
break; // manca la bitmap
case CF_METAFILEPICT:
temp = kMetaData;
PictAvailable = TRUE;
break;
default:
if (flavor == CF_iNMR_Page)
temp = kPageData;
else if (flavor == CF_iNMR_Regions)
temp = kRegionsData;
}
if (temp > result)
{
result = temp;
pick = flavor;
}
}
switch( result )
{
case kPageData: PastePage( doc ); goto closing;
case kRegionsData:
if (PasteIntegrals( doc )) // can we accept integral regions ?
goto closing;
result = kPlainTextData; // if not, the list as text is good
pick = CF_TEXT;
}
if ( result )
{
SetDirty( doc );
note = (Note*) calloc( 1, sizeof(Note) );
switch ( result )
{
case kPlainTextData:
{
HANDLE handle = GetClipboardData( CF_UNICODETEXT );
wchar_t *source = (wchar_t*) GlobalLock( handle );
if (note->bytes = TextDataFromClipboard( source ))
TextCleaning( note );
else if (note->bytes = CreateUnicodeData( source, FALSE ))
result = kUnicodeData;
GlobalUnlock( handle );
break;
}
case kMetaData:
{
HANDLE handle = GetClipboardData( CF_METAFILEPICT );
if ( handle )
{
METAFILEPICT *mfp = (METAFILEPICT*) GlobalLock( handle );
int NumBytes = GlobalSize( mfp->hMF );
if ( NumBytes )
{
void *buffer = malloc( NumBytes );
memcpy( buffer, GlobalLock( mfp->hMF ), NumBytes );
CFDataRef data = (CFDataRef) calloc( 1, sizeof(CFData) );
data->p.kind = isData;
data->storage = (unsigned char*) buffer;
data->mark = data->storage + NumBytes;
data->p.length = NumBytes & 0xffff;
note->bytes = data;
note->position.right = mfp->xExt; // when mfp->mm == 8 these values only give the proportions
note->position.bottom = mfp->yExt;
}
else NumBytes = GetLastError();
NumBytes = GlobalFlags( mfp->hMF );
GlobalUnlock( handle );
}
}
}
if (note->bytes)
{
note->flags = (L->mode & kShowClips) != kShowStickyClips ? NoteFloats : 0;
note->kind = result;
if ( HAS_FONT(note) )
{
wchar_t *fn;
if (global->NoteFont != NULL)
{
fn = global->NoteFont;
note->fsize = global->NoteSize;
}
else
{
fn = page->fontface;
note->fsize = page->fontsize;
}
wcscpy( note->fname = (wchar_t*) malloc( 2 * wcslen(fn) + 2 ), fn );
}
if (MonoDimensional( L )) note->flags |= NoteMono; else note->flags &= ~ NoteMono;
if (note->flags & NoteFloats)
{
FixNote( note, doc );
VisibleRange( L, ¬e->f.x, ¬e->f.y, ceiling );
if (result == kArrowData || result == kFrameData)
VisibleRange( L, ¬e->o.x, ¬e->o.y, ceiling );
}
doc->Labels.push_back( note );
L->mode |= note->flags & NoteFloats ? kShowFlowingClips : kShowStickyClips;
note->flags |= NoteIsNew;
R = ¬e->position;
R->top = R->bottom = ceiling >> 2;
R->left = R->right = doc->width >> 2;
if (result > kFrameData) // pictures
{
R->left = 0.5 * (R->left + R->right) + 0.5;
R->top = 0.5 * (R->top + R->bottom) + 0.5;
}
}
else free( note );
}
closing :
CloseClipboard( );
}
It already works when the content of the clipboard is text. As you can see, I use OpenClipboard() and perform a loop with EnumClipboardFormats(), that confirms that CF_METAFILEPICT is there. The rest of the METAFILEPICT structure is OK. mm = 8, which menas MM_ANISOTROPIC ; xExt and yExt more or less correspond to the picture that I have copied.
Re: How Can I Paste a Picture?
do you have an example project that I can open with Visual Studio 2012 and compare with mine?
Re: How Can I Paste a Picture?
Quote:
GetLastError() returns 6. I can't find the meaning of this code, however.
The file WinError.h contains details of the error codes. You can also use the program errlook.exe that comes with Microsoft Visual Studio.
Re: How Can I Paste a Picture?
I have solved part of the problem. Thanks to those who have helped. It seems that HMETAFILE is not an handle or, more exactly, the Handle functions do not work with HMETAFILE. I can, instead, save the metafile as a file with CopyMetaFile(), which works, then move the bytes from disc to memory. My metadata is now stored into the buffer ptr. The next step is
IStream* stream = SHCreateMemStream( (BYTE*) ptr, length );
which also seems to work. The following step fails instead.
ID2D1GdiMetafile *metafile;
HRESULT hr = ((ID2D1Factory1*) d2dFactory)->CreateGdiMetafile( stream, &metafile );
returns the error D2DERR_UNSUPPORTED_OPERATION.
I have Windows 7 SP1 with Platform Update. I have been able to create the ID2D1Factory1, why doesn't it support all of its methods? If this is impossible with Direct2D, is it possible to playback a picture into a Direct2D render target in any other way?