How to send list through COM - c++

Can I send a list of objects through COM?
I have my class and there is also a list of this class. And I need to send this through a COM function. Can I do that? If yes, then how? Do I need serialization marshaling?

COM does not pin down any particular collection type, it certainly doesn't have anything standard that models a list. By convention, you can model any collection with an interface. So say you have a collection of Foo objects that each implement IFoo. Then declare an IEnumFoo interface similar to:
interface IEnumFoo : IUnknown
{
HRESULT Next( [in] ULONG celt,
[out, size_is(celt), length_is(*pceltFetched)] IFoo **rgelt,
[in,out,unique] ULONG *pceltFetched );
HRESULT Skip( [in] ULONG celt);
HRESULT Reset();
HRESULT Clone( [out] IEnumFoo **ppenum );
}
And then simply return an interface pointer to an implementation of this interface to allow the client code to enumerate the list. Check the MSDN docs for IEnumVARIANT, a very common enumeration interface type for variants. Which also explains what the methods do.

If one side of the interface will be written in a language with a "simpler" type system, such as VB6 or script, then the SAFEARRAY is the way to go. COM's universal marshaller can take care of it.
If you have C++ on both sides of the interface, and you're happy to define the interface in IDL, and generate custom marshalling code, then IDL includes a "size_is" attribute that can be used. See here for details.

To any reasonable degree, there's no way to do so with std::list. I'm sure there is some maniac who could manage it but from my experience, it's not worth it. If doesn't have to be an std::list and just some linked list, then you'll have to either define a new COM interface and provide it's implementation (which can just be a wrapper around std::list) or find some thirdparty resource that has an adequate implementation for your purposes. If you don't have much experience with implementing COM interfaces, then you'll need to do some good amount of reading.
If it can be an array, then you can make your life a lot simpler by using a SAFEARRAY. And SAFEARRAYs can be easier to use with ATL's CComSafeArray, which is pretty much a wrapper. It tries to help/save you from issues, such as reference counting, when dealing with COM objects. You can then just pass the array between your COM objects. Just going to remind you that you still need to pay attention to who is responsible for de-allocating the memory.

Related

Why do CoMarshalInterface and CoUnmarshalInterface need REFIID?

I am a noob regarding COM. In the project that I am currently working we use CoMarshalInterface and CoUnmarshalInterface with REFIID of IDispatch for all the COM object/proxy instances because they are all derived from it.
I wanted to template the code and use it with the most derived COM interfaces and that sparked a discussion in the team as it might introduce unintended/unforeseen changes. From testing, I did not see any differences, but it's still a bit curious that these functions need a REFIID parameter.
So my questions are as follows:
Why do CoMarshalInterface and CoUnmarshalInterface need the REFIID parameter? In the docs [1] MS says they query the object for IMarshal and if not found they fallback to the default COM implementation
Is there any difference between calling these functions with IDispatch vs most derived interfaces (which we know are derived from IDispatch)? The scenario put forward was maybe some interfaces do implement IMarshal, but the implementations might have problems. In that case, wouldn't the object reply to the QueryInterface with IMarshal regardless of the functions being called with IDispatch or most derived?
[1] https://learn.microsoft.com/en-us/windows/win32/api/combaseapi/nf-combaseapi-comarshalinterface#remarks

Removing smart pointers [duplicate]

This question already has an answer here:
What does ComPtr.As() do?
(1 answer)
Closed 2 years ago.
I'm testing some code examples for a CLR project. What would be this code equivalent without using smart pointers?
Microsoft::WRL::ComPtr<ID3D11Device1> m_d3dDevice;
Microsoft::WRL::ComPtr<IDXGIDevice1> dxgiDevice;
...
m_d3dDevice.As(&dxgiDevice);
I tried something like this, but I'm not sure if it's ok.
ID3D11Device1* m_d3dDevice;
IDXGIDevice1* dxgiDevice;
...
dxgiDevice = reinterpret_cast<IDXGIDevice1*>(m_d3dDevice);
These are COM object pointers.
I am not sure why you would not want to use a COM smart pointer template class. They eliminate most reference counting issues that can drive you crazy. And they have almost zero overhead.
As such, you can use the ComPtr class or the legacy CComPtr from ATL as your smart ptr template type to automatically handle Addref, Release, and QueryInterface calls for yourself. You can also roll your own smart pointer classes, but ComPtr/CComPtr are very efficiently written.
The rules of COM basically often break when you try to cast between interfaces without using QueryInterface. The actual concrete implementation is probably a C++ class with multiple inheritance from many interfaces. As such, casting between interfaces is probably a shift in the pointer value. But the compiler can't infer that from base class interfaces only. Also, many COM classes cheat this by having QueryInterface return an entirely different object.
So, instead of this:
dxgiDevice = reinterpret_cast<IDXGIDevice1*>(m_d3dDevice);
This is probably all you need:
HRESULT hr = m_d3dDevice->QueryInterface(&dxgiDevice);
Some legacy SDKs don't have the template overload for IUnknown::QueryInterface that eliminates the need to deal with IID guids. So the full expanded function is really this:
HRESULT hr = m_d3dDevice->QueryInterface(__uuidof(IDXGIDevice1), (void**)&dxgiDevice);
Or the most "old school" way (assuming you know how to link in the definition for the IID variable). dxguids.lib might still be a thing, otherwise, the header file hacks for DEFINE_GUID.
HRESULT hr = m_d3dDevice->QueryInterface(IID_IDXGIDevice1, (void**)&dxgiDevice);

COleSafeArray vs CComSafeArray

I am in a situation where I have a COM object that I need to use in come windows only C++ code. The COM object has functions that accept SAFEARRAYs as arguments to pass arrays of bytes. After looking at the SAFEARRAY API ( http://msdn.microsoft.com/en-us/library/windows/desktop/ms221145(v=vs.85).aspx ) I decided it wasn't what I wanted and that I should find an object oriented wrapper. I tried looking for open source ones and I didn't find any. I found that microsoft has created two objects that seem to encapsulate SAFEARRAY. It looks like the CComSafeArray is exactly what I need, and like the the COleSafeArray might be useful but could exist only for legacy compatibility.
Is COleSafeArray just around for historical compatibility or is there something I am missing?
When should COleSafeArray be used instead of CComSafeArray?
Are there any open source implementations that might be worth looking into?
What are the Pros and Cons of each?
The difference is obvious from class names.
MFC COleSafeArray is designed to support OLE Automation and is actually wrapper for OLE VARIANT struct (which can contain SAFEARRAY). It works generally with array elements as they are of VARIANT type so you need to select & extract appropriate type manually.
ATL CComSafeArray is designed to support SAFEARRAY for generic COM and is actually wrapper for SAFEARRAY struct. It's template class parametrized with array elements type.
In general you shall use CComSafeArray, it's easier and simplier, accessing elements almost same way as for regular arrays/vectors.
COleSafeArray may be preferable sometimes if you work with OLE Automation interfaces that intensively use VARIANT parameters, e.g. automating MS Office, using Visual Basic components etc. For comparision in this case with CComSafeArray you will need to wrap/unwrap it manually to/from VARIANT object.

Call to VB's CreateObject method in C++

I'm trying to call Visual Basic's CreateObject method from my C++ code. In VB, I'd simply type:
Dim obj As Object
obj = CreateObject("WScript.Network")
And that returns me the object from which I can call more methods. But how can I do that in C++? I'm following the MSDN documentation in http://msdn.microsoft.com/en-us/library/bb776046(v=VS.85).aspx, but those parameters are very obscure and I can't figure them out.
The first parameter is a reference to a CLSID, and I can see from the registry that the CLSID for "WScript.Network" is {093FF999-1EA0-4079-9525-9614C3504B74}. But what's the difference between this parameter and the third one, REFIID?
Thanks in advance!
I'll provide my solution, just for the record. It calls the AddWindowsPrinterConnection to install a network printer. It asks for user confirmation, so if you want to bypass that, you need to set HKEY_CURRENT_USER/Printers/LegacyPointAndPrint/DisableLegacyPointAndPrintAdminSecurityWarning to 1 (you can change it back to 0, after everything is done).
CoInitialize(NULL);
{
ATL::CComPtr<IDispatch> test;
_variant_t printerConnection = "\\\\serverAddress\\printerName";
_variant_t result;
test.CoCreateInstance(L"WScript.Network");
test.Invoke1(L"AddWindowsPrinterConnection", &printerConnection, &result);
}
CoUninitialize();
First, you probably want to use CoCreateInstance http://msdn.microsoft.com/en-us/library/ms686615%28VS.85%29.aspx, or the equivalent call inside a smart pointer wrapper (eg: CComPtr<>, _com_ptr<>, etc.).
Second, to your specific question, the IID is the interface ID, the CLSID is the class ID. COM objects can have multiple interfaces on the same object in general, which is why there is a distinction (although VB can only see one, which is why you don't need so to specify anything other than the CLSID for VB).
The "correct" way to duplicate what VB is doing is to create the IDispatch interface on the object, and then enumerate the methods using IDispatch. The "better" way in C++ is to create the direct interface you want to use, and call methods directly through it. However, this requires knowing the interface ID (IID, or REFIID passing the struct by reference), which is specific to the other object.
Hope that helps. I can't provide specifics for your particular interface, but maybe this points you in the right direction.

C++ ATL Member Variable access help

I am not familiar with this, and can use a kick start.
I am using ATL (unmanaged C++) user control and would like to use the ShockWave ActiveX object. I need to know how to declare it so that I can set a property or call a method.
For instance, if I could assign a variable to it, then I would like to call 'variable->LoadMovie()'
I know this is super ridiculous... almost embarrassed to ask it here. ;) (almost)
If you #import the dll (which I recommend when working with COM because it makes your life SO much easier), you can use a smart pointer paired with the CLSID of the object. Remember that smart pointer classes have the post-fix 'Ptr' after the interface name.
For instance:
ISomeInterfacePtr pSomeInterface( CLSID_SomeComponent );
HRESULT hr = pSomeInterface->SomeMethod();
Hope that helps.
EDIT: If you want to check the HRESULT of the allocation, you can do the following:
ISomeInterfacePtr pSomeInterface = 0;
HRESULT hr = pSomeInterface.CreateInstance( CLSID_SomeComponent );
I cut&paste the necessary code so many times I can't remember the exact syntax but you have to:
get a CComPtr<> of the correct interface,
CreateInstance the object
QueryInterface to get the interface you want (assuming you're not using the CComPtr)
then call methods on it.
Alternatively you can #import the dll, then the compiler will generate a c++ class with all the methods and properties for you.