我知道,这种方法已经过时了,只是好奇。当我从 atexit 处理程序调用 ChangeClipboardChain() 时,它成功了。当 precc Ctrl-C 时,它会失败。我知道,因为其他剪贴板查看器不会收到 WM_CHANGECBCHAIN。
此示例程序在将某些内容复制到剪贴板 4 次时退出:
#ifndef _WIN32_WINNT // Allow use of features specific to Windows XP or later.
#define _WIN32_WINNT 0x0501 // Change this to the appropriate value to target other versions of Windows.
#endif
#include <stdio.h>
#include <tchar.h>
#include <windows.h>
static void pWin32Error(const char* fmt, ...);
static int counter=0;
static HWND nextWnd = NULL;
static
LRESULT CALLBACK WindowProc(HWND hwnd,UINT uMsg,WPARAM wParam,LPARAM lParam)
{
switch (uMsg) {
case WM_CHANGECBCHAIN:
{
HWND wndRemove = (HWND)wParam;
HWND wndNextNext = (HWND)lParam;
printf("WM_CHANGECBCHAIN %p %p\n", (void*)wndRemove, (void*)wndNextNext);
if (nextWnd == wndRemove) {
printf("saving next window %p\n", (void*)wndNextNext);
nextWnd = wndNextNext;
} else if (nextWnd) {
printf("notifying next window %p\n", (void*)nextWnd);
return SendMessage(nextWnd,uMsg,wParam,lParam);
} else {
printf("not notifying next window %p\n", (void*)nextWnd);
}
}
break;
case WM_DRAWCLIPBOARD:
counter++;
if (counter > 4) exit(0);
printf("WM_DRAWCLIPBOARD\n");
if (nextWnd) {
printf("notifying next window %p\n", (void*)nextWnd);
return SendMessage(nextWnd,uMsg,wParam,lParam);
} else {
printf("not notifying next window %p\n", (void*)nextWnd);
}
break;
default:
return DefWindowProc( hwnd,uMsg,wParam,lParam);
}
return 0;
}
static volatile HWND global_hwnd = NULL;
WNDCLASS wndclass = {
0,/* UINT style;*/
WindowProc,/* WNDPROC lpfnWndProc;*/
0,/* int cbClsExtra;*/
0,/* int cbWndExtra;*/
NULL,/* HINSTANCE hInstance;*/
NULL,/* HICON hIcon;*/
NULL,/* HCURSOR hCursor;*/
NULL,/* HBRUSH hbrBackground;*/
NULL,/* LPCWSTR lpszMenuName;*/
_T("myclipmonitor")/* LPCWSTR lpszClassName;*/
};
static void unreg() {
HWND hwnd;
hwnd = (HWND)InterlockedExchangePointer(&global_hwnd, NULL); /* ignore the "cast to greater size" warning */
if (hwnd) {
printf("Removing self from chain: %p <- %p\n", (void*)hwnd, (void*)nextWnd);
if (!ChangeClipboardChain(hwnd, nextWnd) && GetLastError() != 0) {
pWin32Error("ChangeClipboardChain() failed");
}
}
}
static void exitproc() {
fprintf(stderr, "exitproc()\n");
unreg();
}
static
BOOL WINAPI CtrlHandler( DWORD fdwCtrlType )
{
fprintf(stderr, "CtrlHandler()\n");
unreg();
switch ( fdwCtrlType ) {
case CTRL_C_EVENT:
fprintf(stderr, "\n\n Stopping due to Ctrl-C.\n" );
break;
case CTRL_CLOSE_EVENT:
fprintf(stderr, "\n\n Stopping due to closing the window.\n" );
break;
case CTRL_BREAK_EVENT:
fprintf(stderr, "\n\n Stopping due to Ctrl-Break.\n" );
break;
// Pass other signals to the next handler - ret = FALSE
case CTRL_LOGOFF_EVENT:
fprintf(stderr, "\n\n Stopping due to logoff.\n" );
break;
case CTRL_SHUTDOWN_EVENT:
fprintf(stderr, "\n\n Stopping due to system shutdown.\n" );
break;
default:
fprintf(stderr, "\n\n Stopping due to unknown event.\n" );
}
return FALSE;
}
int _tmain(int argc, _TCHAR* argv[])
{
ATOM classatom;
HINSTANCE hinst = GetModuleHandle(NULL);
MSG msg;
wndclass.hInstance = hinst;
classatom = RegisterClass(&wndclass);
if (classatom == 0) {
pWin32Error("RegisterClass() failed");
return -1;
}
global_hwnd = CreateWindowEx(0, (LPCTSTR)classatom, NULL, 0, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, NULL, NULL, hinst, NULL);
if (!global_hwnd) {
pWin32Error("CreateWindowEx() failed");
return -1;
}
printf("hwnd = %p\n", (void*)global_hwnd);
nextWnd = SetClipboardViewer(global_hwnd);
if (!nextWnd && GetLastError() != 0) {
pWin32Error("SetClipboardViewer() failed");
return -1;
}
printf("nextWnd = %p\n", (void*)nextWnd);
atexit(exitproc);
if (0 == SetConsoleCtrlHandler( CtrlHandler, TRUE )) {
pWin32Error("SetConsoleCtrlHandler() failed");
return -1;
}
while (GetMessage(&msg, NULL, 0, 0))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
return 0;
}
static char *cleanstr(char *s)
{
while(*s) {
switch((int)*s){
case 13:
case 10:
*s=' ';
break;
}
s++;
}
return s;
}
static void __pWin32Error(int level, DWORD eNum, const char* fmt, va_list args)
{
char emsg[1024];
char *pend = emsg + sizeof(emsg);
size_t count = sizeof(emsg);
unsigned u;
do {
u = (unsigned)_vsnprintf(pend - count, count, fmt, args);
if (u >= count) break;
count -= u;
u = (unsigned)_snprintf(pend - count, count, ": ");
if (u >= count) break;
count -= u;
u = FormatMessageA( FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS,
NULL, eNum,
MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), // Default language
pend - count, (DWORD)count, NULL );
if (u == 0) {
u = (unsigned)_snprintf(pend - count, count, "0x%08x (%d)", eNum, eNum);
}
} while(0);
emsg[sizeof(emsg)-1] = '\0';
pend = cleanstr(emsg);
if (pend < emsg + sizeof(emsg)-1) {
pend++;
*pend = '\0';
}
pend[-1] = '\n';
puts(emsg);
}
static void pWin32Error(const char* fmt, ...)
{
va_list args;
va_start(args, fmt);
__pWin32Error(0, GetLastError(), fmt, args);
va_end(args);
}