I Am Not Charles


Your clipboard isn’t broken, just confused

Posted in the Kitchen by Joe on July 4, 2008
Tags: , ,

This is kind of trivial, but it’s good to have it documented somewhere.

If you ever have to work with the Windows clipboard API directly (and it’s not too bad, as Windows API’s go) this might save you a lot of time: don’t try and step through any clipboard-related code in the debugger.

I was trying to figure out why pasting an image into my app didn’t work, so obviously the first thing to check is that the data is actually being retrieved from the clipboard correctly. I suspected it wasn’t being saved in the format I thought it was.

BOOL clipboardOpen = ::OpenClipboard(NULL);
if (clipboardOpen) {
    qDebug() << "Clipboard open";
} else {
    qDebug() << "Couldn't open clipboard: error" << ::GetLastError();
    return;
}

UINT format = 0;
while ((format = ::EnumClipboardFormats(format) != 0) {
    qDebug() << "Clipboard contains format" << format;
}

qDebug() << "Last EnumClipboardFormat status was" << ::GetLastError();
::CloseClipboard();

MSDN is pretty clear on how these two functions work: OpenClipboard returns true if the clipboard’s open, and EnumClipboardFormats returns 0 when there’s an error (in which case GetLastError returns the error code) or if it’s out of formats (in which case GetLastError returns 0, SUCCESS).

Since I was too lazy to actually hook up the Qt debug logger I was just stepping through this in the Visual Studio debugger to examine the results. And the results were basically:

Clipboard open
Last EnumClipboardFormat status was 1418

Since my app is emphatically not multithreaded, I was pretty baffled about how “Clipboard open” could be immediately followed by 1418: ERROR_CLIPBOARD_NOT_OPEN. I thought my paste problem was because my clipboard was seriously broken (on any OS but Windows I’d have thought something that fundamental was impossible, but on Windows I never assume anything). Took me ages to realize that it worked fine if it wasn’t in the debugger.

The problem, I think, is that when you pass NULL to OpenClipboard it associates the clipboard with the current process, and when you’re stepping through in the debugger it’s switching back and forth between the application and Visual Studio. Somehow the system is getting confused about which process has the clipboard open. This example seemed to work if you pass an HWND to associate it with a specific window instead of a process, but I wouldn’t want to place any bets that more complicated code would keep working. On Windows I never assume anything.

Joel gives bad advice: details at 11:00

Posted in the Living Room by Joe on July 2, 2008
Tags:

Am I blind, or does Joel on Software not allow comments any more? (Or did it ever?) Well, I guess I’ll respond to his latest article on disabling unusable menu items right here, even though that means he’ll never see it.

Don’t do this… Instead, leave the menu item enabled. If there’s some reason you can’t complete the action, the menu item can display a message telling the user why.

That would be incredibly annoying – I’d be constantly clicking on items I expect to work and getting a popup saying, “Sorry.” In an app I use often, I use the menus mostly by feel, so I’m not going to notice that now there’s a message saying, “Disabled because the moon is in th’e fourth quarter and you haven’t paid your phone bill.” Or if I do it’ll be in the instant before my finger clicks the button, so now I’ll just have time to realize I screwed up before it pops up the Box of Aggravation.

A better thing to do would be to disable the option, so if I click on it nothing will happen instead of the app yelling at me, and have feedback on why it’s disabled.

I’m a greasy little monkey

Posted in the Workshop by Joe on July 2, 2008
Tags: , ,

Wow, work’s really been kicking my ass lately. I’ve been meaning to update this blog for ages, but I’ve had no time. Finally got the day off and spent an hour or so learning to use Javascript and Greasemonkey. While we’re waiting for something more substantial, here’s my first script. You might even find it useful:

// ==UserScript==
// @name           Include Linked Images
// @namespace      ca.notcharles.greasemonkey
// @description    Add linked images to the end of a webpage.
// @include        http://www.wizards.com/*&pf=true
// ==/UserScript==

/*
Copyright (c) 2008 Joe Mason 

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
*/

var body = document.getElementsByTagName('body')[0];
var anchors = document.getElementsByTagName('a');

for (var i = 0; i < anchors.length; i++)
{
	var anchor = anchors[i];

	// only process anchors containing images
	if (anchor.getElementsByTagName('img').length == 0) continue;

	// add the target of the image to the end of the document
	var href = anchor.getAttribute('href');
	var hr = document.createElement('hr');
	body.appendChild(hr);
	var img = document.createElement('img');
	img.setAttribute('src', href);
	body.appendChild(img);
}

I won’t bother going through it because there are a million Javascript tutorials out there.

So what’s it useful for? Well, Wizards of the Coast have been releasing Dragon and Dungeon magazine articles online – free, for the time being. Sooner or later they’ll start charging for them so I’ve been downloading as many as I can and saving them as PDF’s. (The best way to do this is to click on the “Printer Friendly” link at the bottom of an article, and then print to PDF. On Windows you’ll have to install an add-on for this – I like PDFCreator.)

The problem is that some of them have thumbnailed images which link to a full-sized version, and I’d really like the full images to end up in the PDF. So this script just finds every image which is a link, and appends that image to the end of the page. It only runs on the printable format page (the “pf=true” at the end of the @include line). It just occurred to me it should really be checking that the link actually leads to an image, but meh – that’s not very likely for these articles, and if it happens I’ll deal with it then.

This article is a nice simple example to try it on.