The Prodigal Drone Returns

I was never one of those kids who was into RC toys. But a few of my friends were. So I got to play with my fair share of remote control cars and planes. Sure, they were interesting. I’d even go so far as to say they were fun. But they never really captured my attention. The batteries died too quickly. And on more than one occasion I witnessed an RC truck plummet to its death on a steep hill or, in one instance, get run over by a much larger, realer truck. They just weren’t my thing.

Fast-forward 25ish years. Now drones/quadcopters are all the rage. You can’t turn on the news without hearing about some nutball flying one into a restricted area or some forward-thinking company wanting to use them for delivery. Imagine my surprise when I realized I actually wanted one. And I didn’t just want one – I needed one. But why? Battery technology hasn’t improved that much since I was a kid. And I was certain controlling one was a bit more of a challenge (which side is the front?). So what was it about them? It didn’t matter. I had been bitten by the bug.

Per @padresj’s recommendation on an episode of “Know How”, I ended up purchasing an Xtreem QuadForce Video Drone from Fry’s for about $70. Padre considers this a starter model and a great tool for learning the controls. It has a crappy camera and that’s about it. No GPS, no programmability, no POV controls, etc. – none of the frills that cross over into drone territory. It’s basically a toy. But I was still excited to take my first steps.

It arrived after about a week. As soon as I got home from work, I pulled the quad out of the box and started charging the battery. After 30 LONG minutes of charging, I turned it on and took my first flight in my bedroom. I got about 4 feet off the ground, panicked, and then cut the throttle. It crashed to the floor. To say that the controls were a tad touchy would be a tad of an understatement. After a few more tries, I managed to keep the quad stable in the air for more than a few seconds at a time. My wife even got in on the action by putting socks on it, with hopes that it might serve as a tool for “putting my damn clothes away.” Yeah, right. 🙂

The battery died after about 10 minutes. So that was a little disappointing. But it was fun. And I was excited to give this thing a whirl outside. But that would have to wait. It was time for bed.

A few days later, the temperature rose a few degrees above freezing (we’re talking January in Maine) and I decided it was time to take the quad outside to see what it could do. I thought I might be able to get more comfortable with it if I didn’t have to worry about crashing it into a wall. Out we went.

I put the quad on the ground, turned it on, and almost gracefully coasted it from one end of the yard to the other. Fun. And now to bring it back. I turned to my wife, “Do you wanna give it a shot? And just bring it back to us?” “YES!” she said. So I handed her the controls and explained how they worked. The quad immediately shot straight up in the air and proceeded to fly away from us as fast as it could. “Wrong way! Wrong way!” “I can’t! You do it!” She handed the controls back to me. But it was too late. The quad was a dot in the sky. I had no idea which end was which and what I was telling it to do. It was gone. (Side note: I learned later that this particular quad will continue doing whatever it was last told to do if communications is lost with the remote. If that was straight up or forward, that’s the direction it’ll keep going until either the batteries run out or it crashes into something. My guess is the quad made it beyond our reach and I couldn’t have brought it back even if I was skilled at such things.)

For the next 30 minutes, my wife and I drove up and down our little country road looking in trees and bushes hoping to see the distinctive orange coloring of our runaway quad. One of our neighbors stopped us and asked what we were looking for. Embarrassingly, we told them. While they seemed amused, I was terrified that maybe the quad fell on their house. If they found it, now they’d know who to blame. We never found what we were looking for that day. Defeated, we came home.

My wife felt awful about the whole thing and offered to buy me a new one. I told her to forget about it. I just couldn’t justify spending another $70 on a toy. But I stared at my remote control for a few days wondering what my next step might be or if that was the end of my quadcopter journey.

Four months and a handful of monster snow storms later, the Spring thaw was in full force. Leora went off shopping with her sister and I sat in the back of the house working on another project I’ll be writing about soon. Suddenly, there’s a knock on my door. I was in the middle of soldering something and couldn’t get up right away. The knock got louder. I was almost done. Just a few more seconds. I put down the soldering iron and walked to the door. I opened it, and there on the concrete steps sat my long lost friend. I couldn’t believe it. The quad was in one piece and mostly dry.

I knew the same neighbor I saw back in January must have found it and brought it to me. He was the only one we told. I left the quad where it sat and walked to his house to thank him. According to him, the quad landed in a tree in his backyard and eventually crashed to the ground after some high winds. He said he’d been looking at it out his window for 2 weeks but couldn’t get to it because of all the snow (Thank goodness it wasn’t on his house. Close one.). I thanked him again and walked back home to take a closer look at the carnage.

It was mostly in-tact. The props were still in good shape. The battery hadn’t swollen or exploded. The only noticeable damage was two of the plastic covers that protected some of the LEDs had been lost. No great loss there. Those things had struggled to stay on even in my bedroom.

Test 1: See if the battery will hold a charge. I ran in the house and grabbed the charger. I decided to charge it outside just in case the battery wasn’t up to snuff. For thirty minutes it sat there charging without incident. I figured that was enough charging time for me to give the quad a test run.

Test 2: I plugged the battery back into the quad and flipped the power switch. The lights blinked to life. Impressive. But surely it wouldn’t fly. I grabbed the remote, synced it, and pushed the throttle. Nothing. “Hmph, that’s about right,” I thought. And then the thing sprang to life and shot up in the air. I was blown away. None of the motors had been damaged. The controllers were working. It was flying. And not just flying, but flying as well as that fateful day in January.

I considered hiding the quad under my wife’s pillow. But I instead texted her a picture. She responded with, “Did you buy a new one?” “Nope,” I said. She came home and I told her the story. We laughed about it and noted how remarkable it was that the only neighbor we told was the neighbor that found it.

I asked her, “Do you want to fly it again?”

“Ummmmm, no.”

Making Progress on the Windows Taskbar

We’ve all seen those programs that show progress on the Windows taskbar. WinRAR does it when creating or extracting RAR files. Firefox does it when downloading files. Windows Explorer does it when copying or moving files. Perhaps you’ve seen this and thought, “I wonder how I could do this in my own application.” It certainly adds polish. And as a user, being able to easily monitor a long running task while surfing the Interwebs has a lot of value. In this blog entry, I’m going to show you how to do it.

Prior to Windows 7, most applications would accomplish similar feats by manipulating window titles or system tray icons. It was kludgy. But it got the job done. Believe it or not, Windows 7 was the first version of Windows that gave us platform support for showing progress on the taskbar. It’s one of those silly little features we developers never knew we needed. After all, we thought we already had it figured out. But now that I know it’s there, I want to use it all of the time.

The key to showing taskbar progress is the ITaskbarList3 COM interface. It extends ITaskbarList and ITaskbarList2 interfaces, which are Windows 2000 and Windows XP era, respectively. As you can tell from the API docs, both ITaskbarList and ITaskbarList2 are pretty boring. It wasn’t until ITaskbarList3 showed up that things started getting interesting with the taskbar. It’s with ITaskbarList3 that we have the ability to manipulate things like overlay icons, thumbnail images, and progress, which is what we’re concerned with in this article.

(Note: If you’re a Windows developer and not experienced with COM, I strongly advise that you educate yourself on the topic. Much of the Windows platform is exposed through COM interfaces. There’s not much beyond the core Win32 API that you can do without dipping your toes into the world of COM. If you’re interested in learning more, I recommend picking up “Essential COM” by Don Box. It’s an older book (circa 1998). But it’s still the best introduction to COM and remains relevant after all of these years.)

I’m now going to demonstrate how to use ITaskbarList3 for showing progress by creating a simple wrapper class called TaskBarProgress. This is what the class declaration looks like.

class TaskBarProgress
{
    public:
 
        //! Constructor.
        TaskBarProgress(HWND hWnd) : m_hWnd(hWnd), 
            m_pTaskBarList3(NULL) {}
        //! Destructor.
        virtual ~TaskBarProgress() { _ASSERT(m_pTaskBarList3 == NULL); }
 
        //! Starts "progress mode".
        void startProgressMode();
        //! Ends "progress mode".
        void endProgressMode();
        //! Sets the current progress.
        void setProgress(ULONGLONG progressValue, ULONGLONG progressTotal);
 
    private:
 
        // We don't want the default implementations of the copy constructor 
        // and assignment operator because we have a COM pointer involved. 
        // Copying that without doing the appropriate AddRef'ing would be 
        // hazardous to our health. Let's just leave these out unless we
        // find we need them at a later date.
 
        //! Copy constructor. NOT IMPLEMENTED.
        TaskBarProgress(const TaskBarProgress &);
        //! Assignment operator. NOT IMPLEMENTED.
        const TaskBarProgress & operator=(const TaskBarProgress &);
 
        //! The window for which we're showing progress.
        HWND m_hWnd;
        //! The ITaskbarList3 implementer.
        ITaskbarList3 *m_pTaskBarList3;
};

TaskBarProgress is fairly simple. It has two member variables – m_hWnd and m_pTaskBarList3. Why do we need a window handle? When setting progress, ITaskbarList3 needs to know what window we’re setting progress on. So TaskBarProgress accepts the window handle as an argument to the constructor, which then gets stashed in m_hWnd.

The copy constructor and assignment operator are not implemented here. This is meant to keep us from shooting ourselves in the foot with COM reference count bookkeeping. For demo purposes (and probably for most practical purposes), we don’t need to support copies of this class.

The three methods startProgressMode(), endProgressMode(), and setProgress() are the interesting methods here. They do what their names suggest. When you want to begin displaying progress on the taskbar, you call startProgressMode(). As progress is made, you update the progress value by calling setProgress(). And when you’re all finished, tidy things up by calling endProgressMode().

Starting Progress

The implementation for startProgressMode() looks like so.

void TaskBarProgress::startProgressMode()
{
    if (!m_hWnd)
        return;
 
    if (!m_pTaskBarList3)
    {
        HRESULT hr = ::CoCreateInstance(CLSID_TaskbarList, NULL, 
            CLSCTX_INPROC_SERVER, IID_ITaskbarList3, (void **)&m_pTaskBarList3);
 
        if (hr != S_OK)
            return; // Not a supported platform. Nothing we can do.
    }
 
    // "Turning on" progress mode and setting the initial progress value to 0.
    m_pTaskBarList3->SetProgressState(m_hWnd, TBPF_NORMAL);
    m_pTaskBarList3->SetProgressValue(m_hWnd, 0, 100);
}

We first obtain a pointer to the ITaskbarList3 interface if we need to and verify that it was successful (this will fail on older platforms like Vista or XP). If it’s successful, we then enable the progress state with a call to ITaskbarList3::SetProgressState(). ITaskbarList3::SetProgressState() accepts two arguments – a window handle and the state flag. If you peruse the documentation for this method, you’ll find 5 different flags you can use for the state. These are described below.

TBPF_NOPROGRESS This is the normal taskbar mode. If a progress bar is present on the taskbar, setting this flag will dismiss it. You’ll notice we set this flag in our endProgressMode() method described later.
TBPF_INDETERMINATE This is what it sounds like. It means you have something going on that you want to show progress for, but you have no idea how to track a progress value for it. For example, imagine calling a third party library function that takes a long time to finish. You may not be able to receive progress notifications from it, so you have no way of knowing when it’ll be finished until it’s actually done. This is when you might use this flag.
TBPF_NORMAL Despite being called “normal”, this is actually the “in-progress” state. When you send this flag, the taskbar icon will begin showing progress.
TBPF_ERROR Turns the icon red to indicate an error has occurred.
TBPF_PAUSED Turns the icon yellow to indicate an action is needed before more progress can be made.

For this article, we’re only concerned with TBPF_NORMAL and TBPF_NOPROGRESS.

After we set the progress mode in startProgressMode(), we initialize the progress value to 0 with a call to ITaskbarList3::SetProgressValue(). This isn’t absolutely necessary, but it’s a good practice.

Updating Progress

Updating the progress value occur in our setProgress method. This method has two parameters – progressValue and progressTotal. progressValue is whatever the current progress value is and progressTotal is the maximum value the progress value can be. Both of these parameters are passed straight through to ITaskbarList3::SetProgressValue()

void TaskBarProgress::setProgress(ULONGLONG progressValue, ULONGLONG progressTotal)
{
    if (!m_pTaskBarList3 || !m_hWnd)
        return;
 
    m_pTaskBarList3->SetProgressValue(m_hWnd, progressValue, progressTotal);
}

Ending Progress Mode

Ending progress occurs in our endProgressMode() method. This method simply sets the state value to TBPF_NOPROGRESS as described above and then releases the ITaskbarList3 pointer.

void TaskBarProgress::endProgressMode()
{
    if (!m_pTaskBarList3 || !m_hWnd)
        return;
 
    m_pTaskBarList3->SetProgressState(m_hWnd, TBPF_NOPROGRESS);
    m_pTaskBarList3->Release();
    m_pTaskBarList3 = NULL;
}

Demo

And that’s all there is to it. We’ll demonstrate the use of this class with a simple console-based application (yes, consoles can have progress too!).

int _tmain(int argc, _TCHAR* argv[])
{
    CoInitialize(NULL);
 
    HWND hwnd = ::GetConsoleWindow();
    TaskBarProgress progress(hwnd);
 
    progress.startProgressMode();
    for (int i = 0; i < 20; ++i)
    {
        progress.setProgress(i, 20);
        Sleep(200);
    }
    progress.endProgressMode();
 
    CoUninitialize();
 
    return 0;
}

The first thing we do here is initialize COM with a call to CoInitialize(). You MUST do this before doing anything COM-related.

After initializing COM, we get a handle to the console window. We use that handle to construct an instance of TaskBarProgress. We then call the instance’s startProgressMode() and enter a loop that iterates 20 times. Each time through the loop, TaskBarProgress’s setProgress() method is called with the current progress value and then we sleep for 200 milliseconds. Once the the loop has finished, the TaskBarProgress’s endProgressMode() method is called.

Just before exiting, COM is uninitialized.

If you build this and run it from the console, you’ll see that the console window taskbar icon shows progress while the application is running and the icon returns to normal just before the application terminates.

Go Forth and Create Progress

The code for this article can be downloaded here. The sample was written and built using the Visual Studio 2012 Express edition. If you’re using an older platform SDK, you may need to update it in order to obtain definitions for ITaskbarList3. If you’ve included shobjidl.h and the compiler complains about missing definitions for ITaskbarList3, CLSID_TaskbarList, and/or IID_ITaskbarList3, that’s usually a good indication you need to update.

And that’s it! The ITaskbarList3 interface is pretty simple. You may not feel the need to wrap it in a class at all. That’s fine. Or you may have a better idea of how to wrap it (a scope-based progress class, perhaps?). That’s fine too. In any case, adding support for taskbar icon progress will definitely add some polish to whatever project you may be working on. Have fun with it!

-Shane