You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

Win32Util.cxx 13KB

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