diff options
Diffstat (limited to 'rfb_win32/Win32Util.cxx')
-rw-r--r-- | rfb_win32/Win32Util.cxx | 447 |
1 files changed, 447 insertions, 0 deletions
diff --git a/rfb_win32/Win32Util.cxx b/rfb_win32/Win32Util.cxx new file mode 100644 index 00000000..e25f43ad --- /dev/null +++ b/rfb_win32/Win32Util.cxx @@ -0,0 +1,447 @@ +/* Copyright (C) 2002-2004 RealVNC Ltd. All Rights Reserved. + * + * This is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This software is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this software; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, + * USA. + */ + +// Win32Util.cxx + +#include <rfb_win32/Win32Util.h> +#include <rdr/Exception.h> +#include <rdr/HexOutStream.h> + + +namespace rfb { +namespace win32 { + +LogicalPalette::LogicalPalette() : palette(0), numEntries(0) { + BYTE buf[sizeof(LOGPALETTE)+256*sizeof(PALETTEENTRY)]; + LOGPALETTE* logpal = (LOGPALETTE*)buf; + logpal->palVersion = 0x300; + logpal->palNumEntries = 256; + for (int i=0; i<256;i++) { + logpal->palPalEntry[i].peRed = 0; + logpal->palPalEntry[i].peGreen = 0; + logpal->palPalEntry[i].peBlue = 0; + logpal->palPalEntry[i].peFlags = 0; + } + palette = CreatePalette(logpal); + if (!palette) + throw rdr::SystemException("failed to CreatePalette", GetLastError()); +} + +LogicalPalette::~LogicalPalette() { + if (palette) + if (!DeleteObject(palette)) + throw rdr::SystemException("del palette failed", GetLastError()); +} + +void LogicalPalette::setEntries(int start, int count, const Colour* cols) { + if (numEntries < count) { + ResizePalette(palette, start+count); + numEntries = start+count; + } + PALETTEENTRY* logpal = new PALETTEENTRY[count]; + for (int i=0; i<count; i++) { + logpal[i].peRed = cols[i].r >> 8; + logpal[i].peGreen = cols[i].g >> 8; + logpal[i].peBlue = cols[i].b >> 8; + logpal[i].peFlags = 0; + } + UnrealizeObject(palette); + SetPaletteEntries(palette, start, count, logpal); + delete [] logpal; +} + + +static LogWriter dcLog("DeviceContext"); + +PixelFormat DeviceContext::getPF() const { + return getPF(dc); +} + +PixelFormat DeviceContext::getPF(HDC dc) { + PixelFormat format; + CompatibleBitmap bitmap(dc, 1, 1); + + // -=- Get the bitmap format information + BitmapInfo bi; + memset(&bi, 0, sizeof(bi)); + bi.bmiHeader.biSize = sizeof(BITMAPINFOHEADER); + bi.bmiHeader.biBitCount = 0; + + if (!::GetDIBits(dc, bitmap, 0, 1, NULL, (BITMAPINFO*)&bi, DIB_RGB_COLORS)) { + throw rdr::SystemException("unable to determine device pixel format", GetLastError()); + } + if (!::GetDIBits(dc, bitmap, 0, 1, NULL, (BITMAPINFO*)&bi, DIB_RGB_COLORS)) { + throw rdr::SystemException("unable to determine pixel shifts/palette", GetLastError()); + } + + // -=- Munge the bitmap info here + switch (bi.bmiHeader.biBitCount) { + case 1: + case 4: + bi.bmiHeader.biBitCount = 8; + break; + case 24: + bi.bmiHeader.biBitCount = 32; + break; + } + bi.bmiHeader.biPlanes = 1; + + format.trueColour = bi.bmiHeader.biBitCount > 8; + format.bigEndian = 0; + format.bpp = format.depth = bi.bmiHeader.biBitCount; + + if (format.trueColour) { + DWORD rMask=0, gMask=0, bMask=0; + + // Which true colour format is the DIB section using? + switch (bi.bmiHeader.biCompression) { + case BI_RGB: + // Default RGB layout + switch (bi.bmiHeader.biBitCount) { + case 16: + // RGB 555 - High Colour + dcLog.info("16-bit High Colour"); + rMask = 0x7c00; + bMask = 0x001f; + gMask = 0x03e0; + format.depth = 15; + break; + case 24: + case 32: + // RGB 888 - True Colour + dcLog.info("24/32-bit High Colour"); + rMask = 0xff0000; + gMask = 0x00ff00; + bMask = 0x0000ff; + format.depth = 24; + break; + default: + dcLog.error("bits per pixel %u not supported", bi.bmiHeader.biBitCount); + throw rdr::Exception("unknown bits per pixel specified"); + }; + break; + case BI_BITFIELDS: + // Custom RGB layout + rMask = bi.mask.red; + gMask = bi.mask.green; + bMask = bi.mask.blue; + dcLog.info("BitFields format: %lu, (%lx, %lx, %lx)", + bi.bmiHeader.biBitCount, rMask, gMask, bMask); + if (format.bpp == 32) + format.depth = 24; // ...probably + break; + }; + + // Convert the data we just retrieved + initMaxAndShift(rMask, &format.redMax, &format.redShift); + initMaxAndShift(gMask, &format.greenMax, &format.greenShift); + initMaxAndShift(bMask, &format.blueMax, &format.blueShift); + } + + return format; +} + + +WindowDC::WindowDC(HWND wnd) : hwnd(wnd) { + dc = GetDC(wnd); + if (!dc) + throw rdr::SystemException("GetDC failed", GetLastError()); +} +WindowDC::~WindowDC() { + if (dc) + ReleaseDC(hwnd, dc); +} + + +CompatibleDC::CompatibleDC(HDC existing) { + dc = CreateCompatibleDC(existing); + if (!dc) + throw rdr::SystemException("CreateCompatibleDC failed", GetLastError()); +} +CompatibleDC::~CompatibleDC() { + if (dc) + DeleteDC(dc); +} + + +BitmapDC::BitmapDC(HDC hdc, HBITMAP hbitmap) : CompatibleDC(hdc){ + oldBitmap = (HBITMAP)SelectObject(dc, hbitmap); + if (!oldBitmap) + throw rdr::SystemException("SelectObject to CompatibleDC failed", + GetLastError()); +} +BitmapDC::~BitmapDC() { + SelectObject(dc, oldBitmap); +} + + +CompatibleBitmap::CompatibleBitmap(HDC hdc, int width, int height) { + hbmp = CreateCompatibleBitmap(hdc, width, height); + if (!hbmp) + throw rdr::SystemException("CreateCompatibleBitmap() failed", + GetLastError()); +} +CompatibleBitmap::~CompatibleBitmap() { + if (hbmp) DeleteObject(hbmp); +} + + +PaletteSelector::PaletteSelector(HDC dc, HPALETTE pal) : device(dc), redrawRequired(false) { + oldPal = SelectPalette(dc, pal, FALSE); + redrawRequired = RealizePalette(dc) > 0; +} +PaletteSelector::~PaletteSelector() { + if (oldPal) SelectPalette(device, oldPal, TRUE); +} + + +IconInfo::IconInfo(HICON icon) { + if (!GetIconInfo(icon, this)) + throw rdr::SystemException("GetIconInfo() failed", GetLastError()); +} +IconInfo::~IconInfo() { + if (hbmColor) + DeleteObject(hbmColor); + if (hbmMask) + DeleteObject(hbmMask); +} + + +ModuleFileName::ModuleFileName(HMODULE module) : TCharArray(MAX_PATH) { + if (!module) module = GetModuleHandle(0); + if (!GetModuleFileName(module, buf, MAX_PATH)) + buf[0] = 0; +} + + +FileVersionInfo::FileVersionInfo(const TCHAR* filename) { + // Get executable name + ModuleFileName exeName; + if (!filename) filename = exeName.buf; + + // Get version info size + DWORD handle; + int size = GetFileVersionInfoSize((TCHAR*)filename, &handle); + if (!size) + throw rdr::SystemException("GetVersionInfoSize failed", GetLastError()); + + // Get version info + buf = new TCHAR[size]; + if (!GetFileVersionInfo((TCHAR*)filename, handle, size, buf)) + throw rdr::SystemException("GetVersionInfo failed", GetLastError()); +} + +const TCHAR* FileVersionInfo::getVerString(const TCHAR* name, DWORD langId) { + char langIdBuf[sizeof(langId)]; + for (int i=sizeof(langIdBuf)-1; i>=0; i--) { + langIdBuf[i] = langId & 0xff; + langId = langId >> 8; + } + + TCharArray langIdStr = rdr::HexOutStream::binToHexStr(langIdBuf, sizeof(langId)); + TCharArray infoName(_tcslen(_T("StringFileInfo")) + 4 + _tcslen(name) + _tcslen(langIdStr.buf)); + _stprintf(infoName.buf, _T("\\StringFileInfo\\%s\\%s"), langIdStr.buf, name); + + // Locate the required version string within the version info + TCHAR* buffer = 0; + UINT length = 0; + if (!VerQueryValue(buf, infoName.buf, (void**)&buffer, &length)) { + printf("unable to find %s version string", CStr(infoName.buf)); + throw rdr::Exception("VerQueryValue failed"); + } + return buffer; +} + + +bool splitPath(const TCHAR* path, TCHAR** dir, TCHAR** file) { + return tstrSplit(path, '\\', dir, file, true); +} + + +static LogWriter dfbLog("DynamicFn"); + +DynamicFnBase::DynamicFnBase(const TCHAR* dllName, const char* fnName) : dllHandle(0), fnPtr(0) { + dllHandle = LoadLibrary(dllName); + if (!dllHandle) { + dfbLog.info("DLL %s not found (%d)", (const char*)CStr(dllName), GetLastError()); + return; + } + fnPtr = GetProcAddress(dllHandle, fnName); + if (!fnPtr) + dfbLog.info("proc %s not found in %s (%d)", fnName, (const char*)CStr(dllName), GetLastError()); +} + +DynamicFnBase::~DynamicFnBase() { + if (dllHandle) + FreeLibrary(dllHandle); +} + + +static LogWriter miLog("MonitorInfo"); + +MonitorInfo::MonitorInfo(HWND window) { +#if (WINVER >= 0x0500) + typedef HMONITOR (WINAPI *_MonitorFromWindow_proto)(HWND,DWORD); + rfb::win32::DynamicFn<_MonitorFromWindow_proto> _MonitorFromWindow(_T("user32.dll"), "MonitorFromWindow"); + typedef BOOL (WINAPI *_GetMonitorInfo_proto)(HMONITOR,LPMONITORINFO); + rfb::win32::DynamicFn<_GetMonitorInfo_proto> _GetMonitorInfo(_T("user32.dll"), "GetMonitorInfoA"); + + // Can we dynamically link to the monitor functions? + if (_MonitorFromWindow.isValid()) { + if (_GetMonitorInfo.isValid()) { + HMONITOR monitor = (*_MonitorFromWindow)(window, MONITOR_DEFAULTTONEAREST); + miLog.debug("monitor=%lx", monitor); + if (monitor) { + memset(this, 0, sizeof(MONITORINFOEXA)); + cbSize = sizeof(MONITORINFOEXA); + if ((*_GetMonitorInfo)(monitor, this)) { + miLog.debug("monitor is %d,%d-%d,%d", rcMonitor.left, rcMonitor.top, rcMonitor.right, rcMonitor.bottom); + miLog.debug("work area is %d,%d-%d,%d", rcWork.left, rcWork.top, rcWork.right, rcWork.bottom); + miLog.debug("device is \"%s\"", szDevice); + return; + } + miLog.error("failed to get monitor info: %ld", GetLastError()); + } + } else { + miLog.debug("GetMonitorInfo not found"); + } + } else { + miLog.debug("MonitorFromWindow not found"); + } +#else +#pragma message ("not building in GetMonitorInfo") + cbSize = sizeof(MonitorInfo); + szDevice[0] = 0; +#endif + + // Legacy fallbacks - just return the desktop settings + miLog.debug("using legacy fall-backs"); + HWND desktop = GetDesktopWindow(); + GetWindowRect(desktop, &rcMonitor); + SystemParametersInfo(SPI_GETWORKAREA, 0, &rcWork, 0); + dwFlags = 0; +} + + +#if (WINVER >= 0x0500) + +struct moveToMonitorData { + HWND window; + const char* monitorName; +}; + +typedef BOOL (WINAPI *_GetMonitorInfo_proto)(HMONITOR,LPMONITORINFO); +static rfb::win32::DynamicFn<_GetMonitorInfo_proto> _GetMonitorInfo(_T("user32.dll"), "GetMonitorInfoA"); + +static BOOL CALLBACK moveToMonitorEnumProc(HMONITOR monitor, + HDC dc, + LPRECT pos, + LPARAM d) { + moveToMonitorData* data = (moveToMonitorData*)d; + MONITORINFOEXA info; + memset(&info, 0, sizeof(info)); + info.cbSize = sizeof(info); + + if ((*_GetMonitorInfo)(monitor, &info)) { + if (stricmp(data->monitorName, info.szDevice) == 0) { + SetWindowPos(data->window, 0, + info.rcMonitor.left, info.rcMonitor.top, + info.rcMonitor.right, info.rcMonitor.bottom, + SWP_NOZORDER | SWP_NOSIZE | SWP_NOACTIVATE | SWP_NOOWNERZORDER); + return FALSE; + } + } + + return TRUE; +} + +#endif + +void moveToMonitor(HWND handle, const char* device) { + miLog.debug("moveToMonitor %s", device); + +#if (WINVER >= 0x500) + typedef BOOL (WINAPI *_EnumDisplayMonitors_proto)(HDC, LPCRECT, MONITORENUMPROC, LPARAM); + rfb::win32::DynamicFn<_EnumDisplayMonitors_proto> _EnumDisplayMonitors(_T("user32.dll"), "EnumDisplayMonitors"); + if (!_EnumDisplayMonitors.isValid()) { + miLog.debug("EnumDisplayMonitors not found"); + return; + } + + moveToMonitorData data; + data.window = handle; + data.monitorName = device; + + (*_EnumDisplayMonitors)(0, 0, &moveToMonitorEnumProc, (LPARAM)&data); +#endif +} + + +void centerWindow(HWND handle, HWND parent, bool clipToParent) { + RECT r; + if (parent && IsWindowVisible(parent)) { + if (!GetWindowRect(parent, &r)) return; + } else { + MonitorInfo mi(handle); + r=mi.rcWork; + } + centerWindow(handle, r, clipToParent); +} + +void centerWindow(HWND handle, const RECT& r, bool clipToRect) { + RECT wr; + if (!GetWindowRect(handle, &wr)) return; + int w = wr.right-wr.left; + int h = wr.bottom-wr.top; + if (clipToRect) { + w = min(r.right-r.left, w); + h = min(r.bottom-r.top, h); + } + int x = (r.left + r.right - w)/2; + int y = (r.top + r.bottom - h)/2; + UINT flags = SWP_NOACTIVATE | SWP_NOOWNERZORDER | SWP_NOZORDER | (clipToRect ? 0 : SWP_NOSIZE); + SetWindowPos(handle, 0, x, y, w, h, flags); +} + + +int MsgBox(HWND parent, const TCHAR* msg, UINT flags) { + const TCHAR* msgType = 0; + UINT tflags = flags & 0x70; + if (tflags == MB_ICONHAND) + msgType = _T("Error"); + else if (tflags == MB_ICONQUESTION) + msgType = _T("Question"); + else if (tflags == MB_ICONEXCLAMATION) + msgType = _T("Warning"); + else if (tflags == MB_ICONASTERISK) + msgType = _T("Information"); + flags |= MB_TOPMOST | MB_SETFOREGROUND; + int len = _tcslen(AppName.buf) + 1; + if (msgType) len += _tcslen(msgType) + 3; + TCharArray title = new TCHAR[len]; + _tcscpy(title.buf, AppName.buf); + if (msgType) { + _tcscat(title.buf, _T(" : ")); + _tcscat(title.buf, msgType); + } + return MessageBox(parent, msg, title.buf, flags); +} + + +}; +}; |