vbbox.plan

It is by will alone I write this stuff.

 

VB6 - Loading an animated cursor

So you're finishing up that cool VB6 application and it hits you –; you must have an animated cursor playing in a corner of your main window, chugging along ala IE throbber while some trascendental things happen with the monthly sales data. Easy you say, I'll put it in my .RES file, load it with a few APIs, create a STATIC control and assign it the image. Instant playback! I'm so cool!

Yeah well, it's not that simple. The part about "playing" the .ANI file is simple enough. Assume m_hImage is your already loaded animated cursor and Container is the PictureBox control that hosts the STATIC control:

m_hWnd = CreateWindowEx(0, _
         "STATIC", _
         vbNullString, _
         WS_CHILD Or WS_VISIBLE Or SS_ICON Or SS_CENTERIMAGE, _
         0, 0, 32, 32, _
         Container.hWnd, 0, App.hInstance, ByVal 0&)

If (m_hWnd <> 0) Then
  Call InvalidateRect(Container.hWnd, ByVal 0&, 1)
  Call SendMessage(m_hWnd, STM_SETIMAGE, IMAGE_CURSOR, ByVal m_hImage)
End If

That will work well enough. In fact, if life were simple and you could ship the .ANI as a separate file with your application and load it from disk, all would be peachy:

m_hImage = LoadImage(0, App.Path & "\res\throbber.ani", 
     IMAGE_CURSOR, 32, 32, LR_LOADFROMFILE Or LR_COLOR)

And of course, because you want to make your life even more simple you'd use the super-duper CStaticCtl class instead of creating the control from scratch. Yay frameworks!

But life is never simple. No, you've decided that you must embed the .ANI in your resource (.res) file, and that's how it's going to be. Got a few hours? Loading the animated cursor from your .res file is a bit convoluted, but (relatively) documented on MSDN:

Dim hResource As Long
Dim dwResSize As Long
Dim hMem As Long
Dim pbCursorData As Long

hResource = FindResource(App.hInstance, "THROBBER", "ANICURSORS")
If hResource Then
  dwResSize = SizeofResource(App.hInstance, hResource)
  If dwResSize Then
      hMem = LoadResource(App.hInstance, hResource)
      If hMem Then
          pbCursorData = LockResource(hMem)
          If pbCursorData Then _
            m_hImage = CreateIconFromResource(ByVal pbCursorData, 
                       dwResSize, 0, &H30000)
      End If
  End If
End If

[If you're wondering what that magic &H30000 does, consult MSDN. This is one of two constants used by that API that are not #defined in the PSDK headers.]

Of course this will not work when your application is running in the VB debugger, because App.hInstance as everybody knows actually points to VB6.EXE. But other than that, it should work... Well, it will work only if you're aware of the quirky way Windows handles these types of resources. Apparently this is a bug, but I never did escalate it to PSS so I'm not sure.

Neither the VC++ or VB's (decidedly primitive) resource editor are able to handle animated cursors, so you need to create (or edit) your .rc file by hand in order to pull this off. Here's a sample:

/////////////////////////////////////////////////////////////
// myapp.rc
LANGUAGE 0x09,0x01	// 0x409
#pragma code_page(1252)

THROBBER ANICURSORS  DISCARDABLE  "res\\throbber.ani"
TOOLBAR  BITMAP      DISCARDABLE  "res\\toolbar.bmp"

Next, you'd run this through rc.exe to generate your resource file, wich then can be added to the VB6 project and linked to the executable during build. Pretty standard fare.

But here's the kicker – if the ANICURSORS entry is not the first resource defined in the .rc file, the code listed earlier that loads it from the resource segment will not work. Yep, that's right. Don't believe me? Transpose the two lines (or add something else above the animated cursor entry, like a string table) and watch in amazement as LoadResource fails with alacrity.

So there you have it. If you want to load an animated cursor from your executable, it better be the first thing in your .rc file. Otherwise your cool throbber will be all gray and dull.

 

 

 

 

 

 

 

 

© 2003-2004 Klaus H. Probst BLOGGER