mirror of
https://github.com/reactos/reactos.git
synced 2024-09-12 13:54:41 +00:00
608 lines
15 KiB
C
608 lines
15 KiB
C
/*
|
|
* COPYRIGHT: See COPYING in the top level directory
|
|
* PROJECT: ReactOS Clipboard Viewer
|
|
* FILE: base/applications/clipbrd/clipbrd.c
|
|
* PURPOSE: Provides a view of the contents of the ReactOS clipboard.
|
|
* PROGRAMMERS: Ricardo Hanke
|
|
*/
|
|
|
|
#include "precomp.h"
|
|
|
|
static const WCHAR szClassName[] = L"ClipBookWClass";
|
|
|
|
CLIPBOARD_GLOBALS Globals;
|
|
SCROLLSTATE Scrollstate;
|
|
|
|
static void UpdateLinesToScroll(void)
|
|
{
|
|
UINT uLinesToScroll;
|
|
|
|
if (!SystemParametersInfo(SPI_GETWHEELSCROLLLINES, 0, &uLinesToScroll, 0))
|
|
{
|
|
Globals.uLinesToScroll = 3;
|
|
}
|
|
else
|
|
{
|
|
Globals.uLinesToScroll = uLinesToScroll;
|
|
}
|
|
}
|
|
|
|
static void SaveClipboardToFile(void)
|
|
{
|
|
OPENFILENAMEW sfn;
|
|
WCHAR szFileName[MAX_PATH];
|
|
WCHAR szFilterMask[MAX_STRING_LEN + 10];
|
|
LPWSTR c;
|
|
|
|
ZeroMemory(&szFilterMask, sizeof(szFilterMask));
|
|
c = szFilterMask + LoadStringW(Globals.hInstance, STRING_FORMAT_NT, szFilterMask, MAX_STRING_LEN) + 1;
|
|
wcscpy(c, L"*.clp");
|
|
|
|
ZeroMemory(&szFileName, sizeof(szFileName));
|
|
ZeroMemory(&sfn, sizeof(sfn));
|
|
sfn.lStructSize = sizeof(sfn);
|
|
sfn.hwndOwner = Globals.hMainWnd;
|
|
sfn.hInstance = Globals.hInstance;
|
|
sfn.lpstrFilter = szFilterMask;
|
|
sfn.lpstrFile = szFileName;
|
|
sfn.nMaxFile = ARRAYSIZE(szFileName);
|
|
sfn.Flags = OFN_PATHMUSTEXIST | OFN_HIDEREADONLY | OFN_OVERWRITEPROMPT;
|
|
sfn.lpstrDefExt = L"clp";
|
|
|
|
if (!GetSaveFileNameW(&sfn))
|
|
return;
|
|
|
|
if (!OpenClipboard(Globals.hMainWnd))
|
|
{
|
|
ShowLastWin32Error(Globals.hMainWnd);
|
|
return;
|
|
}
|
|
|
|
WriteClipboardFile(szFileName, CLIP_FMT_NT /* CLIP_FMT_31 */);
|
|
|
|
CloseClipboard();
|
|
}
|
|
|
|
static void LoadClipboardDataFromFile(LPWSTR lpszFileName)
|
|
{
|
|
if (MessageBoxRes(Globals.hMainWnd, Globals.hInstance,
|
|
STRING_DELETE_MSG, STRING_DELETE_TITLE,
|
|
MB_ICONWARNING | MB_YESNO) != IDYES)
|
|
{
|
|
return;
|
|
}
|
|
|
|
if (!OpenClipboard(Globals.hMainWnd))
|
|
{
|
|
ShowLastWin32Error(Globals.hMainWnd);
|
|
return;
|
|
}
|
|
|
|
EmptyClipboard();
|
|
ReadClipboardFile(lpszFileName);
|
|
|
|
CloseClipboard();
|
|
}
|
|
|
|
static void LoadClipboardFromFile(void)
|
|
{
|
|
OPENFILENAMEW ofn;
|
|
WCHAR szFileName[MAX_PATH];
|
|
WCHAR szFilterMask[MAX_STRING_LEN + 10];
|
|
LPWSTR c;
|
|
|
|
ZeroMemory(&szFilterMask, sizeof(szFilterMask));
|
|
c = szFilterMask + LoadStringW(Globals.hInstance, STRING_FORMAT_GEN, szFilterMask, MAX_STRING_LEN) + 1;
|
|
wcscpy(c, L"*.clp");
|
|
|
|
ZeroMemory(&szFileName, sizeof(szFileName));
|
|
ZeroMemory(&ofn, sizeof(ofn));
|
|
ofn.lStructSize = sizeof(ofn);
|
|
ofn.hwndOwner = Globals.hMainWnd;
|
|
ofn.hInstance = Globals.hInstance;
|
|
ofn.lpstrFilter = szFilterMask;
|
|
ofn.lpstrFile = szFileName;
|
|
ofn.nMaxFile = ARRAYSIZE(szFileName);
|
|
ofn.Flags = OFN_PATHMUSTEXIST | OFN_HIDEREADONLY | OFN_FILEMUSTEXIST;
|
|
|
|
if (!GetOpenFileNameW(&ofn))
|
|
return;
|
|
|
|
LoadClipboardDataFromFile(szFileName);
|
|
}
|
|
|
|
static void LoadClipboardFromDrop(HDROP hDrop)
|
|
{
|
|
WCHAR szFileName[MAX_PATH];
|
|
|
|
DragQueryFileW(hDrop, 0, szFileName, ARRAYSIZE(szFileName));
|
|
DragFinish(hDrop);
|
|
|
|
LoadClipboardDataFromFile(szFileName);
|
|
}
|
|
|
|
static void SetDisplayFormat(UINT uFormat)
|
|
{
|
|
CheckMenuItem(Globals.hMenu, Globals.uCheckedItem, MF_BYCOMMAND | MF_UNCHECKED);
|
|
Globals.uCheckedItem = uFormat + CMD_AUTOMATIC;
|
|
CheckMenuItem(Globals.hMenu, Globals.uCheckedItem, MF_BYCOMMAND | MF_CHECKED);
|
|
|
|
if (uFormat == 0)
|
|
{
|
|
Globals.uDisplayFormat = GetAutomaticClipboardFormat();
|
|
}
|
|
else
|
|
{
|
|
Globals.uDisplayFormat = uFormat;
|
|
}
|
|
|
|
if (Globals.hDspBmp)
|
|
{
|
|
DeleteObject(Globals.hDspBmp);
|
|
}
|
|
|
|
ZeroMemory(&Scrollstate, sizeof(Scrollstate));
|
|
UpdateWindowScrollState(Globals.hMainWnd, Globals.hDspBmp, &Scrollstate);
|
|
|
|
InvalidateRect(Globals.hMainWnd, NULL, TRUE);
|
|
}
|
|
|
|
static void InitMenuPopup(HMENU hMenu, LPARAM index)
|
|
{
|
|
if ((GetMenuItemID(hMenu, 0) == CMD_DELETE) || (GetMenuItemID(hMenu, 1) == CMD_SAVE_AS))
|
|
{
|
|
if (CountClipboardFormats() == 0)
|
|
{
|
|
EnableMenuItem(hMenu, CMD_DELETE, MF_GRAYED);
|
|
EnableMenuItem(hMenu, CMD_SAVE_AS, MF_GRAYED);
|
|
}
|
|
else
|
|
{
|
|
EnableMenuItem(hMenu, CMD_DELETE, MF_ENABLED);
|
|
EnableMenuItem(hMenu, CMD_SAVE_AS, MF_ENABLED);
|
|
}
|
|
}
|
|
|
|
DrawMenuBar(Globals.hMainWnd);
|
|
}
|
|
|
|
static void UpdateDisplayMenu(void)
|
|
{
|
|
UINT uFormat;
|
|
WCHAR szFormatName[MAX_FMT_NAME_LEN + 1];
|
|
HMENU hMenu;
|
|
|
|
hMenu = GetSubMenu(Globals.hMenu, DISPLAY_MENU_POS);
|
|
|
|
while (GetMenuItemCount(hMenu) > 1)
|
|
{
|
|
DeleteMenu(hMenu, 1, MF_BYPOSITION);
|
|
}
|
|
|
|
if (CountClipboardFormats() == 0)
|
|
return;
|
|
|
|
if (!OpenClipboard(Globals.hMainWnd))
|
|
return;
|
|
|
|
AppendMenuW(hMenu, MF_SEPARATOR, 0, NULL);
|
|
|
|
uFormat = EnumClipboardFormats(0);
|
|
while (uFormat)
|
|
{
|
|
RetrieveClipboardFormatName(Globals.hInstance, uFormat, TRUE, szFormatName, ARRAYSIZE(szFormatName));
|
|
|
|
if (!IsClipboardFormatSupported(uFormat))
|
|
{
|
|
AppendMenuW(hMenu, MF_STRING | MF_GRAYED, 0, szFormatName);
|
|
}
|
|
else
|
|
{
|
|
AppendMenuW(hMenu, MF_STRING, CMD_AUTOMATIC + uFormat, szFormatName);
|
|
}
|
|
|
|
uFormat = EnumClipboardFormats(uFormat);
|
|
}
|
|
|
|
CloseClipboard();
|
|
}
|
|
|
|
static int ClipboardCommandHandler(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
|
|
{
|
|
switch (LOWORD(wParam))
|
|
{
|
|
case CMD_OPEN:
|
|
{
|
|
LoadClipboardFromFile();
|
|
break;
|
|
}
|
|
|
|
case CMD_SAVE_AS:
|
|
{
|
|
SaveClipboardToFile();
|
|
break;
|
|
}
|
|
|
|
case CMD_EXIT:
|
|
{
|
|
PostMessageW(Globals.hMainWnd, WM_CLOSE, 0, 0);
|
|
break;
|
|
}
|
|
|
|
case CMD_DELETE:
|
|
{
|
|
if (MessageBoxRes(Globals.hMainWnd, Globals.hInstance,
|
|
STRING_DELETE_MSG, STRING_DELETE_TITLE,
|
|
MB_ICONWARNING | MB_YESNO) != IDYES)
|
|
{
|
|
break;
|
|
}
|
|
|
|
DeleteClipboardContent();
|
|
break;
|
|
}
|
|
|
|
case CMD_AUTOMATIC:
|
|
{
|
|
SetDisplayFormat(0);
|
|
break;
|
|
}
|
|
|
|
case CMD_HELP:
|
|
{
|
|
HtmlHelpW(Globals.hMainWnd, L"clipbrd.chm", 0, 0);
|
|
break;
|
|
}
|
|
|
|
case CMD_ABOUT:
|
|
{
|
|
HICON hIcon;
|
|
WCHAR szTitle[MAX_STRING_LEN];
|
|
|
|
hIcon = LoadIconW(Globals.hInstance, MAKEINTRESOURCE(CLIPBRD_ICON));
|
|
LoadStringW(Globals.hInstance, STRING_CLIPBOARD, szTitle, ARRAYSIZE(szTitle));
|
|
ShellAboutW(Globals.hMainWnd, szTitle, NULL, hIcon);
|
|
DeleteObject(hIcon);
|
|
break;
|
|
}
|
|
|
|
default:
|
|
{
|
|
break;
|
|
}
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
static void ClipboardPaintHandler(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
|
|
{
|
|
HDC hdc;
|
|
PAINTSTRUCT ps;
|
|
RECT rc;
|
|
|
|
if (!OpenClipboard(Globals.hMainWnd))
|
|
return;
|
|
|
|
hdc = BeginPaint(hWnd, &ps);
|
|
GetClientRect(hWnd, &rc);
|
|
|
|
switch (Globals.uDisplayFormat)
|
|
{
|
|
case CF_NONE:
|
|
{
|
|
break;
|
|
}
|
|
|
|
case CF_UNICODETEXT:
|
|
{
|
|
DrawTextFromClipboard(hdc, &rc, DT_LEFT | DT_NOPREFIX);
|
|
break;
|
|
}
|
|
|
|
case CF_BITMAP:
|
|
{
|
|
BitBltFromClipboard(hdc, rc.left, rc.top, rc.right, rc.bottom, 0, 0, SRCCOPY);
|
|
break;
|
|
}
|
|
|
|
case CF_DIB:
|
|
{
|
|
SetDIBitsToDeviceFromClipboard(CF_DIB, hdc, rc.left, rc.top, 0, 0, 0, DIB_RGB_COLORS);
|
|
break;
|
|
}
|
|
|
|
case CF_DIBV5:
|
|
{
|
|
SetDIBitsToDeviceFromClipboard(CF_DIBV5, hdc, rc.left, rc.top, 0, 0, 0, DIB_RGB_COLORS);
|
|
break;
|
|
}
|
|
|
|
case CF_METAFILEPICT:
|
|
{
|
|
PlayMetaFileFromClipboard(hdc, &rc);
|
|
break;
|
|
}
|
|
|
|
case CF_ENHMETAFILE:
|
|
{
|
|
PlayEnhMetaFileFromClipboard(hdc, &rc);
|
|
break;
|
|
}
|
|
|
|
default:
|
|
{
|
|
DrawTextFromResource(Globals.hInstance, ERROR_UNSUPPORTED_FORMAT, hdc, &rc, DT_CENTER | DT_WORDBREAK | DT_NOPREFIX);
|
|
break;
|
|
}
|
|
}
|
|
|
|
EndPaint(hWnd, &ps);
|
|
|
|
CloseClipboard();
|
|
}
|
|
|
|
static LRESULT WINAPI MainWndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
|
|
{
|
|
switch(uMsg)
|
|
{
|
|
case WM_CREATE:
|
|
{
|
|
Globals.hMenu = GetMenu(hWnd);
|
|
Globals.hWndNext = SetClipboardViewer(hWnd);
|
|
UpdateDisplayMenu();
|
|
SetDisplayFormat(0);
|
|
break;
|
|
}
|
|
|
|
case WM_CLOSE:
|
|
{
|
|
DestroyWindow(hWnd);
|
|
break;
|
|
}
|
|
|
|
case WM_DESTROY:
|
|
{
|
|
ChangeClipboardChain(hWnd, Globals.hWndNext);
|
|
PostQuitMessage(0);
|
|
break;
|
|
}
|
|
|
|
case WM_PAINT:
|
|
{
|
|
ClipboardPaintHandler(hWnd, uMsg, wParam, lParam);
|
|
break;
|
|
}
|
|
|
|
case WM_KEYDOWN:
|
|
{
|
|
HandleKeyboardScrollEvents(hWnd, uMsg, wParam, lParam);
|
|
break;
|
|
}
|
|
|
|
case WM_MOUSEWHEEL:
|
|
{
|
|
HandleMouseScrollEvents(hWnd, uMsg, wParam, lParam, &Scrollstate);
|
|
break;
|
|
}
|
|
|
|
case WM_HSCROLL:
|
|
{
|
|
HandleHorizontalScrollEvents(hWnd, uMsg, wParam, lParam, &Scrollstate);
|
|
break;
|
|
}
|
|
|
|
case WM_VSCROLL:
|
|
{
|
|
HandleVerticalScrollEvents(hWnd, uMsg, wParam, lParam, &Scrollstate);
|
|
break;
|
|
}
|
|
|
|
case WM_SIZE:
|
|
{
|
|
UpdateWindowScrollState(hWnd, Globals.hDspBmp, &Scrollstate);
|
|
|
|
if ((Globals.uDisplayFormat == CF_METAFILEPICT) ||
|
|
(Globals.uDisplayFormat == CF_ENHMETAFILE) ||
|
|
(Globals.uDisplayFormat == CF_DSPENHMETAFILE) ||
|
|
(Globals.uDisplayFormat == CF_DSPMETAFILEPICT))
|
|
{
|
|
InvalidateRect(Globals.hMainWnd, NULL, FALSE);
|
|
}
|
|
else if (!IsClipboardFormatSupported(Globals.uDisplayFormat))
|
|
{
|
|
InvalidateRect(Globals.hMainWnd, NULL, TRUE);
|
|
}
|
|
|
|
break;
|
|
}
|
|
|
|
case WM_CHANGECBCHAIN:
|
|
{
|
|
if ((HWND)wParam == Globals.hWndNext)
|
|
{
|
|
Globals.hWndNext = (HWND)lParam;
|
|
}
|
|
else if (Globals.hWndNext != NULL)
|
|
{
|
|
SendMessageW(Globals.hWndNext, uMsg, wParam, lParam);
|
|
}
|
|
|
|
break;
|
|
}
|
|
|
|
case WM_DRAWCLIPBOARD:
|
|
{
|
|
UpdateDisplayMenu();
|
|
SetDisplayFormat(0);
|
|
|
|
SendMessageW(Globals.hWndNext, uMsg, wParam, lParam);
|
|
break;
|
|
}
|
|
|
|
case WM_COMMAND:
|
|
{
|
|
if ((LOWORD(wParam) > CMD_AUTOMATIC))
|
|
{
|
|
SetDisplayFormat(LOWORD(wParam) - CMD_AUTOMATIC);
|
|
}
|
|
else
|
|
{
|
|
ClipboardCommandHandler(hWnd, uMsg, wParam, lParam);
|
|
}
|
|
break;
|
|
}
|
|
|
|
case WM_INITMENUPOPUP:
|
|
{
|
|
InitMenuPopup((HMENU)wParam, lParam);
|
|
break;
|
|
}
|
|
|
|
case WM_DROPFILES:
|
|
{
|
|
LoadClipboardFromDrop((HDROP)wParam);
|
|
break;
|
|
}
|
|
|
|
case WM_QUERYNEWPALETTE:
|
|
{
|
|
if (RealizeClipboardPalette(hWnd) != GDI_ERROR)
|
|
{
|
|
InvalidateRect(hWnd, NULL, TRUE);
|
|
UpdateWindow(hWnd);
|
|
return TRUE;
|
|
}
|
|
return FALSE;
|
|
}
|
|
|
|
case WM_PALETTECHANGED:
|
|
{
|
|
if ((HWND)wParam != hWnd)
|
|
{
|
|
if (RealizeClipboardPalette(hWnd) != GDI_ERROR)
|
|
{
|
|
InvalidateRect(hWnd, NULL, TRUE);
|
|
UpdateWindow(hWnd);
|
|
}
|
|
}
|
|
break;
|
|
}
|
|
|
|
case WM_SYSCOLORCHANGE:
|
|
{
|
|
SetDisplayFormat(Globals.uDisplayFormat);
|
|
break;
|
|
}
|
|
|
|
case WM_SETTINGCHANGE:
|
|
{
|
|
if (wParam == SPI_SETWHEELSCROLLLINES)
|
|
{
|
|
UpdateLinesToScroll();
|
|
}
|
|
break;
|
|
}
|
|
|
|
default:
|
|
{
|
|
return DefWindowProc(hWnd, uMsg, wParam, lParam);
|
|
}
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
int WINAPI wWinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPWSTR lpCmdLine, int nCmdShow)
|
|
{
|
|
MSG msg;
|
|
HACCEL hAccel;
|
|
HWND hPrevWindow;
|
|
WNDCLASSEXW wndclass;
|
|
WCHAR szBuffer[MAX_STRING_LEN];
|
|
|
|
hPrevWindow = FindWindowW(szClassName, NULL);
|
|
if (hPrevWindow)
|
|
{
|
|
BringWindowToFront(hPrevWindow);
|
|
return 0;
|
|
}
|
|
|
|
ZeroMemory(&Globals, sizeof(Globals));
|
|
Globals.hInstance = hInstance;
|
|
|
|
ZeroMemory(&wndclass, sizeof(wndclass));
|
|
wndclass.cbSize = sizeof(wndclass);
|
|
wndclass.lpfnWndProc = MainWndProc;
|
|
wndclass.hInstance = hInstance;
|
|
wndclass.hIcon = LoadIconW(hInstance, MAKEINTRESOURCEW(CLIPBRD_ICON));
|
|
wndclass.hCursor = LoadCursorW(0, IDC_ARROW);
|
|
wndclass.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1);
|
|
wndclass.lpszMenuName = MAKEINTRESOURCEW(MAIN_MENU);
|
|
wndclass.lpszClassName = szClassName;
|
|
|
|
switch (GetUserDefaultUILanguage())
|
|
{
|
|
case MAKELANGID(LANG_HEBREW, SUBLANG_DEFAULT):
|
|
SetProcessDefaultLayout(LAYOUT_RTL);
|
|
break;
|
|
|
|
default:
|
|
break;
|
|
}
|
|
|
|
if (!RegisterClassExW(&wndclass))
|
|
{
|
|
ShowLastWin32Error(NULL);
|
|
return 0;
|
|
}
|
|
|
|
LoadStringW(hInstance, STRING_CLIPBOARD, szBuffer, ARRAYSIZE(szBuffer));
|
|
Globals.hMainWnd = CreateWindowExW(WS_EX_CLIENTEDGE | WS_EX_ACCEPTFILES,
|
|
szClassName,
|
|
szBuffer,
|
|
WS_OVERLAPPEDWINDOW | WS_HSCROLL | WS_VSCROLL,
|
|
CW_USEDEFAULT,
|
|
CW_USEDEFAULT,
|
|
CW_USEDEFAULT,
|
|
CW_USEDEFAULT,
|
|
NULL,
|
|
NULL,
|
|
Globals.hInstance,
|
|
NULL);
|
|
if (!Globals.hMainWnd)
|
|
{
|
|
ShowLastWin32Error(NULL);
|
|
return 0;
|
|
}
|
|
|
|
ShowWindow(Globals.hMainWnd, nCmdShow);
|
|
UpdateWindow(Globals.hMainWnd);
|
|
|
|
hAccel = LoadAcceleratorsW(Globals.hInstance, MAKEINTRESOURCEW(ID_ACCEL));
|
|
if (!hAccel)
|
|
{
|
|
ShowLastWin32Error(Globals.hMainWnd);
|
|
}
|
|
|
|
/* If the user provided a path to a clipboard data file, try to open it */
|
|
if (lpCmdLine != NULL && *lpCmdLine)
|
|
LoadClipboardDataFromFile(lpCmdLine);
|
|
|
|
UpdateLinesToScroll();
|
|
|
|
while (GetMessageW(&msg, 0, 0, 0))
|
|
{
|
|
if (!TranslateAcceleratorW(Globals.hMainWnd, hAccel, &msg))
|
|
{
|
|
TranslateMessage(&msg);
|
|
DispatchMessageW(&msg);
|
|
}
|
|
}
|
|
|
|
if (Globals.hDspBmp)
|
|
{
|
|
DeleteObject(Globals.hDspBmp);
|
|
}
|
|
|
|
return (int)msg.wParam;
|
|
}
|