我正在改造一些早期的基于MFC的代码。其中有当时运行良好的剪贴板例程。但是当我用 Visual Studio 2022 重建它们时,它们构建但在程序运行时挂在
EmptyClipboard()
。有时当我单步执行代码时,它会起作用,但大多数时候它会在同一点挂起,并给出“断点指令(__debugbreak()
语句或类似调用)已执行”消息作为唯一的解释。如果程序在调试之外运行,那么它就会终止。微软的文献表明OpenClipboard()
调用了HWND
或NULL
的参数,但是如果使用了NULL
那么SetClipboardData
过程将会失败。该计划似乎没有那么远。 OpenClipboard()
的旧版本不需要任何参数,如果我尝试输入一个,它会被拒绝。文献要求 winuser.h 的头文件。但在#included 之后,没有区别,OpenClipboard()
仍然不带参数。有没有人知道发生了什么事?谢谢。
这是整个原工作函数;
void CDibView::OnEditCopy()
{
if( m_id == ID_PALETTEEDIT )
{
m_edit.Copy();
return;
}
BeginWaitCursor();
CDibDoc* pDoc = GetDocument();
// Clean clipboard of contents, and copy the DIB.
if (OpenClipboard())
{
BITMAPINFOHEADER m_Dibhead;
HANDLE m_hBitstore2;
m_Dibhead.biSize = sizeof (BITMAPINFOHEADER);
CSize now = rectSave.Size();
m_Dibhead.biWidth = now.cx;
m_Dibhead.biHeight = now.cy;
m_Dibhead.biPlanes = 1;
m_Dibhead.biBitCount = 24;
m_Dibhead.biCompression = 0;
m_Dibhead.biSizeImage = ((DWORD)m_Dibhead.biWidth * m_Dibhead.biBitCount/ 8) * (DWORD)m_Dibhead.biHeight;
m_Dibhead.biXPelsPerMeter = 0;
m_Dibhead.biYPelsPerMeter = 0;
m_Dibhead.biClrUsed = 0;
m_Dibhead.biClrImportant = 0;
DWORD count = (((DWORD)m_Dibhead.biWidth * m_Dibhead.biBitCount/ 8) * (DWORD)m_Dibhead.biHeight) + (unsigned long)sizeof( BITMAPINFOHEADER );
HBITMAP hBitmap2;
char huge* m_pBitstore;
LPBITMAPINFOHEADER binfo;
CClientDC dc( this );
int next;
for( next = 0; next < 2000; next++ )
{
m_pBitstore = (char huge*)GlobalAllocPtr( GPTR, count + (unsigned long)next );
binfo = (LPBITMAPINFOHEADER)m_pBitstore;
*binfo = m_Dibhead;
if( !(hBitmap2 = ::CreateDIBitmap( dc.m_hDC, (LPBITMAPINFOHEADER)m_pBitstore, CBM_INIT, (LPSTR)m_pBitstore + (unsigned long)sizeof( BITMAPINFOHEADER ), (LPBITMAPINFO)m_pBitstore, DIB_RGB_COLORS ) ))
{
GlobalFreePtr( m_pBitstore ); //There is a problem in fabricating the packed DIB used by clipboard here
} //which dosn't seem to show until an attempt to construct a devise dependant
else //bitmap used in the data transfer. This loop searches for a size of memory
break; //allocation which will function.
}
GlobalFreePtr( m_pBitstore );
/*
#ifdef _DEBUG
afxDump << "Dumping next: = "
<< next
<< "\n";
#endif
*/
m_hBitstore2 = (HANDLE) ::GlobalAlloc( GPTR, count + (unsigned long)next );
LPBITMAPINFOHEADER m_pBitstore2;
m_pBitstore2 = (LPBITMAPINFOHEADER) ::GlobalLock( (HGLOBAL) m_hBitstore2 );
*m_pBitstore2 = m_Dibhead;
::GlobalUnlock((HGLOBAL) m_hBitstore2);
m_pBitstore = (char huge*) ::GlobalLock((HGLOBAL) m_hBitstore2);
CDibDoc* pDoc = GetDocument();
HDIB hDIB = pDoc->GetHDIB();
BYTE huge * lpDIBHdr; // Pointer to BITMAPINFOHEADER
BYTE huge * lpDIBBits; // Pointer to DIB bits
lpDIBHdr = (BYTE huge *) ::GlobalLock((HGLOBAL) hDIB);
lpDIBBits = (BYTE huge *)::FindDIBBits((LPSTR)lpDIBHdr);
HDC hdcMem;
HDC hdcMem2;
hdcMem = ::CreateCompatibleDC( dc.m_hDC );//create a memory device context (display surface)
hdcMem2 = ::CreateCompatibleDC( dc.m_hDC );
HBITMAP hBitmap;
hBitmap = CreateDIBitmap( dc.m_hDC, (LPBITMAPINFOHEADER)lpDIBHdr, CBM_INIT, lpDIBBits, (LPBITMAPINFO)lpDIBHdr, DIB_RGB_COLORS );
char huge* ptr;
ptr = m_pBitstore + (unsigned long)sizeof (BITMAPINFOHEADER);
LPBITMAPINFOHEADER info;
info = (LPBITMAPINFOHEADER)m_pBitstore;
LPBITMAPINFO info2;
info2 = (LPBITMAPINFO)m_pBitstore;
hBitmap2 = ::CreateDIBitmap( dc.m_hDC, info, CBM_INIT, ptr, info2, DIB_RGB_COLORS );
::SelectObject( hdcMem, hBitmap );//make this local bitmap the display surface
::SetMapMode( hdcMem, MM_TEXT );
::SelectObject( hdcMem2, hBitmap2 );//make this local bitmap the display surface
::SetMapMode( hdcMem2, MM_TEXT );
CPoint cp, pc;
cp.x = rectSave.left;
cp.y = rectSave.top;
pc = DibPoint( cp );
::BitBlt( hdcMem2, 0, 0,(int)m_Dibhead.biWidth,(int)m_Dibhead.biHeight, hdcMem, pc.x, pc.y, SRCCOPY );
::GetDIBits( dc.m_hDC, hBitmap2, 0, (int)m_Dibhead.biHeight, ptr, info2, DIB_RGB_COLORS );
if( m_bIscut ) //If Cut does this.
{
LPBITMAPINFOHEADER lpbmi; // pointer to a Win 3.0-style DIB
lpbmi = (LPBITMAPINFOHEADER)lpDIBHdr;
::PatBlt( hdcMem, pc.x, pc.y, (int)m_Dibhead.biWidth, (int)m_Dibhead.biHeight, WHITENESS );//clear contend of local bitmap
::GetDIBits( dc.m_hDC, hBitmap, 0, (int)lpbmi->biHeight, lpDIBBits,(LPBITMAPINFO)lpDIBHdr, DIB_RGB_COLORS );
pDoc->SetModifiedFlag(TRUE);
m_bIscut = FALSE;
::InvalidateRect( this->m_hWnd, NULL, FALSE );
}
/*
#ifdef _DEBUG
afxDump << "Dumping m_hBitstore2: = "
<< m_hBitstore2
<< "\n";
#endif
*/
::GlobalUnlock((HGLOBAL) m_hBitstore2);
EmptyClipboard();
SetClipboardData (CF_DIB, CopyHandle((HANDLE)m_hBitstore2));
CloseClipboard();
::GlobalFree((HGLOBAL) m_hBitstore2);
::DeleteDC( hdcMem );
::DeleteObject( hBitmap );
::GlobalUnlock((HGLOBAL) hDIB);
::DeleteDC( hdcMem2 );
::DeleteObject( hBitmap2 );
EndWaitCursor();
}
}
用
#define huge /* nothing */
取消巨大的关键字。
从上面的初始查询开始,我推断问题出在程序挂起之前,但没有说明原因。翻遍文献后,我还没有找到解决办法。该程序基于旧的 Biblook 示例。当时的例程,用于复制,是从其他地方复制的,用于在客户区中操作区域的代码,仍然可以正常工作。复制和粘贴的代码在当时也是有效的。 如果我将 ptr 变量从原来的更改为如下所示,那么复制和粘贴过程在第一次访问时可以正常工作,但不会再有。如果我取消
::GetDIBits(dc.m_hDC, hBitmap2, 0, (int)m_Dibhead.biHeight, ptr, info2, DIB_RGB_COLORS);
程序那么程序不会挂断但它不会复制选定的客户区。
下面是带有注释的函数的当前状态,因为我试图确定该函数。在这一点上,我假设目前采用了一个完全不同的过程,但我找不到它的例子。或者我的代码中仍然存在我无法确定的错误。
void CDibView::OnEditCopy()
{
if( m_id == ID_PALETTEEDIT ) //Do this if copying text
{
m_edit.Copy();
return;
}
BeginWaitCursor();
CDibDoc* pDoc = GetDocument();
// Clean clipboard of contents, and copy the DIB.
//COleDataSource* pData = new COleDataSource; //For test
if (::OpenClipboard(m_hWnd))
{
//* Setup Dib header
//With #include <wingdi.h>
BITMAPINFOHEADER m_Dibhead;//Header
BITMAPV5HEADER m_V5Dibhead;//Tested but ::CreateDIBitmap wouldn't take
HANDLE m_hBitstore2;
//*Fill header fields
m_Dibhead.biSize = sizeof(BITMAPINFOHEADER);
m_V5Dibhead.bV5Size = sizeof(BITMAPV5HEADER);
CSize now = rectSave.Size(); //Size of select rectangle
m_Dibhead.biWidth = now.cx;
m_V5Dibhead.bV5Width = now.cx;
m_Dibhead.biHeight = now.cy;
m_V5Dibhead.bV5Height = now.cy;
m_Dibhead.biPlanes = 1;
m_V5Dibhead.bV5Planes = 1;
m_Dibhead.biBitCount = 24;
m_V5Dibhead.bV5BitCount = 24;
m_Dibhead.biCompression = 0;
m_V5Dibhead.bV5Compression = 0;
m_Dibhead.biSizeImage = ((DWORD)m_Dibhead.biWidth * m_Dibhead.biBitCount / 8) * (DWORD)m_Dibhead.biHeight;
m_V5Dibhead.bV5SizeImage = m_Dibhead.biSizeImage;
m_Dibhead.biXPelsPerMeter = 0;
m_V5Dibhead.bV5XPelsPerMeter = 0;
m_Dibhead.biYPelsPerMeter = 0;
m_V5Dibhead.bV5YPelsPerMeter = 0;
m_Dibhead.biClrUsed = 0;
m_V5Dibhead.bV5ClrUsed = 0;
m_Dibhead.biClrImportant = 0;
m_V5Dibhead.bV5ClrImportant = 0;
//* End header setup
//Size of Dib file in DWORD
DWORD count = (((DWORD)m_Dibhead.biWidth * m_Dibhead.biBitCount / 8) * (DWORD)m_Dibhead.biHeight) + (unsigned long)sizeof(BITMAPINFOHEADER);
//DWORD count = (((DWORD)m_Dibhead.biWidth * m_Dibhead.biBitCount / 8) * (DWORD)m_Dibhead.biHeight) + (unsigned long)sizeof(BITMAPINFOHEADER);
HBITMAP hBitmap2; //Bitmap handle for Clipboard
char* m_pBitstore; //Character pointer to Dib data
CClientDC dc(this);
//Below was used with early memory architecture to find the smallest usable memory for needed dib
//* Find smallest memory storage that CreateDIBitmap will take
int next = 0;
//for (next = 0; next < 2000; next++)
//{ // Establish a memory size to test
// m_pBitstore = (char*)GlobalAllocPtr(GPTR, count + (unsigned long)next);
// //Test it
// if (!(hBitmap2 = ::CreateDIBitmap(dc.m_hDC, (LPBITMAPINFOHEADER)m_pBitstore, CBM_INIT, (LPSTR)m_pBitstore + (unsigned long)sizeof(BITMAPINFOHEADER), (LPBITMAPINFO)m_pBitstore, DIB_RGB_COLORS)))
// {
// GlobalFreePtr(m_pBitstore); //There is a problem in fabricating the packed DIB used by clipboard here
// } //which dosn't seem to show until an attempt to construct a devise dependant
// else //bitmap used in the data transfer. This loop searches for a size of memory
// break; //allocation which will function.
//}
//GlobalFreePtr(m_pBitstore); // Free up this memory
//::DeleteObject(hBitmap2); //Delete the test dib
// Establish memory for dib using the above tested size
// was m_hBitstore2 = (HANDLE) ::GlobalAlloc( GPTR, count + (unsigned long)next );
m_hBitstore2 = (HANDLE) ::GlobalAlloc(GMEM_FIXED, count + (unsigned long)next);
LPBITMAPINFOHEADER m_pBitstore2; // Establish pointer to this memory and thus the header
m_pBitstore2 = (LPBITMAPINFOHEADER) ::GlobalLock((HGLOBAL)m_hBitstore2);
*m_pBitstore2 = m_Dibhead; // Copy the header values to memory
// Unlock the memory for the dib and then relock to retrieve a char pointer
::GlobalUnlock((HGLOBAL)m_hBitstore2);
m_pBitstore = (char*) ::GlobalLock((HGLOBAL)m_hBitstore2);
//* Get a handle to the whole client window
HDIB hDIB = pDoc->GetHDIB();
BYTE* lpDIBHdr; // Pointer to BITMAPINFOHEADER
BYTE* lpDIBBits; // Pointer to DIB bits
lpDIBHdr = (BYTE*) ::GlobalLock((HGLOBAL)hDIB);
lpDIBBits = (BYTE*)::FindDIBBits((LPSTR)lpDIBHdr);
// Make two device contexts
HDC hdcMem; // One for cutting out the selection box content
HDC hdcMem2; // One for placing into Clipboard
hdcMem = ::CreateCompatibleDC(dc.m_hDC);//create a memory device context (display surface)
hdcMem2 = ::CreateCompatibleDC(dc.m_hDC);
// Create new bitmap using the hDib content
HBITMAP hBitmap;
hBitmap = ::CreateDIBitmap(dc.m_hDC, (LPBITMAPINFOHEADER)lpDIBHdr, CBM_INIT, lpDIBBits, (LPBITMAPINFO)lpDIBHdr, DIB_RGB_COLORS);
// Make pointer to the dib data
char* ptr;
//ptr = m_pBitstore + (unsigned long)sizeof(BITMAPINFOHEADER);
ptr = m_pBitstore + (lpDIBBits - lpDIBHdr);
// Make poiner to header in the established memory
LPBITMAPINFOHEADER info;
info = (LPBITMAPINFOHEADER)m_pBitstore;
// Make pointer to a BITMAPINFOHEADER struct plus a RGBQUAD struct
LPBITMAPINFO info2;
info2 = (LPBITMAPINFO)m_pBitstore;
// Create the new (BUT EMPTY) dib using these values
hBitmap2 = ::CreateDIBitmap(dc.m_hDC, info, CBM_INIT, ptr, info2, DIB_RGB_COLORS);
::SelectObject(hdcMem, hBitmap);//make this local bitmap for cutting out selection box
::SetMapMode(hdcMem, MM_TEXT);
::SelectObject(hdcMem2, hBitmap2);//make this local bitmap for the Clipboard
::SetMapMode(hdcMem2, MM_TEXT);
// Retrieve location for top-left corner of selection box
CPoint cp, pc;
cp.x = rectSave.left;
cp.y = rectSave.top;
pc = DibPoint(cp); // Find location of data in client window
// Retrieve color data from selection box for Clipboard and put it in new dib
BOOL bb = ::BitBlt(hdcMem2, 0, 0, (int)m_Dibhead.biWidth, (int)m_Dibhead.biHeight, hdcMem, pc.x, pc.y, SRCCOPY);
if (!bb)
{
::MessageBox(m_hWnd, "BitBlt has failed", "Failed", MB_OK);
}
// Get image data of bitmap for Clipboard
int gb = ::GetDIBits(dc.m_hDC, hBitmap2, 0, (int)m_Dibhead.biHeight, ptr, info2, DIB_RGB_COLORS);
if (gb == ERROR_INVALID_PARAMETER || gb == 0)
{
::MessageBox(m_hWnd, "GetDIBits has failed", "Failed", MB_OK);
}
if (m_bIscut) //If Cut, does this.
{
LPBITMAPINFOHEADER lpbmi; // pointer to a Win 3.0-style DIB
lpbmi = (LPBITMAPINFOHEADER)lpDIBHdr;
// Make selection box image white
::PatBlt(hdcMem, pc.x, pc.y, (int)m_Dibhead.biWidth, (int)m_Dibhead.biHeight, WHITENESS);//clear contend of local bitmap
// Make white dib for selection box
::GetDIBits(dc.m_hDC, hBitmap, 0, (int)lpbmi->biHeight, lpDIBBits, (LPBITMAPINFO)lpDIBHdr, DIB_RGB_COLORS);
pDoc->SetModifiedFlag(TRUE);
m_bIscut = FALSE;
::InvalidateRect(this->m_hWnd, NULL, FALSE);
}
::GlobalUnlock((HGLOBAL)m_hBitstore2);
/*pData->CacheGlobalData(CF_DIB, m_hBitstore2);//For test
pData->SetClipboard();*/
::EmptyClipboard();
::SetClipboardData(CF_DIB, CopyHandle((HANDLE)m_hBitstore2));
::CloseClipboard();
::GlobalFree((HGLOBAL)m_hBitstore2);
::DeleteDC(dc);
::DeleteDC(hdcMem);
::DeleteObject(hBitmap);
::GlobalUnlock((HGLOBAL)hDIB);
::DeleteDC(hdcMem2);
::DeleteObject(hBitmap2);
EndWaitCursor();
}
}