summaryrefslogtreecommitdiffstats
path: root/rfb_win32/Win32Util.cxx
diff options
context:
space:
mode:
Diffstat (limited to 'rfb_win32/Win32Util.cxx')
-rw-r--r--rfb_win32/Win32Util.cxx447
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);
+}
+
+
+};
+};