I am a Software Development Engineer in Test working for the Windows Sound team. You can contact me via email: mateer at microsoft dot com
Friend key: 28904932216450_59cd9d55374be03d8167d37c8ff4196b
I found a simple but nasty bug the other day in this implementation of the IMFOutputSchema interface.
The symptoms: running this code outside of a debugger caused the app to crash. Running it under a debugger (to catch the crash) caused the app to run clean.
// outputschema.hHRESULT CreateTrustedAudioDriversOutputSchema( DWORD dwConfigData, GUID guidOriginatorID, IMFOutputSchema **ppMFOutputSchema);
// outputschema.cpp// ... various include files removed ...// CMFAttributesImpl implements the IMFAttributes interface, minus the IUnknown methodsclass CTrustedAudioDriversOutputSchema : public CMFAttributesImpl<IMFOutputSchema> {friend HRESULT CreateTrustedAudioDriversOutputSchema( DWORD dwConfigData, GUID guidOriginatorID, IMFOutputSchema **ppMFOutputSchema );private: CTrustedAudioDriversOutputSchema(DWORD dwConfigData, GUID guidOriginatorID); ~CTrustedAudioDriversOutputSchema(); ULONG m_cRefCount; DWORD m_dwConfigData; GUID m_guidOriginatorID; public: // IUnknown methods HRESULT STDMETHODCALLTYPE QueryInterface( /* [in] */ REFIID riid, /* [out] */ LPVOID *ppvObject ); ULONG STDMETHODCALLTYPE AddRef(); ULONG STDMETHODCALLTYPE Release(); // IMFOutputSchema methods HRESULT STDMETHODCALLTYPE GetConfigurationData(__out DWORD *pdwVal); HRESULT STDMETHODCALLTYPE GetOriginatorID(__out GUID *pguidOriginatorID); HRESULT STDMETHODCALLTYPE GetSchemaType(__out GUID *pguidSchemaType);}; // CTrustedAudioDriversOutputSchemaHRESULT CreateTrustedAudioDriversOutputSchema( DWORD dwConfigData, GUID guidOriginatorID, IMFOutputSchema **ppMFOutputSchema) { if (NULL == ppMFOutputSchema) { return E_POINTER; } *ppMFOutputSchema = NULL; CTrustedAudioDriversOutputSchema *pSchema = new CTrustedAudioDriversOutputSchema(dwConfigData, guidOriginatorID); if (NULL == pSchema) { LOG(eError, _T("new CTrustedAudioDriversOutputSchema returned a NULL pointer")); return E_OUTOFMEMORY; } *ppMFOutputSchema = static_cast<IMFOutputSchema *>(pSchema); return S_OK;} // CreateTrustedAudioDriversOutputSchema// constructorCTrustedAudioDriversOutputSchema::CTrustedAudioDriversOutputSchema( DWORD dwConfigData, GUID guidOriginatorID): m_dwConfigData(dwConfigData), m_guidOriginatorID(guidOriginatorID){}// destructorCTrustedAudioDriversOutputSchema::~CTrustedAudioDriversOutputSchema() {}#define RETURN_INTERFACE(T, iid, ppOut) \ if (IsEqualIID(__uuidof(T), (iid))) { \ this->AddRef(); \ *(ppOut) = static_cast<T *>(this); \ return S_OK; \ } else {} (void)0// IUnknown::QueryInterfaceHRESULT STDMETHODCALLTYPE CTrustedAudioDriversOutputSchema::QueryInterface( /* [in] */ REFIID riid, /* [out] */ LPVOID *ppvObject) { if (NULL == ppvObject) { return E_POINTER; } *ppvObject = NULL; RETURN_INTERFACE(IUnknown, riid, ppvObject); RETURN_INTERFACE(IMFAttributes, riid, ppvObject); RETURN_INTERFACE(IMFOutputSchema, riid, ppvObject); return E_NOINTERFACE;}// IUnknown::AddRefULONG STDMETHODCALLTYPE CTrustedAudioDriversOutputSchema::AddRef() { ULONG uNewRefCount = InterlockedIncrement(&m_cRefCount); return uNewRefCount;}// IUnknown::ReleaseULONG STDMETHODCALLTYPE CTrustedAudioDriversOutputSchema::Release() { ULONG uNewRefCount = InterlockedDecrement(&m_cRefCount); if (0 == uNewRefCount) { delete this; } return uNewRefCount;}// IMFOutputSchema::GetConfigurationDataHRESULT STDMETHODCALLTYPE CTrustedAudioDriversOutputSchema::GetConfigurationData(__out DWORD *pdwVal) { LOG(eInfo1, _T("IMFOutputSchema::GetConfigurationData called")); if (NULL == pdwVal) { return E_POINTER; } *pdwVal = m_dwConfigData; return S_OK;}// IMFOutputSchema::GetOriginatorIDHRESULT STDMETHODCALLTYPE CTrustedAudioDriversOutputSchema::GetOriginatorID(__out GUID *pguidOriginatorID) { LOG(eInfo1, _T("IMFOutputSchema::GetOriginatorID called")); if (NULL == pguidOriginatorID) { return E_POINTER; } *pguidOriginatorID = m_guidOriginatorID; return S_OK;}// IMFOutputSchema::GetSchemaTypeHRESULT STDMETHODCALLTYPE CTrustedAudioDriversOutputSchema::GetSchemaType(__out GUID *pguidSchemaType) { LOG(eInfo1, _T("IMFOutputSchema::GetSchemaType called")); if (NULL == pguidSchemaType) { return E_POINTER; } *pguidSchemaType = MFPROTECTION_TRUSTEDAUDIODRIVERS; return S_OK;}
Recently I was musing on Order vs. Chaos and toying with my Rubik's Cube. I wondered, as a simple exercise, whether it would be possible to strongly unsolve the cube. Obviously there is a single way to put the cube into a state of greatest possible order... and a multitude of ways to put it into a state of moderate to severe chaos... but is there a "most chaotic" state?
Well, I mused, the "greatest possible order" state is achieved by bringing all the orange squares together... and all the blue squares together... and, in general, all the squares of any given color together. How homogenous... or xenophobic. Ew.
Might it not be interesting to intermingle the colors to as great an extent as possible? Can I put the cube in a state where no two orange squares are adjacent... and no two blue squares are adjacent... and, in general, no two adjacent squares are the same color?
Of course, I responded. In fact, I already know how to do that... I learned that trick before I even learned the Restore Order solution.
Twelve turns later, I had a solution to the Adjacent Squares Are Different problem.
Exercise: what are the twelve turns?
Well, that was quick.
But I wanted more.
Yeah, OK, no two adjacent squares are the same color, by the usual definition of adjacency (the squares share a common border.) But this is still a fairly homogenous solution... each face (of nine squares) still consists of only two colors, and there's a very high incidence of diagonally-touching squares of the same color. Can't we diversify this even more?
That took me a couple of days. But here's the solution I came up with:
Note that, as desired, no two adjacent squares are the same color... even if you consider squares that touch only at a corner to be adjacent... even if that corner lies on an edge, and the two squares in question lie on different faces of the cube.
The method to achieving the solution was simple in the sense that it only requires two moves (starting from a solved cube) but is probably far from optimal in the "total number of turns" sense.
There are two independent steps which can be done in either order:
Each requires knowledge of a single move and a fair amount of courage.
First, some syntax.
Hold the cube facing you. I will name the six faces of the cube:
Each face has a local definition of "clockwise"... this is the direction a clock painted on the face would turn.
Cubelet syntax
Move syntax: a letter means turn that face clockwise by 90 degrees. A letter with a subscripted -1 means turn it counterclockwise by 90 degrees. So a move "turn the Fore face clockwise, then turn the Left face counterclockwise, then turn the Top face counterclockwise" would be written:
F L-1 T-1
Start from a solved cube.
Flip the orientation of all twelve of the "edge pieces"
Pick your favorite color - say, red - and have that be the top face.
The following move flips the orientation of the LT and TH edge pieces, and also disturbs the orientation of some corner pieces:
L-1 T-1 L-1 L-1F-1 L-1 F-1 F-1T-1 F-1 T-1 T-1
All twelve of the edge pieces are now flipped. The corner pieces are still in their original positions, though they may be oriented incorrectly. That's OK.
Reposition all eight corner pieces to the opposite corner
The following move repositions FLT to TLH, TLH to TRH, and TRH to FLT:
L-1 T R T-1 L T R-1 T-1
As a convenience, the following mirror-image move repositions FRT to TRH, TRH to TLH, and TLH to FRT:
R T-1 L-1 TR-1 T-1 L T
Strictly speaking, you can get away with only memorizing one of these moves - each move is equivalent to holding the cube in a different position and executing the other move twice.
Pick three faces that share a common corner - say, the faces whose center cubes are red, white, and blue. Position the cube so it is balancing on that corner. Note that the corner cubelets now occupy four distinct strata:
This part of unsolving the cube is completed in four distinct phases:
EDIT January 16 2012: Thanks to Dustin for pointing out that the diagram above shows some reds touching diagonally (near the topmost corner.) After some analysis I believe this is just due to an error on my part in making the image; specifically, the top corner is green-yellow-red, but so is the corner in the top left. Also, the green-yellow-orange corner is missing.
Both of these can be explained by changing the red in the top corner to orange. Updated image: