Here's a code sample creating a COM object:
CComPtr<IBaseFilter> pFilter;
auto hr = CoCreateInstance(CLSID_DMOWrapperFilter, NULL,
CLSCTX_INPROC_SERVER, IID_IBaseFilter, reinterpret_cast<void**>(&pFilter));
I've seen somewhere that checking if CoCreateInstance() succeeded should look like this:
if (SUCCEEDED(hr) && pFilter != nullptr)
{
// code goes here
}
What if I would check only hr? Wouldn't it be enough? Should I also check that filter != nullptr?
//would this be enough?
if (SUCCEEDED(hr))
{
// code goes here
}
This question also concerns other COM methods like QueryInterface().
Having S_OK result from CoCreateInstance you are guaranteed to get a non-NULL interface pointer, so you don't need to check it additionally. To make it more reliable and be able to detect issues early, you might want to use ATLASSERT there to compare against NULL. This does not produce code in release builds, but generates an early warning in debug if anything goes wrong (esp. you edit or copy paste code later and change the logic of obtaining the pointer.
CComPtr<IBaseFilter> pFilter;
HRESULT hr = CoCreateInstance(CLSID_DMOWrapperFilter, NULL, CLSCTX_INPROC_SERVER,
IID_IBaseFilter, reinterpret_cast<VOID**>(&pFilter));
if(SUCCEEDED(hr))
{
ATLASSERT(pFilter); // hr is of the interest because might explain failure
// pFilter is expected to be non-NULL in case of S_OK
const CComQIPtr<IDMOWrapperFilter> pDmoWrapperFilter = pFilter;
if(pDmoWrapperFilter)
{
// We're not really interested in QueryInterface's HRESULT since it's
// either S_OK or E_NOINTERFACE, hr will typically explain nothing special.
// More important is whether we finally obtained the pointer or not
}
}
I think it is redundant and not needed to check both.
If it does fail though, the return value will tell you which error occurred. That's why there's 2 ways of determining if the function succeeded or not.
Related
I am working on a win7 based system using silverlight for embedded for UI graphics and C++ for firmware. I have noticed that in many of the existing functions (written before i was brought onto the project), there is some code that i am not quite sure what it is doing.
HRESULT AddAlarm::AlarmType_SelectionChanged (IXRDependencyObject* pSender, XRSelectionChangedEventArgs* pArgs)
{
HRESULT hResult = E_NOTIMPL;
if((NULL == pSender)||(NULL==pArgs))
{
hResult = E_INVALIDARG;
}
//Code to set visibility of UI elements
if(index ==0) //index is the threshold type index from the combobox. Can be 0-3.
{
m_pAlarmLowThreshold->SetVisibility(XRVisibility_Collapsed);
}
//Code repeats for other threshold types and visibility states.
return hResult;
}
The if statement is pretty straightforward and the function returns hResult, but i dont understand the declaration HRESULT hResult = E_NOTIMPL;. It is declaring a variable of type HRESULT and assigning it a default HRESULT value of E_NOTIMPL, but since the function doesnt modify this value outside of the if statement, doesnt this mean that it remains as E_NOTIMPL, basically telling the system that it (something) is not implemented or is wrong?
I know that when this king of method is automatically generated trought the VS interface. The inside code is always something like
return E_NOTIMPL;
I think what your predecessors tried to do is beeing clean in there way to develop the method by assuring them self that all case are processed by starting with an E_NOTIMPL that should be changed during method's processing.
This kind of method should return s_OK when it works fine. Here is a list of possible codes :
http://msdn.microsoft.com/en-us/library/windows/desktop/aa378137%28v=vs.85%29.aspx
If there is no assigning of an S_OK it means indeed that the function is not fully implemented thus an E_NOTIMPL seems correct (or not :) )
This question already has answers here:
Handling CoCreateInstance return value
(2 answers)
Closed 8 years ago.
Imagine a situation:
CComPtr<IGraphBuilder> pGraph;
HRESULT hr = CoCreateInstance(CLSID_FilterGraph, NULL, CLSCTX_INPROC_SERVER, IID_PPV_ARGS(&pGraph));
if (SUCCEEDED(hr))
{
CComPtr<IMediaControl> pControl;
hr = pGraph->QueryInterface(IID_PPV_ARGS(&pControl));
if(SUCCEEDED(hr))
{...}
}
I wonder, if pControl could ever be nullptr inside last block {...}. The question occurred, because I saw that code:
if(SUCCEEDED(hr) && pControl)
{...}
I consider that part && pControl as a redundant one. Am I right?
QueryInterface() is required to provide a valid (so non-null) interface pointer on success and a null pointer on failure. However you don't know whether some specific implementation follows that rule and the code you cite most likely tries to be defensive.
That said, the following
HRESULT hr = CoCreateInstance(CLSID_FilterGraph, NULL,
CLSCTX_INPROC_SERVER, IID_PPV_ARGS(&pGraph));
also calls QueryInterface() under the hood to retrieve the pointer to the requested interface. If the code wants to be defensive it should check that pGraph is non-null on success too.
The problem here is you don't know how bad it is when you get S_OK and a null pointer. Suppose QueryInterface() works like this (really bad code follows, not for use anywhere):
HRESULT TheClass::QueryInterface( REFIID iid, void** ppv )
{
if( iid == SomeSpecificIID ) {
AddRef();
*ppv = 0; //BAD IDEA, BAD CODE, JUST DON'T
return S_OK;
} else {
//whatever
}
}
great, the defensive code will avoid dereferencing a null pointer retrieved here together with S_OK returned but reference count will be incorrect - noone will have a chance to call matching Release(). So you instantiate such an object, then call QueryInterface() which works as above, the refcount is now 2, then you Release() the object once and it leaks. How bad it happens to turn out depends on a lot of factors.
Same with CoCreateInstance() - it calls the same QueryInterface() under the hood. Both may be broken and your mileage may vary both with and without checking the retrieved pointer against null.
The following code is copied from MS Async Filter. It is supposed that the following code is calling either CancelIo or CancelIoEx. I don't see where CancelIoEx is called in anyway. It is supposed that the typedef is representing the CancelIoEx but is never called. What exactly the line bResult = (pfnCancelIoEx)(m_hFile, NULL); is doing?
// Cancel: Cancels pending I/O requests.
HRESULT CFileStream::Cancel()
{
CAutoLock lock(&m_CritSec);
// Use CancelIoEx if available, otherwise use CancelIo.
typedef BOOL (*CANCELIOEXPROC)(HANDLE hFile, LPOVERLAPPED lpOverlapped);
BOOL bResult = 0;
CANCELIOEXPROC pfnCancelIoEx = NULL;
HMODULE hKernel32 = LoadLibrary(L"Kernel32.dll");
if (hKernel32){
//propably bad code !!! Take Care.
bResult = (pfnCancelIoEx)(m_hFile, NULL);
FreeLibrary(hKernel32);
}
else {
bResult = CancelIo(m_hFile);
}
if (!bResult) {
return HRESULT_FROM_WIN32(GetLastError());
}
return S_OK;
}
Assuming this is all the code, it has a serious bug in it. This:
CANCELIOEXPROC pfnCancelIoEx = NULL;
defines pfnCancelIoEx as a pointer to function whose signature matches that of CancelIoEx. The pointer is initialised to a null value and the obvious intention is to point it at CancelIoEx later.
That function is defined in Kernel32.dll, so loading this is the logical next step. If this succeeds, the code should proceed by doing this:
pfnCancelIoEx = GetProcAddress(hKernel32, "CancelIoEx");
And then it should check the result. However, it does not do either of that.
Next, on this line:
bResult = (pfnCancelIoEx)(m_hFile, NULL);
it attempts to call the function pointed to by pfnCancelIoEx. However, this pointer is never changed from its initial null value, so this will attempt to dereference a null pointer, resulting in undefined behaviour and likely a crash.
This question already has answers here:
Closed 10 years ago.
Possible Duplicate:
Can I redefine a C++ macro then define it back?
I have an application that calls a function from a third party SDK lots of times along the app lifetime. This third party function checks for some errors with its _3RDPARTY_ASSERT (which is a wrapper around _ASSERT).
My problem is that in one of these calls, I sometimes expect an error (and handle it afterwards). I would like to disable the assert in this case, as it's quite annoying while debugging, but keep it in all the other cases.
I have tried to handle it with pragma push_macro/pop_macro but I haven't found a way.
Is this possible?
I have the source of 3rdParty.cpp but would prefer not to touch it.
This would be a simplified version of the code:
mine.cpp:
#include "3rdparty.h"
HRESULT MyMethod(...)
{
HRESULT hr;
hr = _3rdParty(...);
if (SUCCEEDED(hr))
hr = _3rdParty(...);
if (SUCCEEDED(hr))
hr = _3rdParty(...);
...
if (SUCCEEDED(hr))
hr = _3rdParty(...); // This call shouldn't throw the assertion, as I expect it to fail sometimes!
if (FAILED(hr))
doSomething();
else
doSomethingElse();
...
if (SUCCEEDED(hr))
hr = _3rdParty(...);
return hr;
}
3rdParty.cpp:
...
#define _3RDPARTY_ASSERT (_ASSERT)
...
HRESULT _3rdParty(...)
{
HRESULT hr;
hr = SomeFunction();
_3RDPARTY_ASSERT(SUCCEEDED(hr));
return hr;
}
The problem here is that unless it is inlined, the function will be tokenized and compiled a single time. This means it doesn't matter if the macro is defined or not when you call the function, only when it is compiling the function itself.
If you have access to the definition of _3RDPARTY_ASSER, like
#define _3RDPARTY_ASSERT definition
Then you save that definition:
#define SAVE_ASSERT definition
Then in the place in your code when you don't want an assertion you could #undef _3RDPARTY_ASSERT or #define it to something else.
After that code you can re-enable the old definition by
#define _3RDPARTY_ASSERT SAVE_ASSERT
A second solution, which I prefer, is this: If you have access to the 3'd party code, you can create another version of _3rdParty(...) which doesn't assert, then use it as needed.
I don't know if anyone familiar with BHO (Browser Helper Object), but an expert in c++ can help me too.
In my BHO I want to run the OnDocumentComplete() function only on the main frame - the first container and not all the Iframes inside the current page. (an alternative is to put some code only when this is the main frame).
I can't find how to track when is it the main frame that being populated.
After searching in google I found out that each frame has "IDispatch* pDisp", and I have to compare it with a pointer to the first one.
This is the main function:
STDMETHODIMP Browsarity::SetSite(IUnknown* pUnkSite)
{
if (pUnkSite != NULL)
{
// Cache the pointer to IWebBrowser2.
HRESULT hr = pUnkSite->QueryInterface(IID_IWebBrowser2, (void **)&m_spWebBrowser);
if (SUCCEEDED(hr))
{
// Register to sink events from DWebBrowserEvents2.
hr = DispEventAdvise(m_spWebBrowser);
if (SUCCEEDED(hr))
{
m_fAdvised = TRUE;
}
}
}
else
{
// Unregister event sink.
if (m_fAdvised)
{
DispEventUnadvise(m_spWebBrowser);
m_fAdvised = FALSE;
}
// Release cached pointers and other resources here.
m_spWebBrowser.Release();
}
// Call base class implementation.
return IObjectWithSiteImpl<Browsarity>::SetSite(pUnkSite);
}
This is where I want to be aware whether its the main window(frame) or not:
void STDMETHODCALLTYPE Browsarity::OnDocumentComplete(IDispatch *pDisp, VARIANT *pvarURL)
{
// as you can see, this function get the IDispatch *pDisp which is unique to every frame.
//some code
}
I asked this question on Microsoft forum and I got an answer without explaining how to actually implement that: http://social.msdn.microsoft.com/Forums/en-US/ieextensiondevelopment/thread/7c433bfa-30d7-42db-980a-70e62640184c
What jeffdav suggested is, to test wether the pDisp supports IWebBrowser2 via QueryInterface(), and if so, to check wether it is the same object as the one you stored in SetSite().
The QueryInterface() rules only require that a QI for IUnknown always results in the same pointer value, so you have to additionally QI to IUnknown and compare the resulting pointers.
This would lead to something like this in OnDocumentComplete():
IWebBrowser2* pBrowser = 0;
IUnknown *pUnk1=0, *pUnk2=0;
if( SUCCEEDED(pDisp ->QueryInterface(IID_IWebBrowser2, (void**)&pBrowser))
&& SUCCEEDED(pDisp ->QueryInterface(IID_IUnknown, (void**)&pUnk1))
&& SUCCEEDED(m_spBrowser->QueryInterface(IID_IUnknown, (void**)&pUnk2))
&& (pUnk1 == pUnk2))
{
// ... top-level
}
... or if you are using ATL (as m_spWebBrowser suggests):
CComQIPtr<IWebBrowser2> spBrowser(pDisp);
if(spBrowser && spBrowser.IsEqualObject(m_spWebBrowser)) {
// ...
}
Notice that I did not test this, I'm only rewriting what the guy on msdn said.
In ::SetSite you get an IUnknown pointer. Call IUnknown::QueryInterface on it (just like you're already doing), but instead use IID_IDISPATCH. Save this pointer somewhere, this pointer is the top level frame.
In ::OnDocumentComplete you're getting a IDispatch pointer, compare this one to the previous saved ptr and voĆla, if there is a match you're in the top level.