reactos/base/applications/clipbrd/clipbrd.c

608 lines
15 KiB
C
Raw Normal View History

/*
* 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;
}