C++ ATL Member Variable access help - c++

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.

Related

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

Direct access to C++ ATL COM objects

I have an ATL/COM implementation of an interface, which I need to instantiate in my main code and pass to another COM object. This implementation is in C++.
From my main C++ code, I would like to access directly to the object (not through the COM port), and access class members and methods directly.
I think that the way to go is to add DECLARE_NO_REGISTRY() in the ATL/COM class; then call myCOMClass:CreateObject() instead of CoCreateInstance; but I do not know how to use this (and did not find any example).
I tried several combinations with no success.
In my main code:
//I added this line to call the lib directly
#include "comClass\StdAfx.h"
#include "comClass\comClass_i.c"
#include "comClass\comClass.h"
//I removed this line to bypass COM
//#import "comClass\comClass.dll"
//What can I put here to replace this block, bypass COM
//and being able to access class members??
CoInitialize(NULL);
comClassInterface *myObject = NULL;
HRESULT hr = ::CoCreateInstance(__uuidof(comClass),
NULL,
CLSCTX_INPROC_SERVER,
__uuidof(comClassInterface),
(void**)&myObject);
More or less "standard" wat to create COM objects directly:
CComObject<comClass> *myObject;
CComObject<comClass>::CreateInstance(&myObject);
That's it basically.. You could also just do "new comClass" if the class is not abstract, which is normally the case when you use ATL.

Get the DLL-file for a COM-Object without using CLSID and registry in c++

Is it possible to get the DLL-filename for a loaded COM-Object without using the CLSID and a registry lookup?
I have an IUnknown or in my case an IBaseFilter interface pointer and now I want to get the DLL-filename who created this COM-Object. Can I use the object point adress to reverse lookup the loaded module where it was created? And then get the HMODULE to use it in GetModuleFileName.
Yirkha's answer is in good standing and I have two notes to add:
DirectShow filters are typically old school C++ COM objects with virtual method table residing in code segment, with no proxy/stub code as long as we are inside single process. That is, the hacks of resolving module from interface pointer do work well.
There is an easier replacement for EnumProcessModules/GetModuleInformation walk along module list. VirtualQueryEx can locate the base address of the DLL directly:
const VOID* pvVirtualTable = *((const VOID**) pBaseFilter);
MEMORY_BASIC_INFORMATION Information;
if(VirtualQueryEx(GetCurrentProcess(), pvVirtualTable, &Information,
sizeof Information))
{
TCHAR pszPath[MAX_PATH] = { 0 };
if(GetModuleFileName((HMODULE) Information.AllocationBase, pszPath,
_countof(pszPath)))
{
P.S. This is something we also do in both DirectShowSpy here , and also in GraphStudioNext.
Only using some hacks, naturally. The object itself is on the heap, which is shared, but you could see where the its virtual table resides - it should be almost universally in the read-only data section of the creator's binary.
So load the first pointer in the object, as that's where virtual table pointers reside in Windows COM ABI:
IBaseFilter* pFilter = ...;
char* vtbl = *reinterpret_cast<char**>(pFilter);
Then I originally suggested to do some circus with EnumProcessModules() like e.g. here, call GetModuleInformation() on each module and check if the vtbl pointer falls into its memory ranges. Stupid me, I forgot about VirtualQueryEx(), so better do it as Roman described in his answer.
Of course, all this can work only for in-process COM objects and where there are no proxies involved. I assume it can still be useful in your DirectShow case though.
Also see the comment about using IPersist::GetClassId() and registry lookup, it should apply nicely to most DirectShow filters.

How to send list through COM

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.

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.