Why is this dynamic_cast<T> not working? - c++

This should be quite simple. ID2D1LinearGradientBrush derives from ID2D1Brush with a valid vtable. I realize QueryInterface would work here, however my question pertains to dynamic_cast.
[definition from d2d1.h]
interface DX_DECLARE_INTERFACE("2cd906ab-12e2-11dc-9fed-001143a055f9")
ID2D1LinearGradientBrush : public ID2D1Brush
{
// ....
}
However, given the over-simplified example functions ...
bool ClampToItem(ID2D1Brush *brush, SizeF itemSize)
{
// As expected, works when a linear gradient brush is the parameter.
ID2D1LinearGradientBrush *linearGradientBrush = static_cast<ID2D1LinearGradientBrush *>(brush);
linearGradientBrush->SetStartPoint(D2D1_POINT_2F{ itemSize.Width, 0.0f });
linearGradientBrush->SetEndPoint(D2D1_POINT_2F{ itemSize.Width, itemSize.Height });
return true;
}
bool ClampToItem2(ID2D1Brush *brush, SizeF itemSize)
{
// this dynamic cast FAILS EVERY TIME with an access violation
ID2D1LinearGradientBrush *linearGradientBrush = dynamic_cast<ID2D1LinearGradientBrush *>(brush);
if (!linearGradientBrush) // <-- never gets here
return false;
linearGradientBrush->SetStartPoint(D2D1_POINT_2F{ itemSize.Width, 0.0f });
linearGradientBrush->SetEndPoint(D2D1_POINT_2F{ itemSize.Width, itemSize.Height });
return true;
}
Since I will not be certain that a ID2D1LinearGradientBrush will be provided as a parameter, I would like to use a dynamic_cast. I must be missing something simple. Do these COM objects not contain RTTI info? Thank you for your help.
// For clarification, this works as expected
bool ClampToItem3(ID2D1Brush *brush, SizeF itemSize)
{
ID2D1LinearGradientBrush *linearGradientBrush;
HRESULT hr = brush->QueryInterface(__uuidof(ID2D1LinearGradientBrush), (void **)&linearGradientBrush);
if (hr == S_OK)
{
linearGradientBrush->SetStartPoint(D2D1_POINT_2F{ itemSize.Width, 0.0f });
linearGradientBrush->SetEndPoint(D2D1_POINT_2F{ itemSize.Width, itemSize.Height });
linearGradientBrush->Release();
linearGradientBrush = nullptr;
}
return true;
}
EDIT:
Tracing into the dynamic cast (into rtti.cpp):
extern "C" PVOID __CLRCALL_OR_CDECL __RTDynamicCast(
PVOID inptr, // Pointer to polymorphic object
LONG VfDelta, // Offset of vfptr in object
PVOID SrcType, // Static type of object pointed to by inptr
PVOID TargetType, // Desired result of cast
BOOL isReference) // TRUE if input is reference, FALSE if input is ptr
throw(...)
is called, inptr is valid, vfDelta is 0, SrcType and TargetType look great, isRef says false.
Tracing further, the memory access violation occurs here:
// Ptr to CompleteObjectLocator should be stored at vfptr[-1]
_RTTICompleteObjectLocator *pCompleteLocator =
(_RTTICompleteObjectLocator *) ((*((void***)inptr))[-1]);
char *pCompleteObject = (char *)inptr - COL_OFFSET(*pCompleteLocator);
since *pCompleteLocator was moved to an invalid location.

Standard COM interfaces from Microsoft use __declspec(novtable) as part of their definition; if you look at the definition of DX_DECLARE_INTERFACE you'll see this is the case here. This means that the base interface classes don't have vtables, only the concrete implementation has one. RTTI doesn't have the necessary information for dynamic_cast to work properly.
For COM interfaces you should always use QueryInterface to do dynamic casting.

Related

C++ casting Windows IAction

I'm working on retrieving some info from windows task scheduler.
MSDN indicates there are several types of action. I want to deal with them separately. I tried:
IAction* pAction = NULL;
pActionCollection->get_Item(_variant_t(i), &pAction);
if (IExecAction* pExecAction = dynamic_cast<IExecAction*>(pAction)) { /*my work...*/ }
if (IComHandlerAction* pComHandlerAction = dynamic_cast<IComHandlerAction*>(pAction)) { /*my work...*/ }
if (IEmailAction* pEmailAction = dynamic_cast<IEmailAction*>(pAction)) { /*my work...*/ }
if (IShowMessageAction* pShowMessageAction = dynamic_cast<IShowMessageAction*>(pAction)) { /*my work...*/ }
But this program throws exception at the first dynamic_cast.
Exception thrown at 0x00007FFB516365A5 (vcruntime140d.dll) in myProgram.exe: 0xC0000005: Access violation reading location 0x00000130BAFEDB04.
The definition in taskschd.h shows IExecAction is a derived class from IAction.
This works well:
if (IExecAction* pExecAction = ((IExecAction*)pAction)) { /*my work...*/ }
But what if I want to do some type checking?
How could I use it properly?
for get pointer of com interface from another com interface on the same object we need use only QueryInterface method, which is always implemented by any interface. so code in your case need to be next:
IAction* pAction;
IExecAction* pExecAction;
IEmailAction* pEmailAction;
HRESULT hr;
if (SUCCEEDED(hr = pAction->QueryInterface(IID_PPV_ARGS(&pExecAction))))
{
// use pExecAction
pExecAction->Release();
}
if (SUCCEEDED(hr = pAction->QueryInterface(IID_PPV_ARGS(&pEmailAction))))
{
// use pExecAction
pEmailAction->Release();
}
even if one interface inherit from another use c/c++ cast is always wrong. for example
pExecAction = static_cast<IExecAction*>(pAction);
pEmailAction = static_cast<IEmailAction*>(pAction);
this code is correct from c++ syntax, because both IExecAction : IAction and IEmailAction : IAction inherit from IAction. and this cast (if take to account layout of this 3 interfaces) give you equal binary values for pExecAction and pEmailAction. but pExecAction can not have the same binary value as pEmailAction. must be
assert((void*)pEmailAction != (void*)pExecAction);
why ? because have pEmailAction and pExecAction have different virtual functions at the same position in vtable. for example on the 10-th position in the table of IExecAction must be pointer to get_Path method. from another side on the 10-th position in the table of IEmailAction must be pointer to get_Server method. if (void*)pEmailAction == (void*)pExecAction - they will be have the same pointers to vtable. but pointer to which function - get_Path or get_Server will be in the 10-th position ? as result pointer to this 2 interfaces can not be the same (point to the same memory). so how minimum one static_cast here (may be and both) give wrong result. for understand how QueryInterface work and why pointers to pExecAction and pEmailAction wiil be different - we need look for implementation. implementation of interfaces - this is some class, which inherit (usually) from all this interfaces and implement it like this:
class CAction : IExecAction, IEmailAction
{
virtual ULONG STDMETHODCALLTYPE AddRef( );
virtual HRESULT STDMETHODCALLTYPE QueryInterface( REFIID riid, void **ppvObject)
{
PVOID pvObject;
if (riid == __uuidof(IAction))
{
pvObject = static_cast<IExecAction*>(this);
// or can be
pvObject = static_cast<IEmailAction*>(this);
}
else if (riid == __uuidof(IExecAction))
{
pvObject = static_cast<IExecAction*>(this);
}
else if (riid == __uuidof(IEmailAction))
{
pvObject = static_cast<IExecAction*>(this);
}
else
{
*ppvObject = 0;
return E_NOINTERFACE;
}
*ppvObject = pvObject;
AddRef();
return S_OK;
}
};
look that static_cast<IExecAction*>(this); will always give another binary value compare static_cast<IEmailAction*>(this); - the CAction will be containing 2 different vtables - one for IExecAction and one for IEmailAction. they have common initial part (9 entries) but then different. and static_cast<IExecAction*>(this); and static_cast<IEmailAction*>(this); return 2 different (always) pointers to this 2 different vtables. when for IAction* we select return or first or second vtable pointer. both will be correct. what pointer return implementation - we can not know (the layout of actual class which implement IExecAction, IEmailAction is unknown for us)

pass ref class object(Uri^) as native pointer parameter(IUriRuntimeClass *)

I have following midl method in my code:
interface IMyClass : IInspectable
{
HRESULT Func1([in] Windows.Foundation.Uri *uri);
}
It generates following interface method:
IMyClass : public IInspectable
{
public:virtual HRESULT STDMETHODCALLTYPE Func1(
/* [in] */ __RPC__in_opt ABI::Windows::Foundation::IUriRuntimeClass *uri) = 0;
}
The interface is implemented in App side and its object is passed to my code where I can 'see' only interface.
I want to know what is the best way to call Func1 and pass Windows::Foundation::Uri object as parameter?
Simply passing ref class object does not not work, due to C2664 error
Windows::Foundation::Uri^ u = ref new Uri(...);
IMyClassObj->Func1(u); // error cannot convert argument 1 from Windows::Foundation::Uri ^' to 'ABI::Windows::Foundation::IUriRuntimeClass *
I could achive my goal with reintrepret_casting:
Windows::Foundation::Uri^ u = ref new Uri(...);
ABI::Windows::Foundation::IUriRuntimeClass* uu = reinterpret_cast<ABI::Windows::Foundation::IUriRuntimeClass*>(u);
MyClassObj->Func1(u); // this works fine
Is reinterpret_cast right approach in this situation? Or is there any other way of passing Uri^ object as IUriRuntimeClass* parameter?
A slightly cleaner way to do this is to wrap it in a ComPtr as soon as possible so you get the right behaviour if any exceptions are thrown etc. (Your method might be simple today, but it could get more complex later on).
Something like this:
#include <wrl/client.h>
#include <windows.foundation.h>
// Dummy method that just prints out the URI to the debug console
HRESULT MyFunc(ABI::Windows::Foundation::IUriRuntimeClass* uri)
{
HSTRING str{};
HRESULT ret{ S_OK };
if (SUCCEEDED(ret = uri->get_AbsoluteUri(&str)))
OutputDebugString(WindowsGetStringRawBuffer(str, nullptr));
WindowsDeleteString(str);
return ret;
}
void Test()
{
using namespace Microsoft::WRL;
// Create the ref class
auto uri = ref new Windows::Foundation::Uri(L"http://www.bing.com");
// Wrap in a dummy IUnknown wrapper. In theory you could use
// IInspectable or even IUriRuntimeClass but if you're going to
// copy-paste the code elsewhere, IUnknown is the "safest" thing you
// can reinterpret_cast<>() to.
ComPtr<IUnknown> iUnknown{ reinterpret_cast<IUnknown*>(uri) };
// Try to cast it to the IUriRuntimeClass, and call our method if
// it succeeds
ComPtr<ABI::Windows::Foundation::IUriRuntimeClass> iUri{};
if (SUCCEEDED(iUnknown.As(&iUri)))
MyFunc(iUri.Get());
}

C++ Visual Studio 2015 “non-standard syntax; use '&' to create a pointer to member”

I work with TaskScheduler COM, this is my code:
typedef HRESULT(*FuncOfBoll)(_Out_ VARIANT_BOOL* b);
static bool GetBool(FuncOfBoll func)
{
VARIANT_BOOL b = VARIANT_FALSE;
HRESULT hr = func(&b);
if (FAILED(hr)) return FALSE;
return b == VARIANT_TRUE;
}
void test(ITaskSettings* settings)
{
bool b = GetBool(settings->get_StopIfGoingOnBatteries); // <= The error here
// ...
}
and I get the following error:
Error C3867 'ITaskSettings::get_StopIfGoingOnBatteries': non-standard
syntax; use '&' to create a pointer to member
What is my mistake and how to correct it?
I am guessing that get_StopIfGoingOnBatteries is a member function ofITaskSettings. Such a function cannot be used when the expected argument type is FuncOfBoll. You'll need to create a wrapper function and use it.
ITaskSettings* currentSetttings = NULL;
HRESULT GetBoolWrapper(_Out_ VARIANT_BOOL* b)
{
return currentSetttings->get_StopIfGoingOnBatteries(b);
}
void test(ITaskSettings* settings)
{
currentSetttings = settings;
bool b = GetBool(GetBoolWrapper);
}
The correct definition for a pointer to member function is:
typedef HRESULT(ITaskSettings::*FuncOfBoll)(_Out_ VARIANT_BOOL* b);
Then, you should pass the pointer to the object instance to function GetBool:
static bool GetBool(ITaskSettings* setting, FuncOfBoll func)
{
VARIANT_BOOL b = VARIANT_FALSE;
HRESULT hr = (setting->*func)(&b);
...
}
Or, with template:
template<class C>
static bool GetBool(C* p, HRESULT(C::*func)(_Out_ VARIANT_BOOL*))
{
VARIANT_BOOL b = VARIANT_FALSE;
HRESULT hr = (p->*func)(&b);
...
}
Invocation:
void test(ITaskSettings* settings)
{
currentSetttings = settings;
bool b = GetBool(settings, &ITaskSettings::mb_function);
}
This is not really an answer, the question as written doesn't admit an answer, but this is too long & detailed for comment.
You don't show a full examples, so there has to be guesswork.
Apparently, judging by the error message, settings is a pointer to class type object, where that class has a member function get_StopIfGoingOnBatteries.
And apparently, judging by the use of -> operator, it's a non-static member function. You could still use -> if it were static, but that would be unnatural. So let's say it's a non-static member function.
Then you can't easily form a raw pointer to function that calls that member function, because you need a this-pointer for the call. It could just use a dummy object, if creation of such object is cheap, or it could use a global instance or pointer to instance. But better change something in your design, and/or explain more clearly what you want.

What is the difference between COM property methods and regular interface methods?

I have been poking around with WRL at the ABI layer for the last couple of weeks and have run into this problem.
I have an interface defined in IDL as follows:
namespace Async{
[uuid(f469e110-7ef5-41df-a237-9ddef9aed55c), version(1.0)]
interface IDownloader : IInspectable
{
HRESULT GetFeed([in] HSTRING url,[out, retval] Windows.Web.Syndication.SyndicationFeed ** feed);
[propget]HRESULT Feed([out, retval]Windows.Web.Syndication.SyndicationFeed ** feed);
}
[version(1.0), activatable(1.0)]
runtimeclass Downloader
{
[default] interface IDownloader;
}
}
Which I have defined in my header file like so:
#pragma once
#include "Async_h.h"
namespace ABI {
namespace Async {
class Downloader : public Microsoft::WRL::RuntimeClass<ABI::Async::IDownloader>
{
InspectableClass(L"Async.Downloader", BaseTrust);
public:
Downloader();
STDMETHOD(GetFeed)(HSTRING url, ABI::Windows::Web::Syndication::ISyndicationFeed ** feed);
STDMETHOD(get_Feed)(ABI::Windows::Web::Syndication::ISyndicationFeed ** feed);
private:
//Microsoft::WRL::ComPtr<ABI::Windows::Foundation::Uri> feedUrl;
Microsoft::WRL::ComPtr<ABI::Windows::Web::Syndication::ISyndicationFeed> m_feed;
};
ActivatableClass(Downloader);
}
}
In my cpp file I implement the functions:
STDMETHODIMP Downloader::GetFeed(HSTRING url, ISyndicationFeed** feed)
{
HRESULT hr;
RoInitializeWrapper ro(RO_INIT_MULTITHREADED);
ComPtr<IUriRuntimeClass> uri;
ComPtr<IUriRuntimeClassFactory> uriFactory;
hr = GetActivationFactory(HStringReference(RuntimeClass_Windows_Foundation_Uri).Get(), &uriFactory);
hr = uriFactory->CreateUri(url, uri.GetAddressOf());
ComPtr<ISyndicationClient> client;
ComPtr<IInspectable> inspectable;
RoActivateInstance(HStringReference(RuntimeClass_Windows_Web_Syndication_SyndicationClient).Get(), &inspectable);
hr = inspectable.As(&client);
Event timerCompleted(CreateEventEx(nullptr, nullptr, CREATE_EVENT_MANUAL_RESET, WRITE_OWNER | EVENT_ALL_ACCESS));
auto callback = Callback<IAsyncOperationWithProgressCompletedHandler<SyndicationFeed*,RetrievalProgress>>([&](IAsyncOperationWithProgress<SyndicationFeed*,RetrievalProgress> *op, AsyncStatus status) ->HRESULT
{
auto error = GetLastError();
if (status == AsyncStatus::Completed)
{
hr = op->GetResults(m_feed.GetAddressOf());
*feed = m_feed.Get();
}
return S_OK;
});
ComPtr<IAsyncOperationWithProgress<SyndicationFeed*,RetrievalProgress>> operation;
hr = client->RetrieveFeedAsync(uri.Get(), operation.GetAddressOf());
operation->put_Completed(callback.Get());
return S_OK;
}
STDMETHODIMP Downloader::get_Feed(ISyndicationFeed** feed)
{
*feed = m_feed.Get();
return S_OK;
}
The property works as expected it is projected to c++/cx as it should be. However,in the GetFeed method, when I attempt to set the feed parameter to the retrieved feed I get an access violation. Obviously I know that the memory is bad but the way I understand COM properties, they are essentially function calls and the property method and the GetFeed method are doing exactly the same thing minus the retrieval part.
Here are my questions:
What is the difference between COM property methods and regular interface methods in terms of the projected return value if any?
Why is the parameter to the property method initialized to nullptr and the parameter to the GetFeed Method not when they are described exactly the same in IDL?
If the out parameters in property methods are initialized, what part of the COM runtime is doing that for me and is that controllable? IE is there a way to get memory that I can write to passed to me?
I know that I could probably design that away but that is not the point. I am just trying to learn how it all works.
Thanks.
In your lambda you are capturing by reference with [&]. You need to capture the feed parameter by value, since the stack frame is long gone by the time your lambda executes.
The bigger issue is that the client has no idea when they can retrieve the results since you don't provide that information. (I see you create an unused Win32 Event object, so maybe there's some other code to make that work that you've deleted).

Having problems getting idl declaration with pointer to vector for a getter

I am trying to specify a vector in an IDL specification of property getter.
I am new to C++ so bear with me. The object IThis is a hypothetical object of anything.
I am getting a compile error at the id declaration expecting a type specifier. Thank you very much!!!!!!!!!!!!!!!
STDMETHOD(get_ThisList)(vector<IThis*> *value)
{
*value = mThisList;
return S_OK;
}
vector<IThis*> mThisList;
[propget] IDLAPI ThisList([out,retval] vector<IThis*>* value);
You can't use vector in a COM interface, with IDL or otherwise. You could return a safearray of interface pointers; it would look like this:
// In IDL
[propget]
HRESULT ThisList([out,retval] SAFEARRAY(IThis*)* value);
// In C++
HRESULT get_ThisList(SAFEARRAY** value);
Other alternatives include a conformant array (though this is inadvisable for an automation interface, as yours appears to be), and a separate collection object that represents a list of objects.
An implementation for get_ThisList might look something like this:
STDMETHODIMP MyObject::get_ThisList(SAFEARRAY** value) {
if (!value) return E_POINTER;
SAFEARRAYBOUND bound = {mThisList.size(), 0};
*value = SafeArrayCreate(VT_UNKNOWN, 1, &bound);
IUnknown** data;
SafeArrayAccessData(*value, (void**)&data);
for (int i = 0; i < mThisList.size(); ++i) {
(data[i] = mThisList[i])->AddRef();
}
SafeArrayUnaccessData(*value);
return S_OK;
}
Error handling is left as an exercise for the reader.
std::vector is a C++ class; IDL (interface definition language - different language) has no concept of it.
"expecting a type specifier" means the IDL compiler doesn't recognize std::vector as a type.
You will have to return a pointer to array of IThis as the return value, and put it into a smarter object at the caller's site.