How to convert VARIANT_BOOL* to bool* - c++

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.

Related

Calling Release on COM object never appears to return

I'm debugging an intermittent issue on a customer site. I've got it down to the point that it appears that a call to Release() on a COM object is not returning.
The first log is printing but I never see the second log. I can only assume that the call to Release() never returned for some reason (or could it be the CoInitializeEx()).
I have no idea what to look for next, any help/clues would be greatly appreciated.
Logger::getLogger()->logTrace("AudioCapturer::_shutdown. _pEndpointAudioClient_COM Released. (%s)", _deviceName.c_str());
releaseComObject(_pAudioCaptureClient_COM);
Logger::getLogger()->logTrace("AudioCapturer::_shutdown (%s) succeeded", _deviceName.c_str());
Here is the supporting code:
IAudioCaptureClient *_pAudioCaptureClient_COM;
// Class that Initializes COM on creation and Unitializes on destruction
AutoCOM::AutoCOM() { CoInitializeEx(NULL, COINIT_MULTITHREADED); }
AutoCOM::~AutoCOM() { CoUninitialize(); }
#define AUTO_COM_SUPPORT AutoCOM _autoCOM
// Safe releasing of COM objects. Zeros the pointer
// to the COM object. Safe to use with NULL
// pointers.
template <class T> void releaseComObject(T*& pT) {
if (pT) {
AUTO_COM_SUPPORT;
(pT)->Release();
pT = NULL;
}
}
Never found a duplication scenario for the issue. But the problem was averted with the user of smart pointers, which was mentioned by #Cheersandhth.-Alf. Thanks for the feedback.
Basically used the following macro to define smart pointers, and removed all references to Release()
_COM_SMARTPTR_TYPEDEF(IMyInterface, __uuidof(IMyInterface));

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

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.

Under what conditions is CCmdTarget::OnFinalRelease called?

The MSDN documentation for the CCmdTarget::OnFinalRelease method is pretty brief:
Called by the framework when the last OLE reference to or from the
object is released.
I have created a sub-class of CCmdTarget
class CMyEventHandler : public CCmdTarget { ... }
I'm trying to figure out under what conditions the OnFinalRelease method will be called. I have some code that looks something like this:
CMyEventHandler* myEventHandler = new CMyEventHandler();
LPUNKNOWN pUnk = myEventHandler->GetIDispatch(FALSE);
AfxConnectionAdvise(myEventSource, DIID_IMyEventInterface, pUnk, FALSE, myCookie);
// Application continues...events arrive...eventually the event sink is shutdown
LPUNKNOWN pUnk = myEventHandler->GetIDispatch(FALSE);
AfxConnectionUnadvise(myEventSource, DIID_IMyEventInterface, pUnk, FALSE, myCookie);
Using this code, I observe that the OnFinalRelease method is never called. This means I have a memory leak. So I modified the wrap-up code as follows:
LPUNKNOWN pUnk = myEventHandler->GetIDispatch(FALSE);
AfxConnectionUnadvise(myEventSource, DIID_IMyEventInterface, pUnk, FALSE, myCookie);
delete myEventHandler;
myEventHandler = NULL;
This section of code is triggered off periodically throughout the day. What I notice now is that, while the destructor for the wrapped up instance of myEventHandler is called as expected, the OnFinalRelease function is getting called now! What's worse, it is being called not on the instance that has been wrapped up, but instead on a newly created instance of CMyEventHandler! Thinking that this might be due to a reference counting issue, I modified my wire-up and wrap-up code:
CMyEventHandler* myEventHandler = new CMyEventHandler();
LPUNKNOWN pUnk = myEventHandler->GetIDispatch(TRUE);
AfxConnectionAdvise(myEventSource, DIID_IMyEventInterface, pUnk, TRUE, myCookie);
pUnk->Release();
// Application continues...events arrive...eventually the event sink is shutdown
LPUNKNOWN pUnk = myEventHandler->GetIDispatch(TRUE);
AfxConnectionUnadvise(myEventSource, DIID_IMyEventInterface, pUnk, TRUE, myCookie);
pUnk->Release();
delete myEventHandler;
myEventHandler = NULL;
I let this run all day and now observe that OnFinalRelease is never called. The destructor for the wrapped up instance is called as I would expect, but I'm left feeling uneasy as I clearly don't understand the circumstances under which OnFinalRelease is called. Is OnFinalRelease called on some delay, or is there a way to force it to fire? What will trigger OnFinalRelease to be called?
If it matters, the event source is a .NET assembly exposing events via COM interop.
With COM you should always use the CoCreateInstance() AddRef() and Release() paradigm to manage lifetime of your objects, and let COM do the destruction of your objects based on reference counts. Avoid new and delete because using them breaks this paradigm and causes interesting side effects. You probably have a bug in the management of the reference counts.
The way to debug why the reference counts are not being managed correctly is to override CCmdTarget::InternalRelease() copy the source from oleunk.cpp and put some trace output or break points.
DWORD CMyEventHandler::InternalRelease()
{
ASSERT(GetInterfaceMap() != NULL);
if (m_dwRef == 0)
return 0;
LONG lResult = InterlockedDecrement(&m_dwRef);
if (lResult == 0)
{
AFX_MANAGE_STATE(m_pModuleState);
OnFinalRelease();
}
return lResult;
}
There are lots of times when passing IDispatch interfaces that code will bump reference counts and you have to decrement the reference count using Release(). Pay attention to where your code may be passing this interface because there is aconvention in COM that when Interfaces are passed using [in] or [out] where the caller or callee has to release the interface.
When the reference count issue is corrected you shoudl see the objects OnFinalRelease code being called and the object destoryed by hte MFC framework:
For CCmdTarget the destruction should happen as a result of the final
release in the parent class CWnd:
void CWnd::OnFinalRelease()
{
if (m_hWnd != NULL)
DestroyWindow(); // will call PostNcDestroy
else
PostNcDestroy();
}
FYI: Passing interfaces across threads without marshalling the interface pointers is another common reason to get errors in COM.
It doesn't appear that you ever call myEventHandler->Release(). Therefore, the last reference is never released, and OnFinalRelease is never called.

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.