blob: e25f43ad63c39aa9faa5ab9d12889a827cf37deb [file] [log] [blame]
Constantin Kaplinsky47ed8d32004-10-08 09:43:57 +00001/* Copyright (C) 2002-2004 RealVNC Ltd. All Rights Reserved.
2 *
3 * This is free software; you can redistribute it and/or modify
4 * it under the terms of the GNU General Public License as published by
5 * the Free Software Foundation; either version 2 of the License, or
6 * (at your option) any later version.
7 *
8 * This software is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * GNU General Public License for more details.
12 *
13 * You should have received a copy of the GNU General Public License
14 * along with this software; if not, write to the Free Software
15 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
16 * USA.
17 */
18
19// Win32Util.cxx
20
21#include <rfb_win32/Win32Util.h>
22#include <rdr/Exception.h>
23#include <rdr/HexOutStream.h>
24
25
26namespace rfb {
27namespace win32 {
28
29LogicalPalette::LogicalPalette() : palette(0), numEntries(0) {
30 BYTE buf[sizeof(LOGPALETTE)+256*sizeof(PALETTEENTRY)];
31 LOGPALETTE* logpal = (LOGPALETTE*)buf;
32 logpal->palVersion = 0x300;
33 logpal->palNumEntries = 256;
34 for (int i=0; i<256;i++) {
35 logpal->palPalEntry[i].peRed = 0;
36 logpal->palPalEntry[i].peGreen = 0;
37 logpal->palPalEntry[i].peBlue = 0;
38 logpal->palPalEntry[i].peFlags = 0;
39 }
40 palette = CreatePalette(logpal);
41 if (!palette)
42 throw rdr::SystemException("failed to CreatePalette", GetLastError());
43}
44
45LogicalPalette::~LogicalPalette() {
46 if (palette)
47 if (!DeleteObject(palette))
48 throw rdr::SystemException("del palette failed", GetLastError());
49}
50
51void LogicalPalette::setEntries(int start, int count, const Colour* cols) {
52 if (numEntries < count) {
53 ResizePalette(palette, start+count);
54 numEntries = start+count;
55 }
56 PALETTEENTRY* logpal = new PALETTEENTRY[count];
57 for (int i=0; i<count; i++) {
58 logpal[i].peRed = cols[i].r >> 8;
59 logpal[i].peGreen = cols[i].g >> 8;
60 logpal[i].peBlue = cols[i].b >> 8;
61 logpal[i].peFlags = 0;
62 }
63 UnrealizeObject(palette);
64 SetPaletteEntries(palette, start, count, logpal);
65 delete [] logpal;
66}
67
68
69static LogWriter dcLog("DeviceContext");
70
71PixelFormat DeviceContext::getPF() const {
72 return getPF(dc);
73}
74
75PixelFormat DeviceContext::getPF(HDC dc) {
76 PixelFormat format;
77 CompatibleBitmap bitmap(dc, 1, 1);
78
79 // -=- Get the bitmap format information
80 BitmapInfo bi;
81 memset(&bi, 0, sizeof(bi));
82 bi.bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
83 bi.bmiHeader.biBitCount = 0;
84
85 if (!::GetDIBits(dc, bitmap, 0, 1, NULL, (BITMAPINFO*)&bi, DIB_RGB_COLORS)) {
86 throw rdr::SystemException("unable to determine device pixel format", GetLastError());
87 }
88 if (!::GetDIBits(dc, bitmap, 0, 1, NULL, (BITMAPINFO*)&bi, DIB_RGB_COLORS)) {
89 throw rdr::SystemException("unable to determine pixel shifts/palette", GetLastError());
90 }
91
92 // -=- Munge the bitmap info here
93 switch (bi.bmiHeader.biBitCount) {
94 case 1:
95 case 4:
96 bi.bmiHeader.biBitCount = 8;
97 break;
98 case 24:
99 bi.bmiHeader.biBitCount = 32;
100 break;
101 }
102 bi.bmiHeader.biPlanes = 1;
103
104 format.trueColour = bi.bmiHeader.biBitCount > 8;
105 format.bigEndian = 0;
106 format.bpp = format.depth = bi.bmiHeader.biBitCount;
107
108 if (format.trueColour) {
109 DWORD rMask=0, gMask=0, bMask=0;
110
111 // Which true colour format is the DIB section using?
112 switch (bi.bmiHeader.biCompression) {
113 case BI_RGB:
114 // Default RGB layout
115 switch (bi.bmiHeader.biBitCount) {
116 case 16:
117 // RGB 555 - High Colour
118 dcLog.info("16-bit High Colour");
119 rMask = 0x7c00;
120 bMask = 0x001f;
121 gMask = 0x03e0;
122 format.depth = 15;
123 break;
124 case 24:
125 case 32:
126 // RGB 888 - True Colour
127 dcLog.info("24/32-bit High Colour");
128 rMask = 0xff0000;
129 gMask = 0x00ff00;
130 bMask = 0x0000ff;
131 format.depth = 24;
132 break;
133 default:
134 dcLog.error("bits per pixel %u not supported", bi.bmiHeader.biBitCount);
135 throw rdr::Exception("unknown bits per pixel specified");
136 };
137 break;
138 case BI_BITFIELDS:
139 // Custom RGB layout
140 rMask = bi.mask.red;
141 gMask = bi.mask.green;
142 bMask = bi.mask.blue;
143 dcLog.info("BitFields format: %lu, (%lx, %lx, %lx)",
144 bi.bmiHeader.biBitCount, rMask, gMask, bMask);
145 if (format.bpp == 32)
146 format.depth = 24; // ...probably
147 break;
148 };
149
150 // Convert the data we just retrieved
151 initMaxAndShift(rMask, &format.redMax, &format.redShift);
152 initMaxAndShift(gMask, &format.greenMax, &format.greenShift);
153 initMaxAndShift(bMask, &format.blueMax, &format.blueShift);
154 }
155
156 return format;
157}
158
159
160WindowDC::WindowDC(HWND wnd) : hwnd(wnd) {
161 dc = GetDC(wnd);
162 if (!dc)
163 throw rdr::SystemException("GetDC failed", GetLastError());
164}
165WindowDC::~WindowDC() {
166 if (dc)
167 ReleaseDC(hwnd, dc);
168}
169
170
171CompatibleDC::CompatibleDC(HDC existing) {
172 dc = CreateCompatibleDC(existing);
173 if (!dc)
174 throw rdr::SystemException("CreateCompatibleDC failed", GetLastError());
175}
176CompatibleDC::~CompatibleDC() {
177 if (dc)
178 DeleteDC(dc);
179}
180
181
182BitmapDC::BitmapDC(HDC hdc, HBITMAP hbitmap) : CompatibleDC(hdc){
183 oldBitmap = (HBITMAP)SelectObject(dc, hbitmap);
184 if (!oldBitmap)
185 throw rdr::SystemException("SelectObject to CompatibleDC failed",
186 GetLastError());
187}
188BitmapDC::~BitmapDC() {
189 SelectObject(dc, oldBitmap);
190}
191
192
193CompatibleBitmap::CompatibleBitmap(HDC hdc, int width, int height) {
194 hbmp = CreateCompatibleBitmap(hdc, width, height);
195 if (!hbmp)
196 throw rdr::SystemException("CreateCompatibleBitmap() failed",
197 GetLastError());
198}
199CompatibleBitmap::~CompatibleBitmap() {
200 if (hbmp) DeleteObject(hbmp);
201}
202
203
204PaletteSelector::PaletteSelector(HDC dc, HPALETTE pal) : device(dc), redrawRequired(false) {
205 oldPal = SelectPalette(dc, pal, FALSE);
206 redrawRequired = RealizePalette(dc) > 0;
207}
208PaletteSelector::~PaletteSelector() {
209 if (oldPal) SelectPalette(device, oldPal, TRUE);
210}
211
212
213IconInfo::IconInfo(HICON icon) {
214 if (!GetIconInfo(icon, this))
215 throw rdr::SystemException("GetIconInfo() failed", GetLastError());
216}
217IconInfo::~IconInfo() {
218 if (hbmColor)
219 DeleteObject(hbmColor);
220 if (hbmMask)
221 DeleteObject(hbmMask);
222}
223
224
225ModuleFileName::ModuleFileName(HMODULE module) : TCharArray(MAX_PATH) {
226 if (!module) module = GetModuleHandle(0);
227 if (!GetModuleFileName(module, buf, MAX_PATH))
228 buf[0] = 0;
229}
230
231
232FileVersionInfo::FileVersionInfo(const TCHAR* filename) {
233 // Get executable name
234 ModuleFileName exeName;
235 if (!filename) filename = exeName.buf;
236
237 // Get version info size
238 DWORD handle;
239 int size = GetFileVersionInfoSize((TCHAR*)filename, &handle);
240 if (!size)
241 throw rdr::SystemException("GetVersionInfoSize failed", GetLastError());
242
243 // Get version info
244 buf = new TCHAR[size];
245 if (!GetFileVersionInfo((TCHAR*)filename, handle, size, buf))
246 throw rdr::SystemException("GetVersionInfo failed", GetLastError());
247}
248
249const TCHAR* FileVersionInfo::getVerString(const TCHAR* name, DWORD langId) {
250 char langIdBuf[sizeof(langId)];
251 for (int i=sizeof(langIdBuf)-1; i>=0; i--) {
252 langIdBuf[i] = langId & 0xff;
253 langId = langId >> 8;
254 }
255
256 TCharArray langIdStr = rdr::HexOutStream::binToHexStr(langIdBuf, sizeof(langId));
257 TCharArray infoName(_tcslen(_T("StringFileInfo")) + 4 + _tcslen(name) + _tcslen(langIdStr.buf));
258 _stprintf(infoName.buf, _T("\\StringFileInfo\\%s\\%s"), langIdStr.buf, name);
259
260 // Locate the required version string within the version info
261 TCHAR* buffer = 0;
262 UINT length = 0;
263 if (!VerQueryValue(buf, infoName.buf, (void**)&buffer, &length)) {
264 printf("unable to find %s version string", CStr(infoName.buf));
265 throw rdr::Exception("VerQueryValue failed");
266 }
267 return buffer;
268}
269
270
271bool splitPath(const TCHAR* path, TCHAR** dir, TCHAR** file) {
272 return tstrSplit(path, '\\', dir, file, true);
273}
274
275
276static LogWriter dfbLog("DynamicFn");
277
278DynamicFnBase::DynamicFnBase(const TCHAR* dllName, const char* fnName) : dllHandle(0), fnPtr(0) {
279 dllHandle = LoadLibrary(dllName);
280 if (!dllHandle) {
281 dfbLog.info("DLL %s not found (%d)", (const char*)CStr(dllName), GetLastError());
282 return;
283 }
284 fnPtr = GetProcAddress(dllHandle, fnName);
285 if (!fnPtr)
286 dfbLog.info("proc %s not found in %s (%d)", fnName, (const char*)CStr(dllName), GetLastError());
287}
288
289DynamicFnBase::~DynamicFnBase() {
290 if (dllHandle)
291 FreeLibrary(dllHandle);
292}
293
294
295static LogWriter miLog("MonitorInfo");
296
297MonitorInfo::MonitorInfo(HWND window) {
298#if (WINVER >= 0x0500)
299 typedef HMONITOR (WINAPI *_MonitorFromWindow_proto)(HWND,DWORD);
300 rfb::win32::DynamicFn<_MonitorFromWindow_proto> _MonitorFromWindow(_T("user32.dll"), "MonitorFromWindow");
301 typedef BOOL (WINAPI *_GetMonitorInfo_proto)(HMONITOR,LPMONITORINFO);
302 rfb::win32::DynamicFn<_GetMonitorInfo_proto> _GetMonitorInfo(_T("user32.dll"), "GetMonitorInfoA");
303
304 // Can we dynamically link to the monitor functions?
305 if (_MonitorFromWindow.isValid()) {
306 if (_GetMonitorInfo.isValid()) {
307 HMONITOR monitor = (*_MonitorFromWindow)(window, MONITOR_DEFAULTTONEAREST);
308 miLog.debug("monitor=%lx", monitor);
309 if (monitor) {
310 memset(this, 0, sizeof(MONITORINFOEXA));
311 cbSize = sizeof(MONITORINFOEXA);
312 if ((*_GetMonitorInfo)(monitor, this)) {
313 miLog.debug("monitor is %d,%d-%d,%d", rcMonitor.left, rcMonitor.top, rcMonitor.right, rcMonitor.bottom);
314 miLog.debug("work area is %d,%d-%d,%d", rcWork.left, rcWork.top, rcWork.right, rcWork.bottom);
315 miLog.debug("device is \"%s\"", szDevice);
316 return;
317 }
318 miLog.error("failed to get monitor info: %ld", GetLastError());
319 }
320 } else {
321 miLog.debug("GetMonitorInfo not found");
322 }
323 } else {
324 miLog.debug("MonitorFromWindow not found");
325 }
326#else
327#pragma message ("not building in GetMonitorInfo")
328 cbSize = sizeof(MonitorInfo);
329 szDevice[0] = 0;
330#endif
331
332 // Legacy fallbacks - just return the desktop settings
333 miLog.debug("using legacy fall-backs");
334 HWND desktop = GetDesktopWindow();
335 GetWindowRect(desktop, &rcMonitor);
336 SystemParametersInfo(SPI_GETWORKAREA, 0, &rcWork, 0);
337 dwFlags = 0;
338}
339
340
341#if (WINVER >= 0x0500)
342
343struct moveToMonitorData {
344 HWND window;
345 const char* monitorName;
346};
347
348typedef BOOL (WINAPI *_GetMonitorInfo_proto)(HMONITOR,LPMONITORINFO);
349static rfb::win32::DynamicFn<_GetMonitorInfo_proto> _GetMonitorInfo(_T("user32.dll"), "GetMonitorInfoA");
350
351static BOOL CALLBACK moveToMonitorEnumProc(HMONITOR monitor,
352 HDC dc,
353 LPRECT pos,
354 LPARAM d) {
355 moveToMonitorData* data = (moveToMonitorData*)d;
356 MONITORINFOEXA info;
357 memset(&info, 0, sizeof(info));
358 info.cbSize = sizeof(info);
359
360 if ((*_GetMonitorInfo)(monitor, &info)) {
361 if (stricmp(data->monitorName, info.szDevice) == 0) {
362 SetWindowPos(data->window, 0,
363 info.rcMonitor.left, info.rcMonitor.top,
364 info.rcMonitor.right, info.rcMonitor.bottom,
365 SWP_NOZORDER | SWP_NOSIZE | SWP_NOACTIVATE | SWP_NOOWNERZORDER);
366 return FALSE;
367 }
368 }
369
370 return TRUE;
371}
372
373#endif
374
375void moveToMonitor(HWND handle, const char* device) {
376 miLog.debug("moveToMonitor %s", device);
377
378#if (WINVER >= 0x500)
379 typedef BOOL (WINAPI *_EnumDisplayMonitors_proto)(HDC, LPCRECT, MONITORENUMPROC, LPARAM);
380 rfb::win32::DynamicFn<_EnumDisplayMonitors_proto> _EnumDisplayMonitors(_T("user32.dll"), "EnumDisplayMonitors");
381 if (!_EnumDisplayMonitors.isValid()) {
382 miLog.debug("EnumDisplayMonitors not found");
383 return;
384 }
385
386 moveToMonitorData data;
387 data.window = handle;
388 data.monitorName = device;
389
390 (*_EnumDisplayMonitors)(0, 0, &moveToMonitorEnumProc, (LPARAM)&data);
391#endif
392}
393
394
395void centerWindow(HWND handle, HWND parent, bool clipToParent) {
396 RECT r;
397 if (parent && IsWindowVisible(parent)) {
398 if (!GetWindowRect(parent, &r)) return;
399 } else {
400 MonitorInfo mi(handle);
401 r=mi.rcWork;
402 }
403 centerWindow(handle, r, clipToParent);
404}
405
406void centerWindow(HWND handle, const RECT& r, bool clipToRect) {
407 RECT wr;
408 if (!GetWindowRect(handle, &wr)) return;
409 int w = wr.right-wr.left;
410 int h = wr.bottom-wr.top;
411 if (clipToRect) {
412 w = min(r.right-r.left, w);
413 h = min(r.bottom-r.top, h);
414 }
415 int x = (r.left + r.right - w)/2;
416 int y = (r.top + r.bottom - h)/2;
417 UINT flags = SWP_NOACTIVATE | SWP_NOOWNERZORDER | SWP_NOZORDER | (clipToRect ? 0 : SWP_NOSIZE);
418 SetWindowPos(handle, 0, x, y, w, h, flags);
419}
420
421
422int MsgBox(HWND parent, const TCHAR* msg, UINT flags) {
423 const TCHAR* msgType = 0;
424 UINT tflags = flags & 0x70;
425 if (tflags == MB_ICONHAND)
426 msgType = _T("Error");
427 else if (tflags == MB_ICONQUESTION)
428 msgType = _T("Question");
429 else if (tflags == MB_ICONEXCLAMATION)
430 msgType = _T("Warning");
431 else if (tflags == MB_ICONASTERISK)
432 msgType = _T("Information");
433 flags |= MB_TOPMOST | MB_SETFOREGROUND;
434 int len = _tcslen(AppName.buf) + 1;
435 if (msgType) len += _tcslen(msgType) + 3;
436 TCharArray title = new TCHAR[len];
437 _tcscpy(title.buf, AppName.buf);
438 if (msgType) {
439 _tcscat(title.buf, _T(" : "));
440 _tcscat(title.buf, msgType);
441 }
442 return MessageBox(parent, msg, title.buf, flags);
443}
444
445
446};
447};