Default HRESULT hResult = E_NOTIMPL? - c++

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

Related

IDispatch::Invoke Returning E_INVALIDARG

I have an ATL COM component which raises a few events which are handled by managed (C# and VB.NET) code. The component is currently used by a VS2005 VB.NET project (as an ActiveX control) and all of the events are raised and everything works.
However, in porting some of the code to C#, I noticed that all but one of the events are never raised. The only event which is raised passes no arguments back to the handler. All others do.
// this function is auto-generated
HRESULT Fire_SomeEvent(VARIANT_BOOL inOriginated, IUserType * inUserType)
{
CComVariant varResult;
T* pT = static_cast<T*>(this);
int nConnectionIndex;
CComVariant* pvars = new CComVariant[2];
int nConnections = m_vec.GetSize();
for (nConnectionIndex = 0; nConnectionIndex < nConnections; nConnectionIndex++)
{
pT->Lock();
CComPtr<IUnknown> sp = m_vec.GetAt(nConnectionIndex);
pT->Unlock();
IDispatch* pDispatch = reinterpret_cast<IDispatch*>(sp.p);
if (pDispatch != NULL)
{
VariantClear(&varResult);
pvars[1] = inOriginated;
pvars[0] = inUserType;
DISPPARAMS disp = { pvars, NULL, 2, 0 };
pDispatch->Invoke(0x7, IID_NULL, LOCALE_USER_DEFAULT, DISPATCH_METHOD, &disp, &varResult, NULL, NULL);
}
}
delete[] pvars;
return varResult.scode;
}
Invoke is returning 0x80070057 (E_INVALIDARG). Yet, in VB land, when used via the ActiveX wrapper, it works. Now, I'm no COM wizard by any means, and I just don't get it. I haven't been able to find anything applicable anywhere.
I thought that perhaps it had something to do with passing a UDT, but no; an almost identical version, with the IUserType replaced by a LONG also returns E_INVALIDARG. Again, the single event which passes no arguments works.
A short example of how it may be used by the managed code. Nothing crazy here.
class Program
{
private ComType _c;
static void Main(string[] args)
{
_c = new ComType();
_c.SomeEvent += _c_SomeEvent;
_c.DoSomethingWhichRaisesSomeEvent();
}
static void _c_SomeEvent(bool b, IUserType udt)
{
// never called
}
}
I would normally spend more time debugging before reaching out here, but I have to make a call here soon. I either have to fix this, or abandon this interface and use another (which is sub-optimal for my purpose). So, hoping some of you COM pros have run into this before.
Double-check your vt values in your dispparam variants; many IDispatch implementations are quite particular about having everything line up.

How to convert VARIANT_BOOL* to bool*

I found this question, but they aren't using a pointer.
I have a method that my COM method calls that requires a pointer to a bool. This bool is used to cancel the long running process (video recording, if you must know) from the caller.
Can I cast it somehow, but still have VARIANT_BOOL equate to FALSE and vice-versa?
Code
HRESULT YourObject::YourComMethod(VARIANT_BOOL* pVarBool)
{
callYourNonComMethodHere((bool*)pVarBool);
return S_OK;
}
UPDATE
So, I learned that, although you can have COM parameters as pointers, but they serve no purpose. That don't actually reference the pointer from the caller.
So, what I had to do was make a totally separate COM object that is my CancellationToken. Then, in my implementation, I can call token.Cancel(), and then the YourComMethod will have the updated bool, indicating that the long running method should cancel.
I created a sample project to demonstrate how I was able to pass a pointer to a bool, using a wrapping COM object.
https://bitbucket.org/theonlylawislove/so-blocking-com-call/src
VARIANT_BOOL is supposed to be one of two values if done right. VARIANT_TRUE or VARIANT_FALSE. On the off chance some neanderthal doesn't understand that with all the buggy COM code out there I generally assume if it isn't VARIANT_FALSE, then it must be true.
So:
HRESULT YourObject::YourComMethod(VARIANT_BOOL* pVarBool)
{
bool bval = (*pVarBool != VARIANT_FALSE); // do this if pVarBool is [in,out]
// bool bval = false; // otherwise do this if pVarBool is [out] only.
callYourNonComMethodHere(&bval);
*pVarBool = bval ? VARIANT_TRUE : VARIANT_FALSE;
return S_OK;
}
After a little clarification from Matt, I think that is what you were trying to do. Or something likely close to it.

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.

API Hook on a COM object function?

Greetings StackOverflowians,
As discovered here, Windows 7 features a bug in which the DISPID_BEFORENAVIGATE2 event does not fire for Windows Explorer instances. This event allows shell extensions to be notified when a navigation is about to take place, and (most importantly for me) have the opportunity to cancel the navigation. I've been looking for a workaround for quite some time, and I think I found one. But, I'd like to get some opinions on how safe it is.
I've been playing with API hooking a lot lately, and I'm already using it to hook a few functions for my extension. I noticed that there is a function in IShellBrowser that controls navigation. At first I thought you couldn't hook something like that, but upon reading about the layout of a COM object I realized it should be possible by just grabbing the right function pointer out of the vtable of any active instance. Sure enough, it works like a dream. After the hook is set, all navigations in all Explorer windows run right through my detour function, and I can decide whether to reject them based on their target pidl.
So my question is, is there any reason I should NOT do this? I've never heard of API hooking used to hook COM object functions. Are there circumstances it which it wouldn't work? Is it dangerous? (Any more than regular API hooking, at least)
The relevant code follows. I'm using MinHook, a minimalistic hooking library that uses the tried-and-true method of trampoline functions.
typedef HRESULT (WINAPI *BROWSEOBJECT)(IShellBrowser*, PCUIDLIST_RELATIVE, UINT);
HRESULT WINAPI DetourBrowseObject(IShellBrowser* _this, PCUIDLIST_RELATIVE pidl, UINT wFlags);
BROWSEOBJECT fpBrowseObject = NULL;
BROWSEOBJECT ShellBrowser_BrowseObject = NULL;
bool Initialize() {
if(MH_Initialize() != MH_OK) {
return false;
}
// Get a reference to an existing IShellBrowser. Any instance will do.
// ShellBrowser enum code taken from The Old New Thing
IShellWindows *psw;
BOOL fFound = FALSE;
if (SUCCEEDED(CoCreateInstance(CLSID_ShellWindows, NULL, CLSCTX_ALL, IID_IShellWindows, (void**)&psw))) {
VARIANT v;
V_VT(&v) = VT_I4;
IDispatch *pdisp;
for (V_I4(&v) = 0; !fFound && psw->Item(v, &pdisp) == S_OK; V_I4(&v)++) {
IWebBrowserApp *pwba;
if (SUCCEEDED(pdisp->QueryInterface(IID_IWebBrowserApp, (void**)&pwba))) {
IServiceProvider *psp;
if (SUCCEEDED(pwba->QueryInterface(IID_IServiceProvider, (void**)&psp))) {
IShellBrowser *psb;
if (SUCCEEDED(psp->QueryService(SID_STopLevelBrowser,IID_IShellBrowser, (void**)&psb))) {
fFound = true;
// Grab the 11th entry in the VTable, which is BrowseObject
void** vtable = (*(void***)(psb));
ShellBrowser_BrowseObject = (BROWSEOBJECT)(vtable[11]);
psb->Release();
}
psp->Release();
}
pwba->Release();
}
pdisp->Release();
}
psw->Release();
}
if(fFound) {
if(MH_CreateHook(ShellBrowser_BrowseObject, &DetourBrowseObject, reinterpret_cast<void**>(&fpBrowseObject)) != MH_OK) {
return false;
}
if(MH_EnableHook(ShellBrowser_BrowseObject) != MH_OK) {
return false;
}
}
return true;
}
HRESULT WINAPI DetourBrowseObject(IShellBrowser* _this, PCUIDLIST_RELATIVE pidl, UINT wFlags) {
if(NavigateIsOkay(pidl, wFlags)) {
return fpBrowseObject(_this, pidl, wFlags);
}
else {
return S_FALSE;
}
}
I've never heard of API hooking used
to hook COM object functions.
Member functions of COM Objects are not really that different and can actually be hooked just fine if you stick to the usual guidelines for hooking. A few years ago, I had to hook COM components of a proprietary CRM solution to connect it to a database server. The application worked fine and has been running quite stable for several years.

Comparing objects with IDispatch to get main frame only (BHO)

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.