A customer reported that the DuplicateHandle
function was failing with ERROR_INVALID_HANDLE
even though the handle being passed to it seemed legitimate:
// Create the handle here m_Event = ::CreateEvent(NULL, FALSE/*bManualReset*/, FALSE/*bInitialState*/, NULL/*lpName*/)); ... error checking removed ... // Duplicate it here HRESULT MyClass::CopyTheHandle(HANDLE *pEvent) { HRESULT hr = S_OK; if (m_Event != NULL) { BOOL result = ::DuplicateHandle( GetCurrentProcess(), m_Event, GetCurrentProcess(), pEvent, 0, FALSE, DUPLICATE_SAME_ACCESS ); if (!result) { // always fails with ERROR_INVALID_HANDLE return HRESULT_FROM_WIN32(GetLastError()); } } else { *pEvent = NULL; } return hr; }
The handle in m_Event
appears to be valid. It is non-null, and we can still set and reset it. But we can’t duplicate it.
Now, before claiming that a function doesn’t work, you should check what you’re passing to it and what it returns. The customer checked the m_Event
parameter, but what about the other parameters? The function takes three handle parameters, after all, and they checked only one of them. According to the debugger, DuplicateHandle
was called with the parameters
hSourceProcessHandle |
= 0x0aa15b80 |
|
hSourceHandle |
= 0x00000ed8 |
← m_Event , appears to be valid
|
hTargetProcessHandle |
= 0x0aa15b80 |
|
lpTargetHandle |
= 0x00b0d914 |
|
dwDesiredAccess |
= 0x00000000 |
|
bInheritHandle |
= 0x00000000 |
|
dwOptions |
= 0x00000002 |
Upon sharing this information, the customer immediately saw the problem: The other two handle parameters come from the GetCurrentProcess
function, and that function was returning 0x0aa15b80
rather than the expected pseudo-handle (which is currently -1
, but that is not contractual).
The customer explained that their MyClass
has a method with the name GetCurrentProcess
, and it was that method which was being called rather than the Win32 function GetCurrentProcess
. They left off the leading ::
and ended up calling the wrong GetCurrentProcess
.
By default, Visual Studio colors member functions and global functions the same, but you can change this in the Fonts and Colors options dialog. Under Show settings for, select Text Editor, and then under Display items you can customize the colors to use for various language elements. In particular, you can choose a special color for static and instance member functions.
Or, as a matter of style, you could have a policy of not giving member functions the same name as global functions. (This has the bonus benefit of reducing false positives when grepping.)
Bonus story: A different customer reported a problem with visual styles in the common tab control. After a few rounds of asking questions, coming up with theories, testing the theories, disproving the theories, the customer wrote back: “We figured out what was happening when we tried to step into the call to CreateDialogIndirectParamW
. Someone else in our code base redefined all the dialog creation functions in an attempt to enforce a standard font on all of them, but in doing so, they effectively made our code no longer isolation aware, because in the overriding routines, they called CreateDialogIndirectParamW
instead of IsolationAawreCreateDialogIndirectParamW
. Thanks for all the help, and apologies for the false alarm.”
0 comments