12.1 剪贴板的简单用法
12.1.1 剪贴板的标准格式
分类 |
标准格式 |
说明 |
文本格式 |
CF_TEXT |
以NULL结尾的ANSI字符集,每行结尾含有回车换行符,最后的NULL表示整个数据的结束。 |
CF_OEMTEXT |
以NULL结尾的OEM字符集,供MS-DOS下的剪贴板使用 |
|
CF_UNICODETEXT |
类似CF_TEXT,每行以回车换行结束,字符两个NULL标志着整个数据的结束。 |
|
CF_SYLK |
含有微软件符号链接(Symbolic Link)格式数据的内存块。用与Excel程序交换,是一种ASCII格式,每行以回车换行符结束,但不一定以NULL结尾,现在很少用到。 |
|
位图相关 |
CF_BITMAP |
设备相关位图 |
CF_DIB |
设备无关位图的内存块(以位图信息结构开头,接着有可能是颜色表和位图的位) |
|
CF_PALETTE |
指向调色板的句柄,通常与CF_DIB一起使用 |
|
CF_TIFF |
标签图像文件格式的内存块 |
|
图元 文件 格式 |
CF_METAFILEPICT |
基于Windows过去支持的图元文件 |
CF_ENHMETAFILE |
指向32位Windows版本支持的增强型图元文件 |
|
其他 格式 |
CF_PENDATA |
和Windows画笔扩展一起使用 |
CF_WAVE |
声音波形文件 |
|
CF_RIFF |
资源交换文件格式的多媒体数据 |
|
CF_HDROP |
和拖放服务一起使用的文件列表 |
12.1.2 内存分配——GlobalAlloc(uiFlags,dwSize)
(1)全局内存块的创建(用GlobalAlloc,而不能用malloc)
①固定内存块:hGlobal = GlobalAlloc(GMEM_FIXED|GMEM_ZEROPOINT,dwSize);
A、返回值:指向全局内存块的句柄(全局句柄),Fixed时,实际上也是内存块的指针。
B 、GPTR标志:#define GPTR (GMEM_FIXED | GMEM_ZEROPOINT)
C 、GMEM_FIXED标志指明了该内存块的虚拟地址不可更改(但Windows会通过改变页表移动物理内存的内存块)。
②可移动内存块:hGlobal = GlobalAlloc(GMEM_MOVEABLE | GMEM_ZEROPOINT,dwSize);
A、返回值:返回全局句柄,但不是该内存块的指针。(因为Windows可能会移动虚拟地址),其指针的获取方法:
int* pGlobal;
GLOBALHANDLE hGlobal;
hGlobal = GlobalAlloc(GHND,1024);
pGlobal =(int*) GlobalLock(hGlobal); //锁定内存块以获取指针(防虚址被改变)。
……
GlobalUnlock(hGlobal);//解锁内存块,Windows又可以自由移动该内存块了
B、GHND标志:#define GHND (GMEM_MOVEABLE| GMEM_ZEROPOINT)
C、GMEM_MOVEABLED标志Windows能在虚拟内存中移动内存块(不并移动物理内存)
(2)其它标准内存管理函数
内存重分配函数 |
hGlobal = GlobalReAlloc(hGlobal,dwSize,uiFlags); |
获取内存块大小 |
dwSize = GlobalSize(hGlobal); |
获取内存块句柄 |
hGlobal = GlobalHandle(p); //p为指向内存块的地址(指可移动内存块) |
释放内存函数 |
GlobalFree(hGlobal); |
(3)为什么要用全局句柄,而不直接用指针?(点这里的链接)
12.1.3 把文本传到剪贴板——以ANSI字符串传到剪贴板例
//1、分配全局内存块(可移动、可供其他应该程序共享) hGlobal = GlobalAlloc(GHND|GMEM_SHARE,iLength+1); //GMEM_SHARE表示内存块能被其他程序共享 //2、将字符串复制到全局内存块 pGlobal = GlobalLock(hGlobal); //锁定内存,获取指针 for(int i=0;i<wLength,i++) //复制字符串,不需要加NULL,因为GMEM_ZEROPOINT了。 *pGlobal++ = *pString++; GlobalUnlock(hGlobal); //解锁内存块 //3、将内存块传入剪贴板 OpenClipboard(hwnd); //打开剪贴板并清空。注意:Open和Close要在同一消息里进行。 EmptyClipboard(); hData =SetClipboardData(CF_TEXT,hGlobal);//将内存句柄传给剪贴板。(hGlobal一定会先被解锁) …… //1、这时不能再通过hGlobal使用这块内存了, 因为hGlobal …… // 这句柄是程序本身的。但该内存块己属剪贴板,而不属于本程 // 序了。这里应当把hGlobal当作是无效的。 //2、如果需要继续使用数据,应再复制一份或从剪贴板中读取。 //3、从剪贴板读取的方法:SetClipboardData返回的是全 // 指向剪贴板中那块内存的全局句柄hData,可利用这个句柄 // (而不是传入该函数的句柄hGlobal)。然后锁定内存,再通过 // 获取指针来访问剪贴板。最后解锁hData句柄。 CloseClipboard(); //关闭剪贴板
12.1.4 从剪贴板取得文本
//1、确定剪贴板是否包含CF_TEXT格式的文本 bAvailable = IsClipboardFormatAvailable(CF_TEXT); //不需要打开剪贴板 //2、将文本传出 OpenClipboard(hwnd); //打开剪贴板得,得传入窗口句柄。 hGlobal = GetClipboardData(CF_TEXT);//如果hGlobal为NULL,表示没有文本,再次确认文本是否存在。 //注意,这里的句柄不属于程序,而是属于剪贴板,该句柄只在 //GetClipboardData和CloseClipboard之间有效。 pText = (char*)malloc(GlobalSize(hGlobal))); //分配复制文本的缓冲区 pGlobal = GlobalLock(hGlobal); strcpy(pText,pGlobal); //复制文本 GlobalUnlock(hGlobal); CloseClipboard(); //关闭剪贴板
12.1.5 打开和关闭剪贴板
①无论何时,只有一个程序可以打开剪贴板。OpenClipboard(hwnd)打开剪贴板,使hWnd指向的窗口成为剪贴板的拥有者,一直持续到CloseClipboard()函数的调用后结束。在此期间,剪贴板为拥有者所独占,其他进程将无法对剪贴板内容进行修改。
②剪贴板的内容并不可靠,在用户复制后,调用粘贴之前的这段时间内其他程序修改了剪贴板的内容。
③由于GetClipboardData()获取的数据句柄是属于剪贴板的,因此用户程序必须在调用CloseClipboard()函数之前使用它。
④关闭剪贴板之前,不要弹出消息框或对话框——因为其他程序无法使用剪贴板。
OpenClipboard(hwnd); …… //1、这里不要弹出消息框,会使其他程序无法使用剪贴板。 //2、这里也不要使用对话框,因为对话框内的一些编辑控件可能需要 //使用剪贴板来剪切或粘贴。 CloseClipboard();
12.1.6 剪贴板和Unicode
(1)Unicode格式的用CF_UNICODETEXT
(2)利用剪贴板在两个字符集之间进行文本格式的转换:将ANSI转为Unicode
①SetClipboardData时用CT_TEXT
②而GetClipboard用CT_UNICODETEXT
【ClipText程序】
效果图
/*------------------------------------------------------------ CLIPTEXT.C -- The Clipboard and Text (c) Charles Petzold, 1998 ------------------------------------------------------------*/ #include <windows.h> #include "resource.h" #ifdef UNICODE #define CF_TCHAR CF_UNICODETEXT TCHAR szDefaultText[] = TEXT("Default Text - Unicode Version"); TCHAR szCaption[] = TEXT("Clipboard Text Transfers - Unicode Version"); #else #define CF_TCHAR CF_TEXT TCHAR szDefaultText[] = TEXT("Default Text - ANSI Version"); TCHAR szCaption[] = TEXT("Clipboard Text Transfers - ANSI Version"); #endif // UNICODE LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM); int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, PSTR szCmdLine, int iCmdShow) { static TCHAR szAppName[] = TEXT("ClipText"); HWND hwnd; MSG msg; WNDCLASSEX wndclass; HACCEL hAccel; wndclass.style = CS_HREDRAW | CS_VREDRAW; wndclass.cbSize = sizeof(WNDCLASSEX); wndclass.lpfnWndProc = WndProc; wndclass.cbClsExtra = 0; wndclass.cbWndExtra = 0; wndclass.hInstance = hInstance; wndclass.hIcon = LoadIcon(hInstance, szAppName); wndclass.hIconSm = LoadIcon(hInstance, szAppName); wndclass.hCursor = LoadCursor(NULL, IDC_ARROW); wndclass.hbrBackground = (HBRUSH)GetStockObject(WHITE_BRUSH); wndclass.lpszMenuName = szAppName; wndclass.lpszClassName = szAppName; if (!RegisterClassEx(&wndclass)) { MessageBox(NULL, TEXT("This program requires Windows NT!"), szAppName, MB_ICONERROR); return 0; } hwnd = CreateWindow(szAppName, // window class name szCaption, // window caption WS_OVERLAPPEDWINDOW, // window style CW_USEDEFAULT, // initial x position CW_USEDEFAULT, // initial y position CW_USEDEFAULT, // initial x size CW_USEDEFAULT, // initial y size NULL, // parent window handle NULL, // window menu handle hInstance, // program instance handle NULL); // creation parameters ShowWindow(hwnd, iCmdShow); UpdateWindow(hwnd); hAccel = LoadAccelerators(hInstance, szAppName); while (GetMessage(&msg, NULL, 0, 0)) { if (!TranslateAccelerator(hwnd, hAccel, &msg)) { TranslateMessage(&msg); DispatchMessage(&msg); } } return msg.wParam; } LRESULT CALLBACK WndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam) { HDC hdc; PAINTSTRUCT ps; RECT rect; static PTSTR pText; BOOL bEnable; HGLOBAL hGlobal; PTSTR pGlobal; switch (message) { case WM_CREATE: SendMessage(hwnd, WM_COMMAND, IDM_EDIT_RESET, 0); return 0; case WM_INITMENUPOPUP: EnableMenuItem((HMENU)wParam, IDM_EDIT_PASTE, IsClipboardFormatAvailable(CF_TCHAR) ? MF_ENABLED : MF_GRAYED); bEnable = pText ? MF_ENABLED : MF_GRAYED; EnableMenuItem((HMENU)wParam, IDM_EDIT_CUT, bEnable); EnableMenuItem((HMENU)wParam, IDM_EDIT_COPY, bEnable); EnableMenuItem((HMENU)wParam, IDM_EDIT_DELETE, bEnable); break; case WM_COMMAND: switch (LOWORD(wParam)) { case IDM_EDIT_PASTE: OpenClipboard(hwnd); hGlobal = GetClipboardData(CF_TCHAR); if (hGlobal != NULL) { pGlobal = GlobalLock(hGlobal); //锁定内存块,获取指针 if (pText) { free(pText); pText = NULL; } pText = malloc(GlobalSize(hGlobal)); lstrcpy(pText, pGlobal); GlobalUnlock(hGlobal); InvalidateRect(hwnd, NULL, TRUE); } CloseClipboard(); return 0; case IDM_EDIT_CUT: case IDM_EDIT_COPY: if (!pText) return 0; //分配内存并拷贝数据到全局内存块里 hGlobal = GlobalAlloc(GHND | GMEM_SHARE, (lstrlen(pText) + 1)*sizeof(TCHAR)); pGlobal = GlobalLock(hGlobal); lstrcpy(pGlobal, pText); GlobalUnlock(hGlobal); //将内存块传入剪贴板 OpenClipboard(hwnd); EmptyClipboard(); SetClipboardData(CF_TCHAR, hGlobal); CloseClipboard(); if (LOWORD(wParam) == IDM_EDIT_COPY) return 0; //剪切时,继续向下执行。 case IDM_EDIT_DELETE: if (pText) { free(pText); pText = NULL; } InvalidateRect(hwnd, NULL, TRUE); return 0; case IDM_EDIT_RESET: if (pText) { free(pText); pText = NULL; } pText = (PTSTR)malloc((lstrlen(szDefaultText) + 1)*sizeof(TCHAR)); lstrcpy(pText, szDefaultText); InvalidateRect(hwnd, NULL, TRUE); return 0; } break; case WM_PAINT: hdc = BeginPaint(hwnd, &ps); GetClientRect(hwnd, &rect); DrawText(hdc, pText, -1, &rect, DT_EXPANDTABS | DT_WORDBREAK); EndPaint(hwnd, &ps); return 0; case WM_DESTROY: PostQuitMessage(0); return 0; } return DefWindowProc(hwnd, message, wParam, lParam); }
//resource.h
//{{NO_DEPENDENCIES}} // Microsoft Visual C++ 生成的包含文件。 // 供 ClipText.rc 使用 // #define IDM_EDIT_CUT 40001 #define IDM_EDIT_COPY 40002 #define IDM_EDIT_PASTE 40003 #define IDM_EDIT_DELETE 40004 #define IDM_EDIT_RESET 40005 // Next default values for new objects // #ifdef APSTUDIO_INVOKED #ifndef APSTUDIO_READONLY_SYMBOLS #define _APS_NEXT_RESOURCE_VALUE 103 #define _APS_NEXT_COMMAND_VALUE 40012 #define _APS_NEXT_CONTROL_VALUE 1001 #define _APS_NEXT_SYMED_VALUE 101 #endif #endif
//ClipText.rc
// Microsoft Visual C++ generated resource script. // #include "resource.h" #define APSTUDIO_READONLY_SYMBOLS ///////////////////////////////////////////////////////////////////////////// // // Generated from the TEXTINCLUDE 2 resource. // #include "winres.h" ///////////////////////////////////////////////////////////////////////////// #undef APSTUDIO_READONLY_SYMBOLS ///////////////////////////////////////////////////////////////////////////// // 中文(简体,中国) resources #if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_CHS) LANGUAGE LANG_CHINESE, SUBLANG_CHINESE_SIMPLIFIED #ifdef APSTUDIO_INVOKED ///////////////////////////////////////////////////////////////////////////// // // TEXTINCLUDE // 1 TEXTINCLUDE BEGIN "resource.h\0" END 2 TEXTINCLUDE BEGIN "#include ""winres.h""\r\n" "\0" END 3 TEXTINCLUDE BEGIN "\r\n" "\0" END #endif // APSTUDIO_INVOKED ///////////////////////////////////////////////////////////////////////////// // // Menu // CLIPTEXT MENU BEGIN POPUP "&Edit" BEGIN MENUITEM "Cu&t\tCtrl+X", IDM_EDIT_CUT MENUITEM "&Copy\t Ctrl+C", IDM_EDIT_COPY MENUITEM "&Paste\tCtrl+V", IDM_EDIT_PASTE MENUITEM "&Delete\tDel", IDM_EDIT_DELETE MENUITEM SEPARATOR MENUITEM "&Reset", IDM_EDIT_RESET END END ///////////////////////////////////////////////////////////////////////////// // // Accelerator // ClipText ACCELERATORS BEGIN "^C", IDM_EDIT_COPY, ASCII, NOINVERT "^X", IDM_EDIT_CUT, ASCII, NOINVERT "^V", IDM_EDIT_PASTE, ASCII, NOINVERT VK_DELETE, IDM_EDIT_DELETE, VIRTKEY, NOINVERT END #endif // 中文(简体,中国) resources ///////////////////////////////////////////////////////////////////////////// #ifndef APSTUDIO_INVOKED ///////////////////////////////////////////////////////////////////////////// // // Generated from the TEXTINCLUDE 3 resource. // ///////////////////////////////////////////////////////////////////////////// #endif // not APSTUDIO_INVOKED