Can I disable a macro in an inner function? [duplicate] - c++

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.

Related

Default HRESULT hResult = E_NOTIMPL?

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 :) )

Could QueryInterface() provide us with nullptr when succeed? [duplicate]

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.

Handling CoCreateInstance return value

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.

is there any ATL supported macro that checks the hresults and returns the value?

I'm looking for something equivalent to the following macro:
#define FAILED_CHECK(hr) if(FAILED(hr)) return hr;
is there any implementation inside the ATL library that does as shown above?
thanks!
For whatever reason, ATL have not been providing an extremely useful macro like requested. Starting a few releases of Visual Studio back, ATL introduced similar macros:
/* Naming is slightly off in these macros
ATLENSURE_RETURN(condition) is an HRESULT return of E_FAIL
ATLENSURE_RETURN_VAL(condition, hr) is any return value (function can pick)
ATLENSURE_RETURN_HR(condition, hr) is HRESULT-specific, though currently the same as _VAL
*/
but once again, there was no immediate match. You have to define your own. Or alternatively, switch to throwing exceptions on error conditions. ATL provides useful macros for this: ATLENSURE_THROW, ATLENSURE_SUCCEEDED and friends.
In particular, you can throw exception on failure HRESULT using ATLENSURE_SUCCEEDED and then catch exception, esp. before return from COM interface call, converting it back to HRESULT:
_ATLTRY {
// ...
ATLENSURE_SUCCEEDED(pFoo->Bar()); // Bar returns HRESULT
// ...
} _ATLCATCH(Exception) { // CAtlException class
return Exception; // Back to HRESULT through CAtlException's operator
}
There is no ATL-specific macro since most of ATL functions use standard HRESULT - see the list of most common HRESULT values.
There are macros for error handling, including FAILED and SUCCEEDED, that are used the most:
#define FAILED(hr) (((HRESULT)(hr)) < 0)
#define SUCCEEDED(hr) (((HRESULT)(hr)) >= 0)
So you usually use these, or in specific situations you may expect specific HRESULT to be returned, thus you'll end up with checking whether it's equal to your desired value explicitly. In this case you will most likely end with something like this:
HRESULT hr = ...
if (hr != S_OK)
...
This is the list of ATL macros sorted in alphabetical order, instead this list is focused on debugging and error reporting: it seems there is nothing like you requested.

Loading CLR in C++, Start() problem

So I'm trying to load up the .NET 4 runtime and run my own C# DLL. The Start() method is throwing a HRESULT=0x1 error. If I comment out the start code, the C# DLL loads and executes, then the Stop() method throws a HRESULT=0x8000ffff error. I've looked for hours and all the code looks like what I have below (I left out all my debugging/error handling). Thank you very much for any tips in advance! =)
void DotNetLoad()
{
ICLRRuntimeHost *pClrHost = NULL;
ICLRMetaHost *lpMetaHost = NULL;
MessageBox(0, L"Creating CLR instance.", L"Bootstrap Message", 0);
HRESULT hr = CLRCreateInstance(
CLSID_CLRMetaHost,
IID_PPV_ARGS(&lpMetaHost));
ICLRRuntimeInfo *lpRuntimeInfo = NULL;
hr = lpMetaHost->GetRuntime(L"v4.0.30319",
IID_PPV_ARGS(&lpRuntimeInfo));
hr = lpRuntimeInfo->GetInterface(
CLSID_CLRRuntimeHost,
IID_ICLRRuntimeHost,
(LPVOID *)&pClrHost);
hr = pClrHost->Start();
DWORD dwRet = 0;
hr = pClrHost->ExecuteInDefaultAppDomain(
pwzTargetDll,
pwzNamespaceClass, pwzFunction, L"pwzArgument", &dwRet);
hr = pClrHost->Stop();
hr = pClrHost->Release();
}
I understand the bit about decoupling the init, .NET call, and deinit, but what do you mean by app startup and shutdown? Right now I have DotNetLoad being called from a DLL method that is injected into a remote process. Basically:
extern "C" __Declspec(dllexport) void Initialize()
{
DotNetLoad(params); //ex.
}
By combining runtime init with the assembly method call, followed by runtime deinit, you are executing this code on every call to DotNetLoad().
See the important block here. This leads me to believe that once you load the runtime into your process you don't want to do it again.
Split your initialization / deinitialization out of the method used to call the .NET assembly. Do the initialization only once (at app startup and prior to making the call), and do the deinitialization only once (at app shutdown). I tested this and it worked without error.