// Graphic tip.cpp
#include "stdafx.h"
#include "GraphicTip.h"
#include <Commctrl.h>
#include <AtlWin.h>
BOOL CGraphicTip::ShowTip (std::wstring FileName)
{
IPicture *iPic = NULL;
HANDLE fIn;
fIn = CreateFileW (FileName.c_str (), GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
if (fIn == INVALID_HANDLE_VALUE)
return FALSE;
// Code lifted from JigSaw
DWORD dwFileSize, dwRead;
BY_HANDLE_FILE_INFORMATION info;
GetFileInformationByHandle (fIn, &info);
if (info.nFileSizeHigh) // Too big!
return FALSE;
dwFileSize = info.nFileSizeLow;
void *pBuffer = ::CoTaskMemAlloc (dwFileSize);
if (NULL == pBuffer)
return NULL;
ReadFile (fIn, pBuffer, dwFileSize, &dwRead, NULL);
if (dwRead != dwFileSize)
return NULL;
IStream *iStream = NULL;
if (FAILED(::CreateStreamOnHGlobal ((HGLOBAL)pBuffer, FALSE, &iStream)))
return NULL;
::OleLoadPicture(iStream, 0, FALSE, IID_IPicture, (LPVOID*)&iPic);
iStream->Release ();
::CoTaskMemFree (pBuffer);
if (iPic == NULL)
return FALSE;
// Start a self destructing Tip window
CGraphicTip *pTip = new CGraphicTip;
if (!pTip)
return FALSE;
pTip->m_FileName = FileName;
pTip->m_Picture = iPic;
pTip->m_hThreadHandle = CreateThread (NULL, 0, TipThread, pTip, 0, &pTip->m_dwThreadID);
return TRUE;
}
///////////////////////////////////////////////////////////////////////////////
CGraphicTip::CGraphicTip ()
{
m_hThreadHandle = NULL;
m_dwThreadID = 0;
m_Picture = NULL;
}
CGraphicTip::~CGraphicTip ()
{
if (m_Picture)
m_Picture->Release ();
}
DWORD WINAPI CGraphicTip::TipThread ( LPVOID lpParameter )
{
if (!lpParameter)
return 0;
CGraphicTip *pTip = (CGraphicTip *) lpParameter;
TCHAR *szClassName = _T("IMCSOFT GRAPHIC TIP v1.0");
// Find any windows of our class, and ask them to die. Politely.
HWND hWndFind = FindWindow (szClassName, NULL);
if (hWndFind)
PostMessage (hWndFind, WM_USER, 0, 0);
HINSTANCE hInstance = GetModuleHandle (NULL);
WNDCLASS wc;
memset (&wc, 0, sizeof (wc));
wc.style = CS_HREDRAW | CS_VREDRAW; // | /*CS_DROPSHADOW =*/ 0x00020000;
wc.lpfnWndProc = TipProc;
wc.cbWndExtra = sizeof (CGraphicTip *);
wc.hInstance = hInstance;
wc.hCursor = ::LoadCursor (NULL, IDC_ARROW);
wc.lpszClassName = szClassName;
ATOM atomReg = RegisterClass (&wc);
// Where do we put it, and how big?
POINT pt;
SIZE szPixel, szMax;
GetCursorPos (&pt);
pTip->m_Picture->get_Width (&pTip->m_szHiMetric.cx);
pTip->m_Picture->get_Height (&pTip->m_szHiMetric.cy);
szMax.cx = szMax.cy = 200;
AtlHiMetricToPixel (&pTip->m_szHiMetric, &szPixel);
szPixel = GetCorrectedOutputSize (szPixel, szMax);
pt.y += GetSystemMetrics (SM_CXCURSOR);
pt.x += GetSystemMetrics (SM_CYCURSOR);
pTip->m_hWnd = CreateWindowEx ( WS_EX_TOOLWINDOW | WS_EX_TOPMOST | /* WS_EX_NOACTIVATE =*/0x08000000,
szClassName, NULL,
WS_POPUP | WS_VISIBLE,
pt.x, pt.y, szPixel.cx, szPixel.cy, NULL, NULL, hInstance, pTip);
if (pTip->m_hWnd)
{
ShowWindow (pTip->m_hWnd, SW_SHOW);
MSG msg;
// Simple message loop. - no need for translateaccelerator etc.
while (GetMessage(&msg, NULL, 0, 0))
DispatchMessage (&msg);
}
// Tidy up.
UnregisterClass (_T("GRAPHIC_TIP"), hInstance);
delete pTip;
return 0;
}
SIZE CGraphicTip::GetCorrectedOutputSize (const SIZE szIn, const SIZE sizeBounding)
{
SIZE szOut;
szOut = sizeBounding;
if (!szIn.cx || !szIn.cy || !szOut.cx || !szOut.cy)
return szOut;
double dIn, dOut;
dIn = (double)szIn.cx / (double)szIn.cy;
dOut = (double)szOut.cx / (double)szOut.cy;
if (dIn > dOut) // Short fat picture
szOut.cy = (int) ( (double) szOut.cx / dIn );
if (dIn < dOut) // Tall skinny picture
szOut.cx = (int) ( (double) szOut.cy * dIn );
return szOut;
}
LRESULT CALLBACK CGraphicTip::TipProc ( HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam )
{
CGraphicTip *pTip = (CGraphicTip *)GetWindowLong (hWnd, GWL_USERDATA);
switch (uMsg)
{
case WM_CREATE:
{
CREATESTRUCT *cs = (CREATESTRUCT *) lParam;
pTip = (CGraphicTip *)cs->lpCreateParams;
SetWindowLong (hWnd, GWL_USERDATA, (LONG)pTip);
SetTimer (hWnd, 1, 10000, NULL);
}
break;
case WM_ERASEBKGND:
return 0;
case WM_PAINT:
{
TRACKMOUSEEVENT tme;
tme.cbSize = sizeof (tme);
tme.dwFlags = TME_LEAVE;
tme.hwndTrack = hWnd;
// _TrackMouseEvent (&tme);
}
return pTip->OnPaint ();
case WM_TIMER:
if (wParam != 1)
break;
// Fall through to destroying the window.
case WM_USER: // Quit message.
case WM_MOUSELEAVE:
DestroyWindow (hWnd);
PostQuitMessage (0);
break;
}
return DefWindowProc (hWnd, uMsg, wParam, lParam);
}
LRESULT CGraphicTip::OnPaint ()
{
PAINTSTRUCT ps;
BeginPaint (m_hWnd, &ps);
RECT rc;
GetClientRect (m_hWnd, &rc);
// HBRUSH brOld, brInfo = GetSysColorBrush (COLOR_INFOBK);
// HPEN penOld, penInfo = CreatePen (PS_SOLID, 0, GetSysColor (COLOR_INFOTEXT));
// brOld = (HBRUSH) SelectObject (ps.hdc, brInfo);
// penOld = (HPEN) SelectObject (ps.hdc, penInfo);
// Rectangle (ps.hdc, rc.left, rc.top, rc.right, rc.bottom);
// InflateRect (&rc, -2, -2);
if (m_Picture)
{
m_Picture->Render (ps.hdc,
rc.left, rc.bottom - 1, rc.right - rc.left, rc.top - rc.bottom, // Render upside down
0,0, m_szHiMetric.cx, m_szHiMetric.cy, NULL);
}
// SelectObject (ps.hdc, brOld);
// SelectObject (ps.hdc, penOld);
EndPaint (m_hWnd, &ps);
return 0;
}