21 January

Here comes the sun, and I say

Here's a little retroactive technical support, for those engineers and programmers who are living backwards through time.

If, while attempting to boot an early model Sun SPARCstation, you get the message:

Can't clear ESP interrupts: Check SCSI Term, Power Fuse.

then make sure that all SCSI devices are powered before turning on the SPARCstation. (In other words, turn on your CD-ROM drive.)
15:37:38 - jbyrd - 1 comment

14 May

There's no leaving here; ask, I'm an ear

There?s a great deal of existing rendering code built on old versions of Microsoft?s Foundation Class (MFC) model. In the old object model, you had a single CFrameWnd, a single CDocument, and one or more CView classes that were owned by the CFrameWnd class. These objects share message routing responsibilities with one another, and a great deal of code has been written with these assumptions.

Fast forward twenty or so years, and these old assumptions, upon which most of MFC was originally architected, are incompatible with the complexity of modern user interface design, and even a good deal of modern-day MFC itself. There can be multiple documents, controls floating and tabbed which may or may not be children of the CFrameWnd.

The funky new display and interface features like CDockablePane and CMFCToolBar don?t know anything about the CView class, and they don?t inherit from CView. It?s hard to upgrade an older application written based on the old MFC document-view model to dockable panes.

It?s a bit of work, but here?s one way to accomplish this without relying on proprietary libraries. The basic strategy we use is to change the old CView-based classes to be a subclass of CDockablePane, and then make the new class support enough of the major CView features in order to handle update rendering, commands, OLE drag and drop, and user-interface updates via the old interfaces in your old class.

In order to convert your own subclass of CView into a CDockablePane subclass, here?s what you need to do:

1. Create a new subclass of CDockablePane (we?ll call it CYourDockablePane) from which all your old CViews will inherit.
2. Implement update message handling and OLE support from your CYourDockablePane subclass.
3. Subclass COleDropTarget into a new class which we?ll call CYourOleDropTarget in order to handle OLE drag-and-drop in the manner that CView does.
4. Add features to your C*FrameWnd* class to support window updating and command message routing to the new panes.


#pragma once

#include "YourOleDropTarget.h"

class CYourDockablePane : public CDockablePane

virtual ~CYourDockablePane();

// These are needed to get around OnUpdate()?s protected status
virtual BOOL ReceiveNotification(WPARAM wParam, LPARAM lParam, LRESULT* pResult);
virtual void OnUpdate( CView *pSender, LPARAM lHint, CObject *pHint );

// Simulate CView OLE drag and drop effects
virtual DROPEFFECT OnDragEnter( COleDataObject *pDataObject, DWORD dwKeyState, CPoint point );
virtual void OnDragLeave( void );
virtual DROPEFFECT OnDragOver( COleDataObject *pDataObject, DWORD dwKeyState, CPoint point );
virtual DROPEFFECT OnDropEx( COleDataObject *pDataObject, DROPEFFECT dropDefault, DROPEFFECT dropList, CPoint point );
virtual DROPEFFECT OnDragScroll( DWORD dwKeyState, CPoint point);
virtual BOOL OnDrop( COleDataObject* pDataObject, DROPEFFECT dropEffect, CPoint point);


// View classes know how to do this
virtual CYourDocument *GetDocument(void) const;
CYourOleDropTarget m_OleDropTarget;




// YourDockablePane.cpp : implementation file

#include "stdafx.h"
#include "YourDockablePane.h"

IMPLEMENT_DYNCREATE(CYourDockablePane, CDockablePane)




BEGIN_MESSAGE_MAP(CYourDockablePane, CDockablePane)

CYourDocument * CYourDockablePane::GetDocument( void ) const
CDocTemplate* pDocTemplate;
pos = AfxGetApp()->GetFirstDocTemplatePosition();
pDocTemplate = AfxGetApp()->GetNextDocTemplate(pos);
pos = pDocTemplate->GetFirstDocPosition();
return (CYourDocument*) pDocTemplate->GetNextDoc(pos);

BOOL CYourDockablePane::ReceiveNotification( WPARAM wParam, LPARAM lParam, LRESULT* pResult )
return OnNotify( wParam, lParam, pResult );

DROPEFFECT CYourDockablePane::OnDragEnter( COleDataObject *pDataObject, DWORD dwKeyState, CPoint point )

void CYourDockablePane::OnDragLeave( void )


DROPEFFECT CYourDockablePane::OnDragOver( COleDataObject *pDataObject, DWORD dwKeyState, CPoint point )

DROPEFFECT CYourDockablePane::OnDropEx( COleDataObject *pDataObject, DROPEFFECT dropDefault, DROPEFFECT dropList, CPoint point )

DROPEFFECT CYourDockablePane::OnDragScroll( DWORD dwKeyState, CPoint point )

BOOL CYourDockablePane::OnDrop( COleDataObject* pDataObject, DROPEFFECT dropEffect, CPoint point )
return false;

void CYourDockablePane::OnUpdate( CView *pSender, LPARAM lHint, CObject *pHint )



#pragma once

class CYourDockablePane;

// CYourOleDropTarget command target

class CYourOleDropTarget : public COleDropTarget

virtual ~CYourOleDropTarget();
BOOL Register(CWnd* pWnd);

CYourDockablePane *m_pPane;
virtual DROPEFFECT OnDragEnter(CWnd* pWnd, COleDataObject* pDataObject,
DWORD dwKeyState, CPoint point);
virtual DROPEFFECT OnDragOver(CWnd* pWnd, COleDataObject* pDataObject,
DWORD dwKeyState, CPoint point);
virtual BOOL OnDrop(CWnd* pWnd, COleDataObject* pDataObject,
DROPEFFECT dropEffect, CPoint point);
virtual DROPEFFECT OnDropEx(CWnd* pWnd, COleDataObject* pDataObject,
DROPEFFECT dropDefault, DROPEFFECT dropList, CPoint point);
virtual void OnDragLeave(CWnd* pWnd);
virtual DROPEFFECT OnDragScroll(CWnd* pWnd, DWORD dwKeyState,
CPoint point);



// YourOleDropTarget.cpp : implementation file

#include "stdafx.h"
#include "YourDockablePane.h"
#include "YourOleDropTarget.h"

// CYourOleDropTarget

IMPLEMENT_DYNAMIC(CYourOleDropTarget, COleDropTarget)

CYourOleDropTarget::CYourOleDropTarget() :
m_pPane( NULL )


BEGIN_MESSAGE_MAP(CYourOleDropTarget, COleDropTarget)

BOOL CYourOleDropTarget::Register( CWnd* pWnd )
m_pPane = dynamic_cast< CYourDockablePane * >( pWnd );
return COleDropTarget::Register( pWnd );

// CYourOleDropTarget message handlers

DROPEFFECT CYourOleDropTarget::OnDragEnter(CWnd* pWnd, COleDataObject* pDataObject, DWORD dwKeyState, CPoint point)
return m_pPane->OnDragEnter( pDataObject, dwKeyState, point);

void CYourOleDropTarget::OnDragLeave(CWnd* pWnd)

DROPEFFECT CYourOleDropTarget::OnDragOver(CWnd* pWnd, COleDataObject* pDataObject, DWORD dwKeyState, CPoint point)
return m_pPane->OnDragOver( pDataObject, dwKeyState, point);

DROPEFFECT CYourOleDropTarget::OnDragScroll(CWnd* pWnd, DWORD dwKeyState, CPoint point)
return m_pPane->OnDragScroll( dwKeyState, point);

BOOL CYourOleDropTarget::OnDrop(CWnd* pWnd, COleDataObject* pDataObject, DROPEFFECT dropEffect, CPoint point)
return m_pPane->OnDrop( pDataObject, dropEffect, point);

DROPEFFECT CYourOleDropTarget::OnDropEx( CWnd *pWnd,
COleDataObject* pDataObject,
DROPEFFECT dropDefault,
CPoint point

effect = m_pPane->OnDropEx( pDataObject, dropDefault, dropList, point );

if ( effect == DROPEFFECT_NONE )
return m_pPane->OnDrop( pDataObject, dropDefault, point );

return effect;

Add this snippet to the definition file (the .h file) of your application?s CFrameWnd or CFrameWndEx subclass:

. . .
typedef list< CPane *> CYourPanes;
typedef CYourPanes::iterator CYourPaneIter;

typedef list< CYourDockablePane *> CYourDockablePanes;
typedef CYourDockablePanes::iterator CYourDockablePanesIter;

CYourPanes m_Panes;
CYourDockablePanes m_YourDockablePanes;

Add this to the implementation file (the .cpp file) of your application?s CFrameWnd or CFrameWndEx subclass, changing the CYourFrameWnd class name to the name of your frame window subclass:

void CYourFrameWnd::OnUpdate( CView* pSender, LPARAM lHint, CObject* pHint )
for ( CYourDockablePanesIter it = m_YourDockablePanes.begin();
it != m_YourDockablePanes.end(); it++ )
(*it)->OnUpdate( pSender, lHint, pHint );

BOOL CYourFrameWnd::OnCmdMsg(UINT nID, int nCode, void* pExtra, AFX_CMDHANDLERINFO* pHandlerInfo)
/* We intercept all the commands sent to the frame here, and give all
* our child panes first crack at handling them.
for ( CYourPaneIter it = m_Panes.begin(); it != m_Panes.end(); it++ )
if ( (*it)->OnCmdMsg( nID, nCode, pExtra, pHandlerInfo ))
return true;

return CFrameWndEx::OnCmdMsg(nID, nCode, pExtra, pHandlerInfo);

BOOL CYourFrameWnd::OnNotify(WPARAM wParam, LPARAM lParam, LRESULT* pResult)
for ( CYourDockablePanesIter it = m_YourDockablePanes.begin(); it != m_YourDockablePanes.end(); it++ )
if ( (*it)->ReceiveNotification( wParam, lParam, pResult ) )
return true;

return CFrameWndEx::OnNotify(wParam, lParam, pResult);

At this point, you should search through your old CView class to find any references to a COleDropTarget. These references should be changed to refer to the m_OleDropTarget member that you put within the CYourDockablePane class.

A couple final things you need to do: inform your main frame class about the locations of your CYourDockablePane-derived classes, as well as your toolbars and other non-view features, which are generally children of the CPane class.

Wherever you instantiate and call Create() on your CYourDockablePane descendant, add it to your list of CYourDockablePanes:

m_YourDockablePanes.push_back( &yourNewlyCreatedDockablePane );

And wherever you instantiate and Create() toolbars or other things that need to process commands or UI updates, including your dockable panes, add them to the list of CPanes as well:

m_Panes.push_back( &yourNewlyCreatedControlOrPane );

This basic strategy can be used to convert old CView-based classes into any modern control-based user interface architecture, or merely to have your classes derive from CWnd directly.

There may be other side effects of this class conversion that I've not considered. Please feel free to modify the above code to your specific situation.

Information and code from this blog entry may be reused and redistributed under the following license.

Creative Commons License
There's no leaving here; ask, I'm an ear by John Byrd is licensed under a Creative Commons Attribution 3.0 United States License.
Based on a work at
15:38:13 - jbyrd - 4 comments

07 November

The sky is blue, and all the leaves are green

For those of you who are not familiar: for the past three years I've been working as a contractor at a large video game development house. The company has been laying off a bunch of people, and yesterday they decided that I should be on that list as well. I feel ambivalent about this. The timing was awkward, but I feel like my product is at the point where I can begin licensing it on a larger scale, so this has the potential to be a blessing in disguise. At least, I'm going to try to keep a positive attitude, and try to focus on rounding up new business. Those of you who know me know that I'm the most sardonic human being in this hemisphere, so positivity does not come naturally to me; but middleware is one of those few industries that does well in an economic downturn, and the product we've developed is actually better than the competition, so I do have a good chance of actually turning a profit soon.

Obligatory joke: Titles of musicals that will write themselves:

"Bleeding In The Rain"
"Jesus Christ Porno Star"
"Annie Get Your Machete"
"An American In Paris Hilton"
"Blow Me Kate"
10:33:27 - jbyrd - 1 comment

30 September

Spam spam spam spam spam spam spam spam

So the Yahoo porn spam bot keeps contacting me. Rather than ignore it, I thought I'd try to get it to tell me a little more about its internal structure, so that someone with more time than me can r00t it. Here's what I found out.

The bot has a canned script. If a human responds to its IMs, and it doesn't see a keyword, then it continues with its canned script. Once the script ends, the conversation terminates.

Known interesting keywords follow. The bot searches this keyword list in this order, and the earliest match is returned as a response. The bot is case-insensitive. The bot will continue to chat you indefinitely if you include one or more of the following words in your response.

web / [or whatever the porn URL du jour is]
site / [or whatever the porn URL du jour is]
shit / what's wrong?
fake / the only thing fake here is your toupet!
spam / nah, I am a vegetarian... no spam for me! haha
bot / whats a bot? im 100% all real and natural, from tits to ass!
12:03:38 - jbyrd - Add your comments

13 September

I don't believe it, it's almost too good to be true

I ain't never seen an ass like that

This picture is from Tommy's highfaluting video game party. I'm getting checked from all sides, and one girl is checking my ass. The frightening old man getting ignored happens to be Nolan Bushnell. And Nolan is the guy who invented video games. Leonardo diCaprio is going to play Nolan in an upcoming film. I didn't invent video games, but geek girls apparently prefer to check my ass over Nolan's. Shit, I could play Nolan. Clicky for biggy.
12:24:49 - jbyrd - 4 comments

09 December

I'm a juvenile product of the working class

Make sure your mouse's cursor is in the black window above, or the text you type will be ignored.
18:13:02 - jbyrd - 4 comments

09 November

And now I get to watch the stock report in Korean

The last ten years of my life have apparently been spent maximizing possession of cables. Ancient Mac SCSI cables, USB to mini USB, SATA, MIDI, serial to parallel (including a few LapLink cables), several Firewire variants, defunct mouse cables, joypad cables for game systems long obsolete, multiple Dreamcast A/V cables, at least a dozen transformer/DC converter/wall warts, various power bricks of the 1980s and 1990s.

Cables are expensive, I tell myself, but the Freudian implications are all too clear.

Two Hefty bags, full of nothing but goddamned cables, went to the curb this morning, and another must go. It was heart-wrenching, but it had to be done. At least one major piece of furniture in the new house will have no particular function, as it will not be containing cables anymore.

Even more unsettling (but perhaps ultimately liberating) is the realization that my most treasured possessions are information, not objects. Double-notched Commodore 64 disks, my canonical arcade ROM collection, my stageplays and teleplays, my contact database, e-mail addresses and phone numbers of my friends, pictures on the wall and of every play I?ve ever been in, my movies, the music of the Hungry Hungry Hippos: a finite, fixed incantation of zeros and ones. Since pi never repeats, it contains all possible finite sequences of digits; therefore every object of value in my life could be concatenated and archived by finding the corresponding digit sequence in pi that concatenates all the information from my life. Pi, with an extremely long (but finite) index or subscript, would serve as both an epitaph and a backup copy of my life.

The two objects that must travel with me as we transition into temporary housing: the laptop that I?m tapping on now, and my Montaya acoustic guitar. Everything else is negotiable.

The wife is in ?breakfast mode?. To her, all tasks can be accomplished, simultaneously if need be, with sufficiency of willpower. I?m a tad worried about her, but she?s damned good at managing these sorts of things. She's a listmaker, an organizer, a type-A problem solver. I bought her a teeny little laptop for telecommuting from Costa Mesa, and she carries it about like a teddy bear. For both of us, the move on Friday and Saturday will be tough (but finite). I'm a little more concerned about her finding a posse of friends from the isolation of temporary housing in SoCal -- as much as she loves home decorating, she's simply not stay-at-home material.
09:58:27 - jbyrd - 2 comments

19 September

Destiny is a rising sun

Hi N,

Thanks for the call. With regard to your contract changes:

Section 4. Deleted 4. and renumbered the contract points per your request.

Section 5. The computer services and tools clause only covers items that you need me to purchase as a condition of the work. I presume you're going to let me use your dev equipment, software and PCs. Home-use equipment is my cost, unless you specifically instruct me to buy it.

I would like to consider this document final. I would like to ask you to please print 2 copies of the enclosed, sign them both, and send them to me. I'll countersign and return an original to you.

The wife and I spent Saturday and Sunday driving around the OC looking for houses. Huntington Beach is high on our list.

Thanks for everything, N.
15:44:41 - jbyrd - 3 comments

22 May

She'll do anything, she'll do anything, she'll do anything

1. Go to (Microsoft's search engine)
2. Type in asshole pictures as the search phrase
3. I'm currently ranked at number five!
15:35:43 - jbyrd - 1 comment

09 April

Boogie with a suitcase

An unexpected letter from my father

It got me into the Media Lab in the basement of the Science Center, and that's about it

Most people are this young at some point in their lives
19:50:02 - jbyrd - Add your comments

02 February

I can program a computer, choose the perfect time

Holy shit...!

The choice of February 2, 2006 was significant.
15:06:58 - jbyrd - 1 comment

11 January

When it's time to leave here I hope you'll understand

Commute today: the wife drives me (in the new Prius) to the airport, and it's ten minutes in the red-carpet lounge for a mini-bagel and coffee -- seat 1C to LAX, a shuttle to the Tom Bradley International Terminal, through customs, into the ANA first-class suite for more coffee, then eleven sunshine-filled hours to Tokyo, then a bus takes us to the main terminal, through immigration, a limousine bus (it's just a regular bus, only more expensive) to Akasaka, up the hill to Villa Fontaine Roppongi.
02:45:09 - jbyrd - 3 comments

05 August

I've got your picture of me and you

Sorry to those of you who have been trying unsuccessfully to post here. I added image-based validation -- it should be easier for you to add your comments now.
17:17:27 - jbyrd - Add your comments

03 July

I'm all decoded now, I think you better go

Jul 1 23:14:50 partygirl sshd[19154]: Accepted password for upload from port 39152 ssh2

Jul 3 07:57:14 partygirl sshd[4373]: Accepted password for upload from port 1859 ssh2
Jul 3 11:30:30 partygirl sshd[5391]: Accepted password for upload from port 4646 ssh2


And with that, a skript kiddie in Romania, working from the subdomain, broke into . He installed a subdomain scanner and ssh brute force tool into a hidden directory called "/tmp/ /.of" and he began dictionary attacks on other machines.

The style of compromise is highly specific.

The attacker at is running Windows Terminal Server 2003. The box is probably being controlled remotely by the attacker.

I've nuked the offending account and taken countermeasures, but he's still knocking at the open ports, trying to get in. If you're the attacker, give up on this box and move on, or I'm going to hit back.
16:45:34 - jbyrd - Add your comments

19 May

We've got thrills and shocks, supersonic fighting cocks

At the Summer Consumer Electronics Show in 1994, one particular SNES title on the show floor was being completely ignored, and I had the chance to examine it in some detail.

That SNES title was "The Flintstones: Treasure of Sierra Madrock." Heck, you remember that one, don't you?

Or maybe you don't. Around 1994 there was a huge surplus of mediocre me-too licensed games built around similar recycled 2-D scroller engines for the SNES and the Sega Genesis. The 1994 Summer CES show floor had plenty of them. The basic game play mechanic was well known: you are the licensed character, you run to the right, you jump, you have a short-ranged attack, and you pick up powerups which give you ranged attacks. Bad guys move in predictable patterns except for a boss at the end of the level.

The designers of "Treasure of Sierra Madrock" did not require deep knowledge of their previous title, "The Flintstones," in order to enjoy their new work. You jumped over the rocks, you punched the snakes.

Anyway, I had no competition on the CES show floor to play "The Flintstones: Treasure of Sierra Madrock."

Everyone else was playing 3DO. In 1994 the 3-D revolution hit the industry like a tsunami and the sidescrollers all washed away. With the launch of the 3DO and the Jaguar in 1993, then the PlayStation in 1994, the 2-D scroller game mechanic got very dead very quickly.

Fast forward to the Mongolian cluster fuck of E3 2005. Between meetings, I wandered the West and South Hall and I did my level best to ignore the tits and the subwoofers. And truth be told, there were a handful of shockingly beautiful games out there.

This E3 2005 will be remembered as The E3 That We Decided In Our Hearts To Buy An HDTV. In particular, Top Spin 2, an Xbox 360 title by Indie Built, stood out as a tennis title with some great attention to shadows and character detail. Also on Xbox 360, Activision's Call of Duty 2, done by Infinity Ward, got their building and sky textures just right in the demo level, and the result was a first-person shooter that will sell next-gen systems.

In the PS2 department, Capcom's Clover Studio showed Okami, a stylized "nature adventure" that incorporates elements of Japanese calligraphy with an updated Viewtiful Joe engine. You take control of a sun god, embodied in a wolf. You can call down spells, painted on the screen by a vast Japanese brush as time is frozen; leaves and blades of grass flicker brilliantly about you. Beautiful. Won't sell, but it's still beautiful.

Around a third or so of the titles on the E3 2005 show floor fell into a category that we will refer to as the Formula. The Formula involves putting your licensed protagonist character in a third-person perspective view, Mario World style, and letting him wander around outdoors. He has a short-range attack that he uses against the bad guys, and he has a long range attack that typically works with short-term powerups, and the camera floats behind his head like a balloon on a leash.

There are several technical problems with the Formula. First, you will notice that, due to the camera angle in the Formula, we constantly look down on the protagonist from the ceiling, a few feet behind the character. This means that the majority of screen real estate is taken up by the ground. And the ground is in severe perspective, so unless you do some fantastic mipmapping tricks or procedural texturing, either your ground looks pixellated, or your world is small. You have to get your memory from somewhere. Second, the camera always seems to want to do the wrong thing in a Formula game. Typically it drags along behind the character until some bad guys come along, at which point it hops back to get the bad guys into frame. Going around corners or reversing directions during a fight sequence typically causes camera conniptions.

Those issues are surmountable, but this one is not: at E3 2005, there were just too many games that depended too heavily on the Formula.

PS3 and Xbox 360, supporting HDTV and HD-DVD, are coming out within a year. And as of this writing there is a bunch of licensed games for the old platforms that follow the Formula.

It's Summer CES 1994 all over again.

Supply and demand will sort this out. I suggest that, come E3 2008, you will see very few Formula games on the show floor. Something better is coming.
07:59:00 - jbyrd - 1 comment