65.9K
CodeProject is changing. Read more.
Home

Image Tip - A popup thumbnail shell extension

Mar 9, 2004

3 min read

viewsIcon

93895

downloadIcon

2405

A graphical tooltip to show the contents of jpgs, bmps etc

Introduction

During my day job, I write software that makes ultrasonic scans of aircraft parts. (If you are an part aircraft manufacturer, buy our kit!). These scans are essentially large 8 bit bitmaps, with some job specific extra information. In order to quickly tell these files apart, I wanted an InfoTip shell extension that could either display description text stored in these files, or a preview image (also stored in the files).

Writing the text popup was trivial. But search as I might, I didn't find any graphical equivalent. So I got my hands dirty and wrote it!

Once I'd done that, I thought this might be quite and handy utility for image files too. Theoretically, you could adapt this to play the first 5s of a music file for mp3s etc. That is an exercise for the reader...

How it works... aka The light bulb moment.

I tried for ages to hook into the info tip creation cycle, seeing if I could integrate myself a little earlier. Eventually I gave up. At two am, I woke up with a dead simple idea. Return a blank tooltip, and use than moment to generate my own tooltipesque picture window. After having proved my idea, I went back to bed. Most of my best work is done when I'm asleep. At least, that's what I tell my colleagues when the wake me up at my desk!

The shell extension...

The shell extension itself was premade by a shell extension wizard. (See bibliography). I only really had to change the GetInfoTip function.

HRESULT CImage_Tip::GetInfoTip ( DWORD   dwFlags, LPWSTR* ppwszTip )
{
  static std::wstring  m_FileNameLast;

  // We're going to create our own tooltipesque window, 
  // but with a the CPreviewBitmap in it...
//  wchar_t  buf [512];
//  wcscpy (buf, L"CImage_Tip::GetInfoTip (). m_Filename = '");
//  wcscat (buf, m_FileName.c_str ());
//  wcscat (buf, L"' m_FileNameLast = '");
//  wcscat (buf, m_FileNameLast.c_str ());
//  wcscat (buf, L"'\n");
//  OutputDebugStringW (buf);

  // Return a blank tooltip.
  IMalloc *pMalloc;
  if ( FAILED( SHGetMalloc ( &pMalloc )))
    return E_FAIL;
  *ppwszTip = (LPWSTR) pMalloc->Alloc ( (1) * sizeof(wchar_t) );
  if ( NULL == *ppwszTip )
  {
    pMalloc->Release();
    return E_OUTOFMEMORY;
  }
  (*ppwszTip) [0] = 0;
  pMalloc->Release();

  // Make sure we haven't recently shown this item, 
  // otherwise Explorer will keep on trying...
  if (m_FileName.compare (m_FileNameLast))
    CGraphicTip::ShowTip (m_FileName);  // This is all that's needed here!
  m_FileNameLast.erase ();
  m_FileNameLast.append (m_FileName);
  
  return S_OK;
}

I had to make sure that explorer wasn't making repeat requests for the same tip, otherwise the screen ended up getting very busy. Once that was in place, I simply created a new CGraphicTip object, which made its own window, message loop, and tidying up bit.

The graphic popup window...

This is pretty much a mini app in its own right. Created with a filename as a parameter, it loads the image using IPicture, and creates a window scaled down to a maximum of 200 x 200, and shows it a little way from the cursor.

The object contains its own message loop, and window procedure. I used classic Win32, as MFC seemed like major overkill, and I've yet to play with WTL. Using Win32 windowing code felt like a bit of a nostalgia trip. Beside, all MFC / WTL would do is the same job, but more hidden.

Please forgive the lack of comments, but there are only a few routines, and I try to use very obvious function / variable names...

class CGraphicTip
{
public:
  static BOOL  ShowTip (std::wstring FileName);

protected:
  CGraphicTip ();
  ~CGraphicTip ();

  static  DWORD WINAPI TipThread ( LPVOID lpParameter );
  static  LRESULT CALLBACK TipProc ( HWND hwnd, UINT uMsg, 
    WPARAM wParam, LPARAM lParam );
  static  SIZE  GetCorrectedOutputSize (const SIZE szIn, 
    const SIZE sizeBounding);

  LRESULT  OnPaint ();

  HANDLE  m_hThreadHandle;
  DWORD  m_dwThreadID;
  
  std::wstring  m_FileName;
  IPicture      *m_Picture;
  SIZE          m_szHiMetric;
  HWND          m_hWnd;
};

Installing the extension...

If you haven't compiled it yourself, you'll need to put the dll in an obvious location, fire up a command prompt, go to the dll's directory, and type:

regsvr32 ImageTip.dll"
to install, and
regsvr32 /u ImageTip.dll"
to uninstall.

Things to do...

  • An installation program.
  • A way of changing maximum tip size, and duration at runtime.
  • A way of changing which file types are "tipped" at runtime.
  • Make the tip appear above / to the left when necessary.
  • An uninstallation program!
  • Bibliography

    The following codeproject articles made my life veeeeery easy:

    Context Menu Shell Extension AppWizard by Maxime Labelle.

    which seemed heavily based on...

    The Complete Idiot's Guide to Writing Shell Extensions - Part III by Michael Dunn. I cannot recommend his shell extension series highly enough.

    History

    v1.0

    Uploaded to Code Project. The software is perfect already. Honest. Would these eyes lie?