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).
Related
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)
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());
}
I make an OCX in C++ Builder Borland. My OCX has these function as I describe it:
Login
Write
Read
DebugOutput
GetVal
I am using this OCX in my c# application. In c# side I have a button and list box. The button calls login method from OCX and the list box shows this method's output.
In OCX side, the login method creates a command for server (with socket programming) to get authentication. Then call Write function to writes on socket. Then gets response from socket and calls Read function to reads the socket response.
The Read method reading the result and send it to DebugOutput to debug the output stream and call GetVal to find Last main server response. Then they pass their parameters to each other. after all the C# side show the result (SUCCESS | FAIL ) for login methods.
I used BSTR. (I read the topics about BSTR in stackoverflow and on MSDN but I think I did not get it well in my solution). These are my code in OCX side:
BSTR STDMETHODCALLTYPE TVImpl::Login(BSTR PassWord)
{
wchar_t wcs1[500];
Var *var=new Var();
//here make the command
...................
//get the server response to show to user
BSTR read=::SysAllocString(Write(wcs1));
if(read!=NULL) ::SysFreeString(read);
return read;
}
BSTR STDMETHODCALLTYPE TVImpl::Read()
{
BSTR str ;
try
{
IdTCPClient1->ReadTimeout=100;
str =::SysAllocString( IdTCPClient1->IOHandler->ReadLn().c_str());
}
catch(Exception &e)
{
str= e.Message.c_str();
}
str=(DebugOutput(str));
return str;
}
BSTR STDMETHODCALLTYPE TVImpl::Write(BSTR str)
{
IdTCPClient1->IOHandler->WriteLn(str) ;
BSTR str2=::SysAllocString(L"TST");
str2=Read();
return str2;
}
BSTR STDMETHODCALLTYPE TVImpl::GetVal(BSTR st,BSTR ValTyp)
{
BSTR res;
AnsiString stAnsi;
//Do some thing with st and save it to stAnsi
.................
res=(BSTR)WideString(stAnsi);
return ::SysAllocString(res);
}
BSTR STDMETHODCALLTYPE TVImpl::DebugOutput(BSTR st)
{
Var *val=new Var();
BSTR res;
res=GetVal(st,val->CMD_CMD);
if(res==val->CMD_AUTHENTICATE)
res=GetVal(st,val->XPassword);
return res;
}
In C3 code it was hanging. I know my problem is to use sysAllocString. but I when I used ::sysFreestring for each one in each method again my C# code hanging.
This is my C# code :
private void button4_Click(object sender, EventArgs e)
{
VinSockCmplt.Vin vin = new Vin();
listBox1.Items.Add(vin.Login("1234"));
}
You should not return BSTR (or any "complex" type that various compilers compile in various ways). The recommended return type for COM methods is HRESULT (a 32-bit integer). Also, you must not release a BSTR you just allocated and return it to the caller.
Here is how you could layout your methods:
HRESULT STDMETHODCALLTYPE TVImpl::Login(BSTR PassWord, /*out*/ BSTR *pRead)
{
...
*pRead = ::SysAllocString(L"blabla"); // allocate a BSTR
...
// don't SysFreeString here, the caller should do it
...
return S_OK;
}
If you were defining your interface in a .idl file, it would be something like:
interface IMyInterface : IUnknown
{
...
HRESULT Login([in] BSTR PassWord, [out, retval] BSTR *pRead);
...
}
retval is used to indicate assignment semantics are possible for languages that support it, like what you were trying to achieve initially with code like this var read = obj.Login("mypass")
There are lots of mistakes in your code:
if(read!=NULL) ::SysFreeString(read); return read; frees a string and then returns it
str= e.Message.c_str(); ... return str; returns a pointer to something that isn't even a BSTR
BSTR str2=::SysAllocString(L"TST"); str2=Read(); allocates a string and then leaks that string immediately
res=(BSTR)WideString(stAnsi); creates a dangling pointer
All of these are undefined behaviour (except the leak) and might cause a crash.
Also, I'm not sure if it is valid to have your functions return BSTR; the normal convention in COM programming is that functions return HRESULT and any "return values" go back via [out] parameters. This is compatible with all languages that have COM bindings; whereas actually returning BSTR limits your code compatibility. (I could be wrong - would welcome corrections here). You can see this technique used in the other question you linked.
To get help with a question like "Why is my code crashing?", see How to Ask and How to create a Minimal, Complete, and Verifiable example.
We have a COM API for our application (which is written in VC++) which exposes a few functionalities so that the users can automate their tasks. Now, I'm required to add a new method in that, which should return a list/array/vector of strings. Since I'm new to COM, I was looking at the existing methods in the .idl file for that interface.
One of the existing methods in that idl file looks like this:
interface ITestApp : IDispatch
{
//other methods ..
//...
//...
//...
[id(110), helpstring("method GetFileName")] HRESULT GetFileName([out, retval] BSTR *pFileName);
//...
//...
//...
};
My task is to write a similar new method, but instead of returning one BSTR string, it should return a list/array/vector of them.
How can I do that?
Thanks!
Since yours is an automation-compatible interface, you need to use safearrays. Would go something like this:
// IDL definition
[id(42)]
HRESULT GetNames([out, retval] SAFEARRAY(BSTR)* names);
// C++ implementation
STDMETHODIMP MyCOMObject::GetNames(SAFEARRAY** names) {
if (!names) return E_POINTER;
SAFEARRAY* psa = SafeArrayCreateVector(VT_BSTR, 0, 2);
BSTR* content = NULL;
SafeArrayAccessData(psa, (void**)&content);
content[0] = SysAllocString(L"hello");
content[1] = SysAllocString(L"world");
SafeArrayUnaccessData(psa);
*names = psa;
return S_OK;
}
Error handling is left as an exercise for the reader.
I came across a problem in my code today where an access violation was being caused, AFAICT, by casting a COM object of mine to an IUnknown**. The function it was passed into executed without a problem but when calling one of my object's functions it would execute some random function and corrupt the stack then die.
Indicative code (just ignore why it's done this way - I know it's bad and I know how to fix it but this is a question of why problems like this may occur):
void MyClass2::func(IMyInterface* pMyObj)
{
CComPtr<IMyInterface2> pMyObj2;
HRESULT hRes = pMyObj->GetInternalObject((IUnknown**)&pMyObj2);
if (SUCCEEDED(hRes))
pMyObj2->Function(); // corrupt stack
}
void MyClass::GetInternalObject(IUnknown** lpUnknown)
{
pInternalObject->QueryInterface(IID_IMyInterface2, (void**)lpUnknown);
}
I have always been a bit suspicious of using C/C++ casts on COM objects but I've never encountered (possibly through undefined behaviour) any problems until now.
I had a quick look and from what I can tell casting to IUnknown is technically valid so long as there is no multiple interitance in the inheritance chain, however it is not considered best practice - I should really pass an IUnknown to MyClass::GetInternalObject(IUnknown** lpUnknown) and then query the return value for the interface I want.
My question is, are there rules as to when C/C++ casts can be used on COM objects, and aside from multiple inheritance and the adjustor thunks they bring, how can casting COM objects result in surprises like access violations? Please be detailed.
Edit: They're all good examples of how it should be done properly but what I was hoping for was a technical explanation of why you shouldn't cast COM objects (assuming one exists) e.g. casting will return pMyObj2-4 in situation x but QueryInterface will return pMyObj2-8 because of y...or is casting COM objects simply a matter of bad practice/style?
TIA
I'd just use CComPtr and CComQIPtr to manage COM interfaces, instead of writing code with C-style casts that to me seem inappropriate in the context of COM:
void MyClass2::Func(IMyInterface* pMyObj)
{
// Assuming:
// HRESULT IMyInterface::GetInternalObject( /* [out] */ IUnknown** )
CComPtr<IUnknown> spUnk;
HRESULT hr = pMyObj->GetInternalObject(&spUnk);
if (SUCCEEDED(hr))
{
// Get IMyInterface2 via proper QueryInterface() call.
CComQIPtr<IMyInterface2> spMyObj2( spUnk );
if ( spMyObj2 )
{
// QueryInterface() succeeded
spMyObj2->Function();
}
}
}
Moreover, I'm not a COM expert, but I see with suspicion your code:
void MyClass::GetInternalObject(IUnknown** lpUnknown)
{
pInternalObject->QueryInterface(IID_IMyInterface2, (void**)lpUnknown);
}
If you are QueryInterface()'ing IID_MyInterface2, you should store that in an IMyInterface2*, not in an IUnknown*.
If your method returns an IUnknown*, then I'd QueryInterface() an IID_IUnknown:
// NOTE on naming convention: your "lpUnknown" is confusing.
// Since it's a double indirection pointer, you may want to use "ppUnknown".
//
void MyClass::GetInternalObject(IUnknown** ppUnknown)
{
pInternalObject->QueryInterface(IID_IUnknown, (void**)ppUnknown);
}
or better use IID_PPV_ARGS macro:
void MyClass::GetInternalObject(IUnknown** ppUnknown)
{
IUnknown* pUnk = NULL;
HRESULT hr = pInternalObject->QueryInterface(IID_PPV_ARGS(&pUnk));
// Check hr...
// Write output parameter
*ppUnknown = pUnk;
}
COM style casts have a specific name: QueryInterface().
I think the issue is that because a cast from IMyInterface* to IUnknown* is OK (in COM everything inherits from IUknown right?) you think that a cast from IMyInterface** to IUnknown** is also OK. But that's not true in C++, and I doubt it's true in COM either.
To me the following looks more logical, apologies if this isn't strictly correct, my COM is very rusty, but hopefully you get the idea.
CComPtr<IUnknown> pMyObj2;
HRESULT hRes = pMyObj->GetInternalObject(&pMyObj2);
if (SUCCEEDED(hRes))
{
CComPtr<IMyInterface> pMyObj3 = (IMyInterface*)pMyObj2;
pMyObj3->Function();
}
I.e. get an IUnknown object first, and then down cast that to your actual type.
I don't see any issues in your code snippets, the stack corruption perhaps has its cause but its somewhere else.
I don't think it is your actual code because GetInternalObject should be of HRESULT type and yours is not, so you lost something during copy/pasting.
To stay safer, just avoid direct QueryInterface calls because together with casting they might misinterpret interfaces. Casting to and from IUnknown* might be inevitable though. If the callee cannot be trusted to return proper interface casted to IUnknown, on the caller side you might prefer to QI once again to make sure you hold the interface of your interest.
Provided that GetInternalObject is a COM interface method on its own, you could have it like this:
void MyClass2::func(IMyInterface* pMyObj)
{
CComPtr<IUnknown> pMyObj2Unknown;
pMyObj->GetInternalObject((IUnknown**)&pMyObj2Unknown);
CComQIPtr<IMyInterface2> pMyObj2 = pMyObj2Unknown; // This is only needed if callee is not trusted to return you a correct pointer
if (pMyObj2)
pMyObj2->Function(); // corrupt stack
}
STDMETHODIMP MyClass::GetInternalObject(IUnknown** lpUnknown) // COM method is typically both HRESULT and __stdcall
{
CComQIPtr<IMyInterface2> pMyInterface2 = pInternalObject;
if(!pMyInterface2)
return E_NOINTERFACE;
*lpUnknown = pMyInterface2.Detach(); // *lpUnknown will have to me IMyInterface2 this way
return S_OK;
}
PS If GetInternalObject was a native method, not COM, you would avoid casting to IUnknown* at all.